Laravel Ecosystem Tools – How Development Can be Faster and More Effective
Laravel architecture was designed for MVC web applications, making it very powerful in terms of business logic and data presentation. The...
In this article, you’ll learn about:
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 of using 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 the PHP Repository Pattern has many benefits. Below is a list of the most important ones:
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 thinking about 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 can deal with it easily. The repository template greatly facilitates this process!
Despite common misconceptions that PHP is a technology of the past, our extensive experience in web software development has proven its ongoing relevance and efficiency. PHP remains a robust choice for many web applications due to its simplicity, extensive community support, and seamless integration with various databases. By deploying PHP in numerous projects, we have enabled startups to launch scalable, secure, and cost-effective platforms quickly. COO, ASPER BROTHERS Contact Me
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 folder structure. We should start by creating a Repository folder in our app folder. We should create another folder with a current repository implementation inside a newly created folder. 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 the 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 implementing 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 lines 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 making logic 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 PHP application.
Finally, a summary of what is worth noting when implementing a repository pattern.
Laravel architecture was designed for MVC web applications, making it very powerful in terms of business logic and data presentation. The...
If you’re reading this post, then you’ve likely heard that Laravel is the recommended PHP framework for robust application...
PHP frameworks are the most frequently chosen solution when it comes to web development. In the market, you can find a...
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
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! 🙂
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?
… 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. 🙂
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?
Agree with @mohammad, the model should be decoupled so as not to depend on Eloquent model in our controllers.
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. 🙂
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
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
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’.
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
You probably didn’t injected you service provider, check if you add the provider into your app.php file
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.
after many years working with Laravel, i get the point: using Repository pattern as a proxy for Eloquent model methods is totally bullshit.
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
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
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!
You should not use repository pattern with ActiveRecord – all logic for receiving and updating models already stays within models. All you did is just created a useless layer of abstraction and probably caused N+1 querry issue because you will get data on top of the Eloquent but not within. Eloquent has its own method to avoid repeatable code, and it’s called scopes.
hey there
I think the BaseRepository you have extended is extra in UserRepository because instead of parent::all() you used it self query
have fun 🙂
Why users still make use of to read news papers when in this technological world
everything is accessible on net?