DSC00409
1 Oct 2019 11 min to read

Laravel Repository Pattern – PHP Design Pattern

The first thing we need to know to implement a repository pattern in the Laravel application is to understand what Repository Pattern is and its benefits.

In this article, you’ll learn about:

  • Main benefits of using Repository Pattern 
  • How to implement a PHP Repository Pattern in Laravel?
  • We will show you how to start code and implement it in the Laravel based App.

What’s important – Why we need a design pattern?

A repository is a separation between a domain and a persistent layer. The repository provides a collection interface to access data stored in a database, file system or external service. Data is returned in the form of objects.

The main idea to use Repository Pattern in a Laravel application is to create a bridge between models and controllers. In other words, to decouple the hard dependencies of models from the controllers. The model should not be responsible for communicating with or extracting data from the database. A model should be an object that represents a given table/document/object or any other type in our data structure, and this should be its sole responsibility. Therefore, to keep your Laravel code clean and safe, it is worth using repositories to separate the responsibility for which the model should never be responsible.

The use of Repository Pattern has many benefits, below is a list of the most important ones:

  • Centralization of the data access logic makes code easier to maintain
  • Business and data access logic can be tested separately
  • Reduces duplication of code
  • A lower chance for making programming errors

In most Laravel applications, you may encounter such a code.

class UsersController extends Controller
{
   public function index()
   {
       $users = User::all();

       return view('users.index', [
           'users' => $users
       ]);
   }
} 

At first glance, it doesn’t look that bad. However, it is worth to think what if the client proposes to change the data structure and instead of in MySQL/Postgresql from now on we are going to keep the data somewhere else, in the data engine which Eloquent does not support? When we write such a code, such a change may be tough to implement or even impossible! That’s why it’s very dangerous to write code this way. Every implementation should be based on interfaces. In case of changes, you don’t need to change the code in the whole application but only create another class implementing the interface. This should be the code above written correctly. 


class UsersController extends Controller
{
   private $userRepository;
  
   public function __construct(UserRepositoryInterface $userRepository)
   {
       $this->userRepository = $userRepository;
   }

   public function index()
   {
       $users = $this->userRepository->all();

       return view('users.index', [
           'users' => $users
       ]);
   }
}

In this particular example, when a client wishes to change the data structure, it is child’s play to implement these changes into our application! We create a class that implements UserRepositoryInterface and contains the logic that will allow us to pull it out in a new way, and everything works again. That is why it is so important to write code so that even when the client comes with the most difficult change, we will be able to deal with it easily. The repository template greatly facilitates this process!

 

Let’s start with code and implement it in your Laravel app!

Now you know the benefits of the repository pattern in Laravel, so let’s implement them in your application! In the beginning, we will start with a folders structure. We should start by creating a Repository folder into our app folder. Inside a newly created folder, we should create another folder with a current repositories implementation. We use Eloquent this time, so let’s name it Eloquent. So the final file structure should look like this:


-- app
---- Repository
------ Eloquent
-------- UserRepository.php
-------- BaseRepository.php
------ UserRepositoryInterface.php
------ EloquentRepositoryInterface.php

One thing that might make you wonder at this stage – what exactly are the BaseRepository and EloquentRepositoryInterface? Let me explain this quickly. It will be just a parent class that every eloquent repository implementation class will be extended. This class will store the methods that are common use in every repository. So the BaseRepository class will look like this:

EloquentRepositoryInterface.php



namespace App\Repository;


use Illuminate\Database\Eloquent\Model;

/**
* Interface EloquentRepositoryInterface
* @package App\Repositories
*/
interface EloquentRepositoryInterface
{
   /**
    * @param array $attributes
    * @return Model
    */
   public function create(array $attributes): Model;

   /**
    * @param $id
    * @return Model
    */
   public function find($id): ?Model;
}

BaseRepository.php


<?php   

namespace App\Repository\Eloquent;   

use App\Repository\EloquentRepositoryInterface; 
use Illuminate\Database\Eloquent\Model;   

class BaseRepository implements EloquentRepositoryInterface 
{     
    /**      
     * @var Model      
     */     
     protected $model;       

    /**      
     * BaseRepository constructor.      
     *      
     * @param Model $model      
     */     
    public function __construct(Model $model)     
    {         
        $this->model = $model;
    }
 
    /**
    * @param array $attributes
    *
    * @return Model
    */
    public function create(array $attributes): Model
    {
        return $this->model->create($attributes);
    }
 
    /**
    * @param $id
    * @return Model
    */
    public function find($id): ?Model
    {
        return $this->model->find($id);
    }
}

So that’s our base repository. We inject their model class into constructor and store methods that may be used in every eloquent repository. In this current example, it will be just created () and find() methods.

We got the parent class, so the next step is to implement our user repository!

UserRepositoryInterface.php


<?php
namespace App\Repository;

use App\Model\User;
use Illuminate\Support\Collection;

interface UserRepositoryInterface
{
   public function all(): Collection;
}

UserRepository.php


<?php

namespace App\Repository\Eloquent;

use App\Model\User;
use App\Repository\UserRepositoryInterface;
use Illuminate\Support\Collection;

class UserRepository extends BaseRepository implements UserRepositoryInterface
{

   /**
    * UserRepository constructor.
    *
    * @param User $model
    */
   public function __construct(User $model)
   {
       parent::__construct($model);
   }

   /**
    * @return Collection
    */
   public function all(): Collection
   {
       return $this->model->all();    
   }
}

And that’s it! You have just implemented the repository pattern in laravel. Let’s use it in our application then!

To let our application know which implementation of which interface we want to use, we need to create a Laravel service provider. We will name it RepositoryServiceProvider, so let’s type (it) in our console method:


php artisan make:provider RepositoryServiceProvider

After creating this file, let’s open it and add some new line of codes:


<?php 

namespace App\Providers; 

use App\Repository\EloquentRepositoryInterface; 
use App\Repository\UserRepositoryInterface; 
use App\Repository\Eloquent\UserRepository; 
use App\Repository\Eloquent\BaseRepository; 
use Illuminate\Support\ServiceProvider; 

/** 
* Class RepositoryServiceProvider 
* @package App\Providers 
*/ 
class RepositoryServiceProvider extends ServiceProvider 
{ 
   /** 
    * Register services. 
    * 
    * @return void  
    */ 
   public function register() 
   { 
       $this->app->bind(EloquentRepositoryInterface::class, BaseRepository::class);
       $this->app->bind(UserRepositoryInterface::class, UserRepository::class);
   }
}

The last step is to register this service provider in our config/app.php. Open this file and add to providers our provider  App\Providers\RepositoryServiceProvider::class

Now our application knows what class it should use when we type objects by its interfaces. So we can use makinglogic like this in the controller:


class UsersController extends Controller
{
   private $userRepository;
  
   public function __construct(UserRepositoryInterface $userRepository)
   {
       $this->userRepository = $userRepository;
   }

   public function index()
   {
       $users = $this->userRepository->all();

       return view('users.index', [
           'users' => $users
       ]);
   }
}

Our app knows that we are looking for App\Repository\Eloquent\UserRepository implementation. In case we want to use another implementation other than eloquent, we change App\Repository\Eloquent\UserRepository in our service provider to, e.g. App\Repository\Mongo\UserRepository. Our application will work the same way as before, even if the data engine has changed and we didn’t change even 1 line of code in our controller or anywhere else! 

That’s it! You have implemented a repository pattern in your app. Now you can add new repositories for the other models you are using in your application.

Finally, a summary of what is worth noting when implementing a repository pattern.

  • Each repository should have its own interface implemented! Never create a repository without implementing its own interface, and do not create one interface for all repositories. It is not a good practice!
  • It would help if you always injected your repository using Dependency Injection instead of making an instance using the new keyword. As a type always use interface, not an implementation! If you inject objects into the class, it is easier to write unit tests, you are warning SRP(Single Responsibility Principle), and the code looks more cleaner.
  • Make your code reusable. If more repositories than the one use any method, you should implement this method into the BaseRepository class to avoid the DRY principle.
  • In your repository, inject the model in a constructor, don’t use a class as a static. By doing it, you can easily mock your model in your unit tests!
Call to action
Do you think that you know how to implement Repository Pattern in Laravel already? If you need any help, don’t hesitate to contact us!

Share

SUBSCRIBE our NEWSLETTER

Are you interested in news from the world of software development? Subscribe to our newsletter and receive a list of the most interesting information.

    COMMENTS (25) comments arrow

    1. What about adding magic __call function which will handle find, paginate, where and etc..

      /**
      * @param $name
      * @param $arguments
      * @return mixed
      */
      public function __call($name, $arguments)
      {
      return $this->model->{$name}($arguments);
      }

      • I am not a big fan of magic methods, so I rather to avoid using them to be honest. It’s not a good idea to use a magic methods because:

        1. System is harder to understand, especially for newcomers
        2. There is no auto-completion(and this is a major problem actually), and type management by the IDE for refactoring and code-browsing
        3. The documentation (phpdoc) doesn’t match how your code is supposed to be used, and looking at your class doesn’t bring much answers as well. This is confusing.
        4. It’s harder to write unit tests, mock magic methods.
        5. It’s harder to debug code.

        So it produces more problems than it gives a value. For your own sake you should avoid using magic methods too. 🙂

      • If you use the magic __call method, this should be

        public function __call ($method, $args)
        {
        return call_user_func_array ([$this-> model, $method], $args);
        }

        But indeed, as Adrian mentioned, it quickly turns out that the solution is becoming onerous. In my solutions I usually duplicated the methods from the model in the repository

    2. Thanks for this. While it helped to understand the basics of the repository pattern, my feedback on this post would be to give a complete example including the code for the UserRepository in order to understand how to actually bind an eloquent model to a repository. Am I supposed to call parent::__construct(new User); in the UserRepository?

      • The post has been updated as we noticed this part was missing somehow. Please read it again and if it still be confused for you please let us know! 🙂

    3. Agree with @Tim, it’s not enough clear why we have this hierarchy for UserRepository:

      BaseRepository < EloquentRepositoryInterface
      UserRepository < UserRepositoryInterface
      UserRepository < BaseRepository

      I assume UserRepository this is because it has user-specific logic in it and at the same time it wants to benefit from generic repository methods implemented by BaseRepository?

    4. … but the example given has all() method which should be in BaseRepository not in the UserRepositoryInterface since it’s a very generic way to get all Eloquent models, isn’t it?

      • Yes, you’re right. In a real project this should be in BaseRepository, because more than 1 class would probably use it. However, for the purpose of the article I implemented this method in UserRepository in order to make the article easier to understand and not to complicate the matter with a more complicated example. 🙂

    5. hi,thanks for shared your knowledge .i have a big question. after all steps we use eloquent model in controller methods that’s means we don’t good decouple . what do you think?

    6. Agree with @mohammad, the model should be decoupled so as not to depend on Eloquent model in our controllers.

    7. Medicaltipes

      However, you are not even achieving the benefits you preached about with your interface. The Eloquent jargon in your interface and the type hint to return an Eloquent model are coupling it to Eloquent: you gain nothing of what you aimed for in this case. If you were to eventually replace Eloquent, you’ll have a hard time doing so.

      • Yes, you’re absolutely right. This example does not achieve all the benefits I mentioned, because the main purpose of this article was to show how to implement repository pattern in easy way and with a quality that will be “high enough” for most laravel projects. Yes, as you noticed in this particular implementation changing eloquent to something else will be painful, and that’s true, because our repositories refer to Eloquent classes to remedy this we should create appropriate interfaces for our models/collections and change the type hints to those interfaces. Maybe in future I will update this article or create a new one that will show “higher level” implementation that will achive all the benefits I mentioned. 🙂

        • Oluwadamiloju Yusuf

          Isn’t what is needed just to change the type hints in the UserRepositoryInterface to refer to an Interface for collections?? Or can you explain better?

      • Yes, you’re right. ActiveRecord is not good solution for this kind of problem, doctrine entities are best suited for this but unfortunately its not easy to use doctrine in laravel project

    8. I really enjoyed your implementation, so I’ve copied some parts. I agree with people said return model and collection is not a good way, so I changed it.
      I also changed the directories organization. I think this is more organized and easier to understand.
      |-Repositories
      |—Eloquent
      |—‘–Base
      |——‘–BaseRepository.php
      |——‘–EloquentRepositoryInterface.php
      |—‘–UserRepository.php
      |—UserRepositoryInterface.php

    9. Hi guys, I have found you after I’ve been looking for a solution for weeks now for an api problem. The problem is that I work with multiple tables that are joined together. I’ve extracted some of the logic to a resource file based on one tutorial, then it didn’t look as I expected, so I kept looking and found repository, and I’m full confused. What’s the difference between repos and resources, and how to modify data that comes from several models into a nicely formatted json to send to the controller? An easy example: I have account groups, that has many accounts, that has many transactions. Ho would you return a json of the accounts grouped by account groups, with all its accounts, and their transactions, and for example alter the transaction date format to return date only of mysql timestamp? This is what I try to accomplish. Thank you.

      • Hey!
        I am 100% sure that noone will explain you how to achieve that because “Repository Pattern” is wrong out of the box.
        Problems you presented cannot be handled with repository pattern without huge amount of additional queries, deadly slowing your app.

        Every f… “repository pattern” article stops here, because example given above is the only example when repository pattern will do the job.
        In any more complicated case it simple does not work.

        I faced this problem so many times and i am just tired of that concept.
        this pattern:
        – complicates development process without befetints that may be wotrh it
        – anforces you to think that you will somehow change your entire database to something absolutely weird (eg: api call. And yes api call may be used, but try to use something like join ^^).

        You may agree or disagree of that, but this came from years of my experience.

        • This is just a pattern, it does not have anything to do with your issue ‘huge amount of additional queries’. Secondly, I disagree with your second statement, ‘enforces you to think that you will somehow change your entire’.

    10. hi, why i am having this error?

      Illuminate\Contracts\Container\BindingResolutionException: Target class [Repositories\UserRepositoryInterface] does not exist. in file C:\xampp\htdocs\blog-api\vendor\laravel\framework\src\Illuminate\Container\Container.php on line 807

    11. You probably didn’t injected you service provider, check if you add the provider into your app.php file

    12. Thanks a lot . This blog helped me so much to understand the Repository pattern . But can you please explain to me that when i want to call a method of BaseRepository like (create Or find) in UserController how i call the method.

    13. after many years working with Laravel, i get the point: using Repository pattern as a proxy for Eloquent model methods is totally bullshit.

    14. Sorry, I did everything according to the article, but the application reports Interface ‘App \ Repositories \ EloquentRepositoryInterface’ not found in ……\app\Repositories\Eloquents\BaseRepository.php:9

    15. Thanks a lot for that precious information.
      Nevertheless, I hardly get the point of why the interface should not be shared between the repositories.

      It’s another topic, but knowing how to create the command `php artisan make:repository UserRepository` would be magic 🙂

      Thanks again

    16. Julian Somoza

      Excellent article (and comments). In my case, I never implement the repository on controllers, as controllers wouldn’t manage any database interaction. Instead, I inject it into my services. Greetings from Argentina!

    ADD COMMENT

    RECOMMENDED posts