Laravel Repository Pattern – How to use & why it matters

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

In this article you’ll learn about:

  • Main benefits of using Repository Pattern 
  • How to implement a Repository Pattern in Laravel?
  • We will show you step by step how to start code and implement it in Laravel app

What’s important

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, 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 is not supported by Eloquent? When we write such a code, such a change may turn out to be very difficult to implement, or even impossible! That’s why it’s very dangerous to write code this way, every implementation should be based on interfaces, so 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 in a correct way. (The code above should be written in a correct way).


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 simply 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 in such a way 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 repository pattern in Laravel, so let’s implement it 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 is 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);
    }
}

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 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 an objects by its interfaces. So we can simply use makinglogic like this in 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 other implementation than eloquent we simply 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 brief 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!
  • You should always inject your repository using Dependency Injection instead of making an instances 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 a unit tests, you are warning SRP(Single Responsibility Principle) and the code looks more cleaner.
  • Make your code reusable, if any method is used by more repositories than one you should implement this method into the BaseRepository class to avoid DRY principle.
  • In your repository inject 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!

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!

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 once a week.

Add comment