Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bigsinoos's avatar

Reasons I abandoned repository pattern in Laravel

I used to do database stuff inside repository implementations. This is how I was treating problems:

Scenario : Creating a user :

  1. Creating validation services like UserStoreValidator.
  2. Calling the validator inside the controller and passing the user's input to the validator.
  3. Creating a service class called UserCreator and adding a create method to that.
  4. Creating a UserRepositoryInterface and a UserRepository class, adding a createUserFromArray method to it, or sometimes just calling the the createRaw(array $data) method from my AbstractEloquentRepository implementation. The method is called from my user creator service.
  5. And doing some other jobs like sending welcome_email by Events which are fired inside my service classes.

There are examples of how I was doing stuff inside repositories:

  1. SalesBoss CRM
  2. Pardisan CMS

In this strategy I was able to decouple all of the business from each other. But someday I started to move one of my implementations into MongoDb with Doctrine's ODM. What I was expecting was really different from what I experienced. It is not just adding another implementation of my repository interface. In my opinion ** Laravel's power is in Eloquent **. I was just duplicating a lot of logic that eloquent already had into my repositories like SoftDeletes and Eventing system.

By using services I have put lots of repetitive logic inside them and my controllers are still thin. Removing repositories causes models to be fat, but it's ok to have models with +2000 lines of code instead of repositories with +2000 lines of code.

Using repositories with Eloquent does not allow you to swap between different storages or drivers easily. there were lots of eloquent features that I was using inside my eloquent implementation which I rewrote them in my Doctrine implementation like deleting model's related files in model's deleting event, or some recursive calls to update nested parents of a record in my model's updating call, I came to a solution to implement the same features in my abstract repository, but it was a buggy decision, and eloquent is not the right tool if you don't use its features.

My relations were only meaningful in SQL databases, I had a really different approach in my MongoDb implementation.

Generally I don't write unit tests a lot, but moving the query logic into models, makes it easy to mock them inside services.

I used to wrap some cache decorators around my repository calls, which is the main great feature I lost. I still use them arround my models but it is not as clean as it was.

Laravel is meant to be used by eloquent and its great features, using repositories decreases the power of eloquent and also my development speed. Using laravel with another DataMapper ORM like Doctrine causes to loose eloquent features. Repositories are not the right place for putting business logic, they are just data delegators , there is no difference in maintenance cost of a model with +2000 lines of code or of a repository class with +2000 lines of code, moving business logic into service classes allows controllers to be still thin.

I ended up with removing repository pattern from my design and moving the logic into models or service classes, actually I made two contracts for putting business into models or service classes :

  1. Any single unit of business of records are moved to models (like actions on model events).
  2. Other businesses like sending text messages, emails, indexing elasticsearch with a nosql data structure, are moved into service classes.

I really like to know your idea on using repositories in your projects .

0 likes
13 replies
Mattiman's avatar

Seems like a smart decision. Eloquent is already an extra layer which can handle a lot of things in an easy way. Adding another layer in between should only be done if it really adds something. "so I can easily switch database system" sounds good but the question is how big the chance is that you do that in practice.

1 like
pmall's avatar

Repositories are not the right place for putting business logic, they are just data delegators

Yes this is the point. You shouldn't have expected more.

Using repositories with Eloquent does not allow you to swap between different storages or drivers easily.

Yes I agree. It is overrated but it is mentioned regularly because it is a canonical example of interface implementation switch.

If you like the data mapper approach like doctrine, I suggest you have a look on analogue orm. It is a great datamapper package made for laravel.

1 like
bobbybouwmann's avatar

The idea of the repository pattern is to work with an interface! It's so much eacher to code to an interface. I implemented the repository pattern just for this reason. I'm also 99% procent sure I won't switch my database driver, but I like to code to that interface which you get when you use the repository pattern

2 likes
sukonovs's avatar

To use repositories you must ignore eloquent specific features, or implement them by yourself. You save standard objects (or arrays), you get standard objects.

From online discussions, books and my experience I came to conclusion that If you decide to use active record implementation, use it without any wrapper classes. Eloquent has nice features that reduces duplication, like scopes. Other cases you can just put into model, there is nothing wrong with that. When you need repositories, entities and other DDD stuff just switch to Doctrine it will be easier.

9 likes
jekinney's avatar

Great post. I too jumped on the repo train and ended with a similar opinion. Why create a wrapper for eloquent? Lol on swapping database, said it for awhile, if you have significant data already and then swap for a non-eloquent supported db the few classes are a least of your worries.

Now on fat models, that argument will always be there, has been in asp since mvc came out. Even using helpers, traits, or extending classes etc. all really does is help or confuse the developers be pending but does it really help the code? Nope as on run time it all gets read.

2 likes
nateritter's avatar

I'm curious about your response to one of the named benefits of using the repository pattern being easy testability without hitting the database via mocks. Thoughts on that?

ohffs's avatar

@nateritter I think the current thinking is that hitting the db is fine. The "don't touch the DB!" was from a time when that was really problematic, slow (and possibly expensive) - now we have in-memory sqlite etc, so spending the time making mocks etc is more costly than just hitting the 'real' service.

1 like
nateritter's avatar

@ohffs Interesting. Most of the applications I work with include the use of some big, already present, datasets. Hitting the db is usually not much of a problem, but spinning up and destroying the tables that contain that data is not feasible. This is why the repository pattern and testing appeals to me.

That said, adding repos seems to be cumbersome at best, and I have yet to build an app that required changing storage.

I vacillate on this subject every time I start a new project that's of any decent size.

MikeHopley's avatar

Most of the applications I work with include the use of some big, already present, datasets. Hitting the db is usually not much of a problem, but spinning up and destroying the tables that contain that data is not feasible.

Normally you would run your tests against a much smaller set of test data, rather than mirroring the production database contents.

There are also ways to make the "spin up / tear down" much more efficient, such as wrapping the test in a database transaction and rolling back the transaction after the test.

2 likes
themanish's avatar

Generally I don't write unit tests a lot, but moving the query logic into models, makes it easy to mock them inside services.

May be this was the main reason you abandoned repository pattern. May be this post (https://heera.it/laravel-repository-pattern) might put some light on it.

1 like
bigsinoos's avatar
bigsinoos
OP
Best Answer
Level 1

7 years later and this was one of my best decisions in writing software. Either use DataMapper ORM with separate persistence layer or ActiveRecord models not both.

Keeping application as close as possible to the Laravel way is the best way to keep it maintainable across different teams, official community trends and new versions. Worst applications to maintain and upgrade were those who invented architectural approaches baed on an incorrect or partial summary of a book or medium post.

Today, The same goes for Service objects (use case scenarios) or anything modeling your app outside the scope of the model itself (models backed by eloquent or just rich objects connected to other models.)

1 like
MrMoto9000's avatar

Every so often the repository pattern rears its head again, thanks for coming back and updating your thoughts after abandoning it.

Would love to hear more on this:

The same goes for Service objects (use case scenarios)

Please or to participate in this conversation.