


Your Laravel application with Repository doesnt make any sense
I’ve seen over the years many developers using the Repository pattern with Laravel, attempting to apply clean architecture concepts to their applications, but often misunderstanding the general concept of using a framework like Laravel.
Before I start and have to dodge some stones that I know you folks might throw my way, let me be clear: this is my opinion as a software engineer who has worked with several languages, frameworks, building software from scratch, and maintaining old legacy codebases. My word is not final, and as always, I believe the most acceptable answer to any software engineering question is: “It depends on what you are willing to trade off to solve your problem.”
So, without further ado, let’s get into the subject.
What is Clean architecture?
Clean Architecture is a software design philosophy that aims to create systems that are easy to maintain, test, and understand. It emphasizes the separation of concerns and the creation of boundaries between different parts of the system to ensure that changes in one part do not adversely affect others. This architecture was popularized by Robert C. Martin (Uncle Bob) and is often used to guide the organization of code in a way that is resilient to changes in business rules or technical requirements.
In short, what Bob proposes is that your application should be split into layers that follow key principles to allow your business logic to be decoupled from any external dependencies, giving them mobility and a single responsibility context. But this isn’t going to be a clean architecture article; I just wanted to put us on the same page about it.
How about Laravel and Clean Architecture?
When it comes to frameworks, we’re talking about tight coupling of dependencies. You likely didn’t pick Laravel to use Doctrine with it; you probably chose it to use Eloquent. The same goes for any piece of framework functionality you may find — you are picking the framework for development speed and convenience.
So, my question is: Why would you add an extra complexity layer to something that you picked to be simple?
Wait, don’t hate me for saying this. You can still adapt or even use clean architecture with Laravel, but the most important aspect of any architectural decision is having a clear understanding of what you are trying to achieve and the pros and cons of those choices.
It’s a hard decision, and you can change your mind in the middle of an implementation. Software should not be immutable, right? I have a whole article about software quality where I raise this flag.
Anyway, getting back to Laravel and clean architecture. One of the most annoying approaches, in my humble opinion, is the use of the Repository pattern with Eloquent, and this is what motivated me to write this article.
Repository Pattern
The Repository pattern is a design pattern that mediates between the domain and data mapping layers, acting as an in-memory collection of domain objects. It aims to decouple the domain and data mapping layers.
So, the Repository definition is a domain entity. Why? Because it interacts with the domain and defines how the infrastructure interacts with the domain, acting as a contract between the Domain and the Infrastructure layer of our application.
The Repository Pattern on Laravel
First, let me show you a bad implementation of the Repository pattern that I often see in Laravel applications and then fix it for you:
// app/Repositories/UserRepositoryInterface.php <?php namespace App\Repositories; interface UserRepositoryInterface { // ...methods definitions }
// app/Repositories/UserRepository.php <?php namespace App\Repositories; class UserRepository implements UserRepositoryInterface { // ...implementation }
As you can see in the code above, the “contract” with the domain and the infrastructure isn’t defined inside the domain, but inside the infrastructure itself. Yes, the App namespace is part of the Application Layer, and it contains all the non-domain stuff.
Now, let’s see how I would implement the same thing:
// domain/Repositories/UserRepositoryInterface.php <?php namespace Domain\Repositories; interface UserRepositoryInterface { // ...methods definitions }
// app/Repositories/UserRepository.php <?php namespace App\Repositories; use Domain\Repositories\UserRepositoryInterface; class UserRepository implements UserRepositoryInterface { // ...implementation }
Notice that now we have a proper domain layer and an application layer. It is quite simple to get, right?
The Repository Pattern with Eloquent
Now, let us think a bit. Since the Repository Interface is now part of the Domain, it means that we can’t simply inject dependencies from other layers into it. Here’s a bad example to explain it:
// app/Repositories/UserRepositoryInterface.php <?php namespace App\Repositories; use App\Models\User; interface UserRepositoryInterface { public function find(int $id): User|null; // ...other methods }
Not clear yet? Let me move it to the domain layer:
// domain/Repositories/UserRepositoryInterface.php <?php namespace Domain\Repositories; use App\Models\User; interface UserRepositoryInterface { public function find(int $id): User|null; // ...other methods }
See the problem? We’re injecting an Eloquent model that is part of the infrastructure layer into our domain. This tightly couples our domain to Eloquent, which defeats the purpose of the Repository pattern.
But how do we solve it? Well, it is not as hard as you might think. You probably already heard about Entities, right? So, let’s fix it:
// domain/Repositories/UserRepositoryInterface.php <?php namespace Domain\Repositories; use Domain\Entities\User; interface UserRepositoryInterface { public function find(int $id): User|null; // ...other methods }
// domain/Entities/User.php <?php namespace Domain\Entities; class User { public function __construct( public int $id; public string $name; public string $email; ) {} // ...other properties and methods }
Our domain layer is now clean from external dependencies, and if we want to move the whole domain to another framework, we can do it.
Now, how do we implement our Repository in our Laravel application? Let me show you:
// app/Repositories/EloquentUserRepository.php <?php namespace App\Repositories; use Domain\Repositories\UserRepositoryInterface; use Domain\Entities\User; use App\Models\User as EloquentUser; class EloquentUserRepository implements UserRepositoryInterface { public function find(int $id): ?User { $eloquentUser = EloquentUser::find($id); return $eloquentUser ? $this->toDomain($eloquentUser): null; } private function toDomain(EloquentUser $eloquentUser): User { return new User( $eloquentUser->id, $eloquentUser->name, $eloquentUser->email ); } }
Now we have a proper implementation of the Repository pattern in Laravel using Eloquent. You can create any other Repository implementation, such as PDOUserRepository.php, DoctrineUserRepository.php, and many others without injecting any dependency into your Domain layer.
Do You Really Need to Use Repository?
Back to what I said in the subject of this article, I’ll complement that, in my humble opinion, using the Repository Pattern with Laravel is just overengineering, and you need a really good reason to do it.
You are adding an extra layer of complexity to your application that you may not need at all, or even worse, it will not guarantee that your business logic is actually isolated into the Domain layer.
What are you trying to achieve here? Think about it. You might end up missing out on many nice functionalities from Laravel or at least making their usage overly complicated.
Are you not sure if Laravel is the best framework for your application and you might move your application to Symfony in the future? Sure, go for the Domain and the Repository. Do you need to replace your SQL database with a NoSQL database later? Maybe it is a good justification. But do you really need it, or is it just charm?
One common argument is that the Repository helps to put some business logic into a separate layer. This normally gives me the creeps because there are better approaches for splitting your logic. Repositories are just for acting as a middle layer to connect the data layer and domain, nothing else. If you want to split your business logic, you should make use of something else — but this is another subject.
Conclusion
In conclusion, while the Repository pattern and clean architecture principles offer significant benefits in terms of maintainability and separation of concerns, their application in a Laravel context often introduces unnecessary complexity. Laravel is designed for simplicity and rapid development, and adding layers of abstraction can complicate this process.
Before implementing the Repository pattern, it is essential to evaluate your project’s specific needs. If decoupling your domain logic from Laravel’s infrastructure is a genuine necessity due to future migrations or a need for flexibility, then the complexity might be warranted. However, for many Laravel applications, leveraging Eloquent directly aligns better with the framework’s strengths and keeps the codebase simpler and more maintainable.
Ultimately, the decision should be driven by a clear understanding of your project’s requirements, balancing the trade-offs involved. Overengineering can lead to more problems than it solves, so aim to keep your solutions as straightforward as possible while still achieving your design goals. The primary objective of any architecture is to solve problems, not to create new ones.
The above is the detailed content of Your Laravel application with Repository doesnt make any sense. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics











JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

Session hijacking can be achieved through the following steps: 1. Obtain the session ID, 2. Use the session ID, 3. Keep the session active. The methods to prevent session hijacking in PHP include: 1. Use the session_regenerate_id() function to regenerate the session ID, 2. Store session data through the database, 3. Ensure that all session data is transmitted through HTTPS.

RESTAPI design principles include resource definition, URI design, HTTP method usage, status code usage, version control, and HATEOAS. 1. Resources should be represented by nouns and maintained at a hierarchy. 2. HTTP methods should conform to their semantics, such as GET is used to obtain resources. 3. The status code should be used correctly, such as 404 means that the resource does not exist. 4. Version control can be implemented through URI or header. 5. HATEOAS boots client operations through links in response.

In PHP, exception handling is achieved through the try, catch, finally, and throw keywords. 1) The try block surrounds the code that may throw exceptions; 2) The catch block handles exceptions; 3) Finally block ensures that the code is always executed; 4) throw is used to manually throw exceptions. These mechanisms help improve the robustness and maintainability of your code.

The main function of anonymous classes in PHP is to create one-time objects. 1. Anonymous classes allow classes without names to be directly defined in the code, which is suitable for temporary requirements. 2. They can inherit classes or implement interfaces to increase flexibility. 3. Pay attention to performance and code readability when using it, and avoid repeatedly defining the same anonymous classes.

In PHP, the difference between include, require, include_once, require_once is: 1) include generates a warning and continues to execute, 2) require generates a fatal error and stops execution, 3) include_once and require_once prevent repeated inclusions. The choice of these functions depends on the importance of the file and whether it is necessary to prevent duplicate inclusion. Rational use can improve the readability and maintainability of the code.

There are four main error types in PHP: 1.Notice: the slightest, will not interrupt the program, such as accessing undefined variables; 2. Warning: serious than Notice, will not terminate the program, such as containing no files; 3. FatalError: the most serious, will terminate the program, such as calling no function; 4. ParseError: syntax error, will prevent the program from being executed, such as forgetting to add the end tag.

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.
