This article assumes that you have a basic understanding and fundamentals of PHP and the Laravel framework.
Before we get into the topic we first must understand what is Repository pattern:
The Repository pattern. Repositories are classes or components that encapsulate the logic required to access data sources. They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer.
Now open up a terminal and install a fresh Laravel project,
composer create-project laravel/laravel laravel-repository-pattern
Then open this in your code editor (VS Code).
I am not going to go through the installation process since this article does not aim to teach about installing a Laravel project. Go to the official docs for reference instead, https://laravel.com/docs/8.x#installation-via-composer
Create a directory inside the app and name it as Repository and inside it create another directory Eloquent then create a file named
BaseRepository.php inside Eloquent directory and create an interface and name it
EloquentRepositoryInterface.php inside Repository . If you did it correctly you will have the following file structure.
- app - Repository - Eloquent - BaseRepository.php - EloquentRepositoryInterface.php
Then inside the interface EloquentRepositoryInterface.php , write an interface that will contain all the common methods that are used when we are accessing our database to retrieve, store, and remove data. (CRUD)
We also want to set standards when creating our repository interface, because we want the method names to be self-describing and that we should know what we get when we use the method. We can use the following verbs: 'find', 'get', 'remove', 'update' and etc that simply describes what it does.
The interface does not care about the implementation details, we only define the method names, what arguments are being passed into it and what we expect it returns. We can simply do that by type hinting it. This what makes it beautiful because whenever we had to change a Data Provider (I am talking about Eloquent ORM, DB, or any 3rd party APIs if there's any), we only have to create another class specifically for it and we do not need to replace code.
Now let us define the methods that we will be using throughout our entire application in this interface.
Here is an example,
As you may have noticed the method names are verbose and contains the verbs we just described. Making method names verbose actually makes everything easier.
BaseRepository we created a protected property named as $model and it will receive an instance of class Model. In our constructor we inject the Model class and assign the instance into the $model property so it will be available to all methods. These are the important part of our
BaseRepository class since any new repositories will be extending to this base repository and they won't have to rewrite what we just wrote regarding the implementation details that we interfaced against the
Here is an example,
To your terminal and execute this command to create the class,
php artisan make:provider RepositoryServiceProvider
Then inside that class, inside
register() method is here me bind the
EloquentRepositoryInterface.php and the actual repository, in this case it it the
BaseRepository.php that we created.
Make sure to import these files into the
And now to make these changes available in our entire application, we register the
RepositoryServiceProvider class inside the
Then execute this composer command in your terminal to read the bindings,
If it doesn't work you must delete the cache manually if you are having problems. These files should be deleted specifically as they will get auto-generated by Laravel whenever we run a caching command. And normally these files are being ignored by git.
- app - bootstrap - cache (Delete these files below) - config.php - packages.php - services.php
Now that we have a our BaseRepository defined, when we create another module or feature it should give us a boost in development time since we eliminated it by applying abstraction using the Repository Pattern.
Now just create another interface and a repository class.
In your terminal execute these commands to create the files,
touch app/Repository/UserRepositoryInterface.php touch app/Repository/Eloquent/UserRepository.php
UserRepositoryInterface we only have to define the interface and extend on to the
And then inside the
UserRepository class, we still implement the
UserRepositoryInterface that we just created and extend
BaseRepository class, by doing this we are applying Inheritance, we inherit all the methods that we just defined from our
BaseRepository class and we will be able to access to the fields inside
BaseRepository class so we do not have to rewrite everything. One thing we only want to override is the first parameter in our constructor, from the base repository it is the Model class, but since it is a user repository then we should replace it with the User model.
And now inside our user repository also contains the methods that we implemented inside the base repository.
And now bind the UserRepositoryInterface with the UserRepository inside the RepositoryServiceProvider class so our application will recognize this new repository that we created in the entire application.
Then execute the command again,
I typically execute this command every time I add a new repository, if I don't then Laravel does not know or recognize about this new repository that we just created.
In your terminal execute this command,
php artisan make:controller UserController
and define a route inside
And now inside our
UserController let us define method index() but before that in our constructor we want to inject the
UserRepository into the
Contoller so that we will have all the methods available at our disposal. In this case the index() method in the Controller is commonly known to return a list of resources, so let's make that as is.
The Repository Pattern also allows us to write less code inside our Controllers and that makes it even better rather having a giant code in the Controller which isn't what we want if we are aiming for better maintainability and readability. Let's keep it that way, clean controllers.
In case you don't agree with me because I am only showing a simple example and it's for retrieving all users only, then for creating a new user and sometimes we have to put some logic into it, maybe some if-else statements, that actually is considered a code smell and we don't want to do that. And also what about if you have to use the same logic in a different Controller, without creating a repository you will have to copy and paste these code. So when we are using the Repository Pattern we just inject it to the class that we need it for without having to rewrite logic.
So let us test that the route that we created by accessing this link in your browser
We should see an empty set. That means everything we did worked and it makes sense because we haven't created any users yet.
So let us create users using the factory, open to your terminal and go to tinker CLI,
php artisan tinker
Then execute this command to create 10 users
Then go back to your browser and hit refresh and you should see 10 users being returned from the API.
And there we have it!
In leveraging on this design pattern we took some time to set it up in exchange for better readability and maintainability of our codebase. By doing abstraction and encapsulation we eliminate code duplications as we created a
BaseRepository that shares all the common methods in every new repository that uses Eloquent ORM.
So for any small changes that we will make in the future, we don't have to bother updating every single file because we extended the common methods and by apply a single change saves us ample time and reduces cognitive load and that makes us happy.
On the other hand, this will make our code testable and we can easily scale it. But this isn't a silver bullet unfortunately, we might have sacrificed a little bit of performance as having these repositories are at the center between our data provider and our Controllers or any class that we might need to get data from.
If you aren't using Repository Pattern yet, make sure to try it out yourself. Thank you for taking the time to read and I hope this helps you out in getting started with Repository Pattern in Laravel.
Full source code: https://github.com/carlomigueldy/laravel-repository-pattern