For example, you could simply break a more complicated task into a command/job.
The problem is when you have many times the same query across different tasks.
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
So I've been thinking about repositories recently, and questioning their usefulness when working with Eloquent (or really any ORM). Some thoughts:
1. Repositories allow you to swap out your data source (rely on interfaces)
While this is maybe a strong argument for some, in my experience it isn't. I don't ever plan on changing my ORM, at least not without a major rewrite. And Eloquent (along with any decent ORM) already supports multiple database types, so I still have the freedom to swap from MySQL to PostgreSQL to SQlite.
2. Repositories help keep your controllers slimmer
This is true, but there are other ways to accomplish this. For example, you could simply break a more complicated task into a command/job or query object. In fact, I find this is often clearer, especially when there is business logic that goes with it.
3. Repositories make for easier testing
So, the thinking here is that I use an ArrayUsersRepository instead of my EloquentUsersRepository when testing so I don't have to hit my actual database. But I literally never do that. I simply mock out my UsersRepositoryInterace. But the thing is, this can be done with Eloquent objects as well. Ideally you would inject your Eloquent objects into your class, but technically it's even possible to mock the Facades.
So, and I missing something? It seems many are actually using the DAO pattern and calling it the repository pattern. What do you think?
For example, you could simply break a more complicated task into a command/job.
The problem is when you have many times the same query across different tasks.
The problem is when you have many times the same query across different tasks.
That's a good point actually. I've been reading, and the popular approach here seems to be query objects. It's sort of the same thing as a repository, but instead of it just being a method in your repository, it's a standalone class. But the point is, you only create these when you need them, not for every single database interaction.
But I agree with you I barely use repositories in my project. I think it became so popular because it is the canonical example of interfaces allowing to switch implementation.
I think it became so popular because it is the canonical example of interfaces allowing to switch implementation.
Totally.
Repositories also help to keep your models slimmer which can easily fall into the same pitfall as controllers. I personally like really small and dumb models. Well.. small and dumb classes in general I guess. All about that separation of concern.
But it's pretty handy to be able to omit them in favor of Eloquent in projects to save time and sanity too.
Also, repositories are really helpful when you want to use decorators. Caching, Access Control, etc, can easily be done at the repository level with decorators.
@thepsion5 Can you show an example of a repository decorator allowing access control ?
@thepsion5 Yeah, I saw that screencast, I'm just not sure I like my repositories handling that stuff.
[Related] Excellent blog post by Adam Wathan that goes into more detail on the issues with Active Record and repositories: Active Repository is an anti-pattern
@reinink What screencast? :P
"Swap out your X."
I think that's what the answer to this question ultimately comes down to.
Your first two options are both essentially about encapsulation: hiding the complexity of data access so that the using codes becomes smaller, and so that the knowledge/logic isn't duplicated all over your code. If you really switch out your storage layer, you won't need the original implementation anyway, so all you care about is encapsulation.
You'll only need an interface if there may be multiple implementations at any given point in time. A good example may be software you distribute, that can store its data both in a traditional SQL database and in Mongo. Also, someone mentioned a separate implementation for testing - that would be a valid use case, too.
I'm probably using the pattern all wrong but I like to use a repository to encapsulate all my entity fetching. This is great for keeping the logic needed for paginating, filtering, sorting or caching result sets. I've got a baserepository which I use; maybe will be putting it online if there is any interest.
I normally use gateway objects (or query objects - not sure if they're the same thing) to group related queries and business logic. This way it's easy to reuse them, cache, etc.
@pmall Sure. Here's a simple example, for anything more complex one would presumably have a separate ACL class one would inject into the decorator:
class ProfileRepoAccessControlDecorator implements ProfileRepository
{
/**
* @var \App\Domain\Profiles\ProfileRepository
*/
private $next;
/**
* @var \Illuminate\Contracts\Auth\Guard
*/
private $auth;
/* constructor, etc... */
public function findById($id)
{
$profile = $this->next->findById($id);
return $this->filterProfileByUserAccess($profile);
}
public function getAllProfiles()
{
$profiles = $this->next->getAllProfiles();
foreach($profiles as &$profile) {
$profile = $this->filterProfileByUserAccess($profile);
}
return $profiles;
}
protected function filterProfileByUserAccess(Profile $profile, User $user = null)
{
$user = $user ?: $this->auth->user();
if(!$user) {
return null;
}
return $user->isSuperAdmin() || $profile->ownedBy($user) || $user->oversees($profile->owner);
}
}
@thepsion5 ok thanks, it is inspiring :)
@thepsion5 What is advantage of using it like this?
@bobbybouwmann Simplicity. You configure the decorator once in your service provider, and then you don't need to worry about access control in any of your application services, controllers, views, middlware, etc. If the user doesn't have access to it, your application transparently handles it the same way as if it didn't find the entity in the first place. In many cases, that's preferable for security reasons (vs. the end user knowing that an entity with a specific ID exists but they can't see it).
@thepsion5 use middleware for ACL instead?
I have used a repo pattern for years now, but just the other day when I was cleaning up code for deployment. It occurred to me that in many cases it does just clean up your controllers for the most part.
I look at the repo pattern more of a translation layer or wrapper. Instead of create you call addNewUser, abstract the common queries to a base repo. then more complex queries to each repo. It helps keep your queries in one spot and like I mentioned turns query code into more business friendly method names but you still seem to repeat yourself quite a bit by calling the same methods over and over...
@mantasmo That's definitely a viable alternative, but I've had cases where apps communicated internally or via the command line where I needed to put the ACL logic as part of my core domain as opposed to just the HTTP layer.
I think the Repository pattern falls short due to the way it's usually utilized. The idea would be, that you can swap out a database layer easily. But in most cases repositories are just a wrapper around eloquent
<?php
...
class EloquentUserRepository implements UserRepositoryInterface
{
...
public function all()
{
return $this->model->all();
}
...
}
We end up with Eloquent instances anyway, and if we rely on them (relations for example), it can't be "easily" changed without breaking the application. To really be able to swap out db layers, you would need to do a lot more than this.
I don't use the repository pattern per se but I often find that I need an object that may need more than one model injecting into it. So I guess that can be referred to as a repository of sorts.
For example, If I have a book application and a book model has a many-many relationship with authors and a many-many relationship with categories and a one-many relationship with publishers. What I want is to have one class that gets injected into my controller so that I can easily fake it out for testing, I don't want to inject all the models into the controller and I don't want my models having knowledge of other models.
A 'repository' which gets injected with the appropriate models it needs to do it's job where I can just call a method saying 'Here is all the data you need to create and save an instance of a book including book data, author data, publisher and categories... go and create every database record that it needs and give me the book model back' is my solution of choice.
To my mind, a repository pattern is useful to use if your client is unsure as to where the data is going to originate from or be stored so that is can be swapped out easily but if you know it's going to be a database then it's probably overkill.
@mantasmo Could you give an example of one of those gateway objects?
My current view on repositories is to only reach for them when I have a very specific reason to do so. Sort of a "guilty until proven innocent" approach, haha.
I don't worry too much these days about Eloquent calls from the controller. The big benefit to repos is the ability to assign a readable name to a complicated query. That way, you're not rewriting the same long query in multiple spots.
However, as a couple others noted here, query objects can be really useful for those sorts of things. I don't think we have a video on that, so I'll try to tackle one this week.
Update: Here it is. :) https://laracasts.com/lessons/scopes-repositories-and-query-objects
Great discussion here.
The big benefit to repos is the ability to assign a readable name to a complicated query. That way, you're not rewriting the same long query in multiple spots.
What about defining a new scope ?
My main argument for repositories is they provide a way to abstract away the details of my data access, let you interact with your data in an API-oriented vs schema-oriented way, and ensure consistent formatting for data being returned.
For example. I might get most of my simple SELECT * FROM table WHERE id = x type queries via Eloquent, but more complex queries that need hand-tuned joins will use the query builder directly and skip Eloquent altogether. Also, maybe one of my data sources is a 3rd party API of some kind.
Repositories allow me to massage any data collected before it's sent to a controller, so it's always in a consistent, expected format. It also allows me to be explicit in what my application is allowed to do with that data, AND allow me to speak to my controllers in business-oriented language. By that I mean that I won't have a 1:1 mapping of repositories to database tables. I want my controllers to not have to worry about understanding the schema and makes it so the logic is centered around business objects.
For example, I might have a complex entity in my application - let's say something like courses. Courses likely have a ton of different related tables that make up the concept of a "Course". Repositories allow me to write functions that let me operate on courses from the perspective of the user of the application. Maybe I want to register for a course - I'd do that through the course repository despite that data not being saved to the courses table.
ALSO, when you start thinking of your application in this way, you're also setting your app up to have an awesome, logical API.
Would definitely like to see an example or video of query objects, seems like they could be useful when you only have a few complex queries and feel like a full repository class might be overkill or just unnecessary.
Also curious what people think about implementing a repository for some models that warrant it and then just using eloquent models where it seems unnecessary - basically implementing some repositories vs forcing all model access everywhere to use a repository and ending up with a lot of wrappers. Could be expanded to any design pattern or any new thing you want to try out but very curious as I've been having this debate a lot at my job.
I don't understood using repositories. The claimed benefit of being able to swap out database implementations never made sense to me. It's a lot of work for a change that I would only expect during a large rewrite (not to mention Laravel already makes it easy to switch SQL-style databases). As to being a place to put complex queries, I personally just throw those in my models (bad practice? it's just way simpler than adding a whole new application concept) and use service objects to hold business logic (e.g. create user, update application, etc). I do tend to work on smaller apps. Maybe it would make more sense if I was working on larger apps?
I started using repositories with the idea of being able to swap implementations, and I started defining interfaces for every repository and project, let's face it: it's a waste of time, 99% of the time it is not going to be needed, you can mock repositories or even Eloquent models for testing, so you don't need the interface, and you don't even need the repository in that scenario.
And if suddenly your SQL projects needs to use a NoSQL DB instead, well, in that case, you refactor.
Otherwise (expecting everything to change, etc. etc. for no particular reason) makes development really hard and slow.
But... Nowadays I use repositories as a way to clean my controllers, extract the query logic, reuse that query logic (for example imagine you have a public web, an admin panel and a REST API, and those need the same query).
This is a small example I've developed for a demo app:
// Controller stuff
public function latest()
{
$tickets = $this->ticketRepository->paginateLatest();
return view('tickets/list', compact('tickets'));
}
public function open()
{
$tickets = $this->ticketRepository->paginateOpen();
return view('tickets/list', compact('tickets'));
}
class TicketRepository extends BaseRepository {
public function getModel()
{
return new Ticket();
}
protected function selectTicketsList()
{
return $this->newQuery()->selectRaw(
'tickets.*, '
. '( SELECT COUNT(*) FROM ticket_comments WHERE ticket_comments.ticket_id = tickets.id ) as num_comments,'
. '( SELECT COUNT(*) FROM ticket_votes WHERE ticket_votes.ticket_id = tickets.id ) as num_votes'
)->with('author');
}
public function paginateLatest()
{
return $this->selectTicketsList()
->orderBy('created_at', 'DESC')
->paginate(20);
}
public function paginateOpen()
{
return $this->selectTicketsList()
->where('status', 'open')
->orderBy('created_at', 'DESC')
->paginate(20);
}
}
Notice how:
Another option? I could have implemented those as static methods inside the Ticket model, which is ok for small or medium size apps, but as the app grows you could end up with 1000+ lines of code models.
What I recommend? Have fun with Eloquent+Fluent in the controllers, focus on building your app, it starts to get complicated or you need to reuse a query? Create a static method in the model, model starts to grow? Implement repositories.
Are you working in a crazy project with crazy APIs and no one knows how to use them yet? Implemente Repository Interfaces (UserRepositoryContract), work with SQL Lite or MySQL (UserEloquentRepository) so you can develop a fast prototype to show it to the client without waiting for API madness, as API clarify you can start writing and testing a new UserCrazyApiRepository, the API works? Swap implementations and everyone will be happy.
Don't try to use the same solution for every project. "It depends" as Jeffrey have explained lately.
I use repositories completely wrong. I used them as wrappers for either complex query sets or interfacing with services I might one day swap out for another. I've always done it that way long before I was using Laravel. I prefer that slim controller and model look to my code.
Please or to participate in this conversation.