Repository pattern implementation with Laravel Repository pattern implementation with Laravel laravel laravel

Repository pattern implementation with Laravel


@likerRr you asked:

Whether it will be correct to re-write this example using Repository pattern this way:

First of all, you should think why do we use Desing Patterns and specifically the Repository Pattern? We use the Repository pattern to implement the SOLID principles (all or few).The first thing is one should not access the data source/database in controllers. Doing this you are:

  1. violating the Single Responsibility Principle (S in SOLID). Your controller must not be aware of the data source. It is only responsible to respond to HTTP Request or meditate b/w your Application and HTTP.
  2. you are violating the Liskov Substitution Principle
  3. you are violating the Dependency Inversion Principle.

So, that's why you should use not only the Repository Patterns but implement the SOLID Principles.how to do then? Wrap your data source access in somewhere else and the Repository is the best place.Suppose you are getting a user using the following code:

User::where('id', $id)->where('company_id', $companyId)->get();

If you write this code in all your controllers where you needed, you can not do the following:

  1. You can not change your data source without changing that line
  2. You can not test your code
  3. and eventually this will be hard to maintain

2: Can I somehow pass the found model back to the repository and to increase her counter (does it contradict this approach to Repository pattern?)

You are doing right in your snippet. Actually, you want to gain both the ease provided by the Laravel and the benefits of Patterns.You probably know that you have to sacrifice something for another thing. Drivers driving on the easy to drive roads can not become good drivers. So, I will suggest you follow the design patterns and SOLID Principles and leave the "ease" provided by the Laravel. Otherwise, this so-called "ease" will create so many troubles for you and you couldn't even maintain your project and all would get vanished.

Last Things about Using Events:

Events are nothing but Observer Pattern. In your case, there seems no need to use the Observer Patterns, so you should avoid it.

The best candidate for the observer patterns/Events would be that you are charging your client and after your successful charge, you want to send the currently charged amount detail along with the previous heavy calculation via email. As this will take time and you don't want to show the user a page reload while all this heavy processing is being done. So you can charge the user, fire an event, redirect the user to your site with a success message and let the event handler do the heavy lifting and your user can do other stuff.

You can ask any other questions if you want to!


The repository pattern has it's pros and cons.

From my relatively recent adoption of the pattern it allows for a much easier testing experience - especially when inheritance and polymorphism are leveraged.

Below is an excerpt of a near catch-all repository contract I 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 a record with the given values exists     * @param array $attr     * @return bool     */    public function exists(array $attr);    /**     * Checks if any records with any of these values exists and returns true or false     * @param array $attr     * @return bool     */    public function unique(array $attr);}

The contract is relatively self explanatory, save() manages both inserting and updating entities (models).

From here I'll create an abstract class that implements all the functionality for the vendor(s) I want to use - such as Eloquent or Doctrine.

It's worth noting, this contract wouldn't catch every thing and I am currently in the process of creating a separate implementation that handles many to many relationships but that's another story.

To create my individual repository classes, to do that I create another contract for each repository that extends the EntityRepositoryContract and states what functionality is exclusive to them. In the case of a user - registerUser(...) and disableUser(...) etc etc.

The final classes will then extend the EloquentEntityRepository and implement the relevant contract for the repository. The class signature for the EloquentUserRepository would be some thing like:

class EloquentUserRepository extends EloquentEntityRepository implements UserRepositoryContract{...}

In my own implementation to make the class names less verbose I leverage namespaces to alias each implementation like so:

use Repo\Eloquent\UserRepo; //For the Eloquent implementationuse Repo\Doctrine\UserRepo; //For the Doctrine implementation

I try not to bunch all of my repositories together and instead group my application by feature to keep my directory structure less cluttered.

I'm skipping out on a lot of details but I don't want to throw too much in so experiment with inheritance and polymorphism to see what you can achieve for a better workflow with Repositories.

With my current workflow, my tests have their own abstract classes exclusively for the base repository contract that all entity repositories implement making testing a breeze after the first few hurdles.

Best of luck!


It works fine!

api.php

Route::get('/articles/{article}', 'ArticleController@getArticle')->middleware('can:get,article');

ArticleController.php

class ArticleController extends BaseController {    protected $repo;    public function __construct(ArticleRepository $repository) {        $this->repo = $repository;    }    public function getArticle(int $id)    {        $articleRepo = $this->repo->find($id);        return View::make('article.show', compact('articleRepo'));    }}