Wednesday 15 May 2013

php - Repository pattern implementation with Laravel -



php - Repository pattern implementation with Laravel -

recently start study laravel 4 , it's capabilities. want implement repository pattern move model logic there. , @ point faced number of inconvenience or misunderstanding of how organize it. general question have goes this: is possible implement , apply pattern in laravel without headaches, , whether it's worth?

the question divided several parts, caused confusion.

1) laravel provides convenient way bind model controller parameter, e.g. way:

// routes.php route::bind('article', function($slug) { homecoming article::where('slug', $slug)->first(); }); route::get('articles/{article}', 'articlescontroller@getarticle'); // controllers/articlescontroller.php class articlescontroller extends basecontroller { public function getarticle(article $article) { homecoming view::make('article.show', compact('article')); } }

if want utilize repository pattern, can't utilize approach, since in case controller aware of existence of models article? whether right re-write illustration using repository pattern way:

// routes.php route::get('articles/{slug}', 'articlescontroller@getarticle'); // controllers/articlescontroller.php class articlescontroller extends basecontroller { private $article; public function __construct(articlerepository $article) { $this->article = $article; } public function getarticle($slug) { $article = $this->article->findbyslug($slug); homecoming view::make('article.show', compact('article')); } }

2) suppose, code above utilize of repository correct. want increment article views counter each time showed, however, want create processing in event. is, code follows:

// routes.php route::get('articles/{slug}', 'articlescontroller@getarticle'); // controllers/articlescontroller.php class articlescontroller extends basecontroller { private $article; public function __construct(articlerepository $article) { $this->article = $article; } public function getarticle($slug) { $article = $this->article->findbyslug($slug); events::fire('article.shown'); homecoming view::make('articles.single', compact('article')); } } // event subscriber class articlesubscriber { public function onshown() { // why implementation missed described bellow } public function subscribe($events) { $events->listen('article.shown', 'articlesubscriber@onshown'); } }

at point puzzled 1 time again how implement event processing. can't pass $article model straight event, because, again, it's violates principles of oop , subscriber know existence of article model. so, can't so:

// controllers/articlescontroller.php ... \events::fire('article.shown', $article); ... // event subscriber ... public function onshown(article $article) { $article->increment('views'); } ...

on other hand don't see sense introduce subscriber repository articlerepository (or inject in subscriber's contructor), because first should find article, , update counter, in end, query (cause in constructor same) database:

// controllers/articlescontroller.php ... events::fire('article.shown', $slug); ... // event subscriber ... private $article; public function __construct(articlerepository $articlerepository) { $this->article = $articlerepository; } public function onshown($slug) { $article = $this->articlerepository->findbyslug($slug); $article->increment('views'); } ...

moreover, after event handled (i.e. increased views count), necessary controller knew updated model, because in view want display updated views counter. turns out somehow still need homecoming new model event, not want event has become mutual method processing particular action (for there repository) , homecoming value. in addition, may notice lastly onshow() method 1 time again contrary rules of repository pattern, don't understand how set logic repository:

public function onshown($slug) { $article = $this->articlerepository->findbyslug($slug); // incorrect! because event shouldn't know model able implement eloquent // $article->increment('views'); }

can somehow pass found model repository , increment counter (does contradict approach repository pattern?)? this:

public function onshown($slug) { $article = $this->articlerepository->findbyslug($slug); $this->articlerepository->updateviews($article); } // articlerepository.php ... public function updateviews(article $article) { $article->increment('views'); } ...

as result, seek formulate more compact:

i'll have reject pass models straight controller , other comforts provided di, if i'll utilize repository pattern?

is possible utilize repository keeping state of model , pass between entities (e.g., filter controller controller event , back) avoiding obscene repeated calls db , approach right (model persistence)?

such things, these questions. hear answers, thoughts, comments. maybe, wrong approach apply pattern? causes more headaches solves issue of info mapping.

also i've read articles repository implementation:

http://heera.it/laravel-repository-pattern#.vfaku8lirle http://vegibit.com/laravel-repository-pattern

but doesn't solve misunderstanding

the repository pattern has it's pros , cons.

from relatively recent adoption of pattern allows much easier testing experience - when inheritance , polymorphism leveraged.

below excerpt of near catch-all repository contract use.

interface entityrepository { /** * @param $id * @return array */ public function getbyid($id); /** * @return array */ public function getall(); /** * @param array $attr * @return array */ public function save(array $attr); /** * @param $id */ public function delete($id); /** * checks if record given values exists * @param array $attr * @return bool */ public function exists(array $attr); /** * checks if records of these values exists , returns true or false * @param array $attr * @return bool */ public function unique(array $attr); }

the contract relatively self explanatory, save() manages both inserting , updating entities (models).

from here i'll create abstract class implements functionality vendor(s) want utilize - such eloquent or doctrine.

it's worth noting, contract wouldn't grab every thing , in process of creating separate implementation handles many many relationships that's story.

to create individual repository classes, create contract each repository extends entityrepositorycontract , states functionality exclusive them. in case of user - registeruser(...) , disableuser(...) etc etc.

the final classes extend eloquententityrepository , implement relevant contract repository. class signature eloquentuserrepository thing like:

class eloquentuserrepository extends eloquententityrepository implements userrepositorycontract { ... }

in own implementation create class names less verbose leverage namespaces alias each implementation so:

use repo\eloquent\userrepo; //for eloquent implementation utilize repo\doctrine\userrepo; //for doctrine implementation

i seek not bunch of repositories , instead grouping application feature maintain directory construction less cluttered.

i'm skipping out on lot of details don't want throw much in experiment inheritance , polymorphism see can accomplish improve workflow repositories.

with current workflow, tests have own abstract classes exclusively base of operations repository contract entity repositories implement making testing breeze after first few hurdles.

best of luck!

php design-patterns laravel repository-pattern

No comments:

Post a Comment