What is The Clean Architecture structure?
“Clean Architecture” is a project structure first mentioned by Robert C. Martin (Uncle Bob).
At first glance, this is the diagram of the structure:
The structure is divided in layers, where each layer does have a precise function, separated from the others.
The simplest and more important rule of this structure is:
An inner circle must never know anything about the circles around it.
To learn more about the benefits of this structure, and see the levels in detail, you can read the article on Uncle Bob's blog.
What we want to do today, is apply this structure in a Laravel project that uses the MVC (Model-View-Controller) design pattern.
Let’s go through every level.
Entities
TL;DR: this layer contains "Enterprise Business Rules”.
This is the layer that should change less during the development of the project.
Why?
Because the objects inside this layer contain the enterprise wide business rules, and usually they are defined at the start of the project (or at the start of a new feature).
In a Laravel project there is no Entity concept: we have to create it.
We can create a folder inside the app folder, called “Entities”.
Use Cases
TL;DR: this layer contains the actions your project performs.
Good examples of use cases are:
- Login
- Register
- ConfirmOrder
A use case should be a single, very specific action. It shouldn’t do anything more than its name suggests.
If you structure your project with use cases, you get an unexpected and very powerful benefit: you are creating your project’s documentation.
If an external developer looks at your use cases list, it understands exactly what your project is about.
In a Laravel project there is no UseCase concept: we have to create it.
We can create a folder inside the app folder, called “UseCases”.
Interface adapters
TL;DR: this layer contains all MVC elements.
This is the most controversial and ambiguous layer.
Many classes could be inside it, it’s the developer choice.
For start, the best decision in a Laravel project is to put inside it:
- Models
- Views
- Controllers
At the end of the day, how should I develop?
- In a Laravel controller, you can just call an UseCase.
- In an UseCase, you can just call classes in the Entity layer.
An example of Laravel controller:
namespace App\Http\Controllers;
use App\UseCases\LoginUseCase;
use Illuminate\Http\Request;
public class AuthController extends Controller
{
public function login(Request $request)
{
LoginUseCase::run($request);
}
}
What if I have to update a database model in an UseCase?
Since a model is in the Interface Adapters layer, an UseCase must not depend on a lower layer.
So we add the Repository pattern to abstract the Database and to create coupling only between UseCase and Repository.
In a Laravel project there is no Repository concept: we have to create it.
We can create a folder inside the app folder, called “Repositories”.
An example of UseCase:
namespace App\UseCases;
use App\Repositories\UserRepository;
class LoginUseCase
{
public static function run(...$arguments): mixed
{
return UserRepository::login($arguments);
}
}
Our Laravel project structure will be:
app
Http
Entities
Models
Providers
Repositories
UseCases
Best practices
Always work with interfaces.
You should create interfaces for every layer, in order to keep your code more stable and maintainable.
- EntityInterface
- UseCaseInterface
- RepositoryInterface
- ArchitectureControllerInterfacer
Now what?
There are a lot of improvements you can do. These are some examples:
- Use Laravel validation rules for validating parameters passed to use case;
- Work with dependency injection and substitute the static run function with a not static run function;
I developed a PHP package on Github to use it.
Top comments (0)