loading...

Laravel Repository Pattern

asperbrothers profile image Asper Brothers Updated on ・3 min read

Originally posted on: https://asperbrothers.com/blog/implement-repository-pattern-in-laravel/

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!


To see the entire article go to https://asperbrothers.com/blog/implement-repository-pattern-in-laravel/.

Discussion

pic
Editor guide
Collapse
andreich1980 profile image
AndrewP

When people advocate for repositories pattern they often say "what if I want to change data storage from MySQL to something else". And it always makes me wonder how many times have you heard of such a decision if ever?

Here you're creating a s***load of additional files (a repo, a base repo, an interface, a service provider) just in case that might never happen.

You have a method find to find a model by id. What if you need to get a model by other attributes (email, name)? Would you create a couple of new methods like findByXxx in the repo and in the interface?

Collapse
mabalashov profile image
mabalashov

"To change data storage" - is not the main aim of Repository.
The main aim is to have separate layers and clean code. It becomes much easier to make scalable code, cover it by tests if you are going this way. But it makes sense to use repositories and follow the best practices of clear code if you are developing big enterprise applications.
For RAD the ActiveRecord (Eloquent) is the best

But, in the current article author suggests using Eloquent Models with Repository. It is not the best way and it will be better to use or AR or Repo. Otherwise, you will lose all the benefits of both ones.

Collapse
mnavarrocarter profile image
Matias Navarro Carter

You are right in many things you said. It's true that the repository pattern is used to decouple a specific persistence layer from your domain/application logic.

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.

This would be a more appropiate, really vendor agnostic approach:

interface UserRepository
{
   /**
    * @return User[]
    */
   public function all(): iterable;

   public function ofId(string $userId): ?User;

   public function add(User $user): void;

   public function remove(User $user): void;
}

interface User
{
   public function getId(): string;

   public function getPassword(): string;

   // You get the idea
}

Your Eloquent models then would have to implement the User interface.

With this approach, you really are abstracting away any possible third party or vendor relationship from your domain.

However, that's going to be hard to do. Active Record is not really the best choice for implementing the repository pattern. It's kinda hard to set up and feels hacky. This is pretty obvious: Active Record ties your models (that belong to your domain layer) to a connection to a relational database, and your model data to a relational table structure. Repository pattern is about doing exactly the opposite.

I recommend you to take a look at Doctrine ORM (but for that you'll have to quit Laravel really) and to read this blog. Also, repositories, models and concepts alike have been around for years. One book that explains them well is Domain Driven Design by Eric Evans. He kinda popularized those concepts, among several others.

Collapse
herminioheredia profile image
Herminio Heredia Santos

This seems to be a classic example of a smell coupling with a middle man.
On the other hand, the advantages you are talking about are achieved in another way without the need to use "Repositories" which in this case is more a wrapper with delegation than a genuine implementation of the repository pattern

Collapse
georaldc profile image
Georald Camposano

"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!"

I don't use Laravel much at the moment, but won't this still depend on how your views are using whatever was returned by your repository? From what I can tell, your sample is returning a collection of eloquent models using the all method. What happens if your view file starts referencing eloquent-only methods and/or relationships? Won't switching repositories break this, unless you add another layer of abstraction to what your repository returns?