
The first question you need to answer before you start developing any Laravel application, is “How to make my project’s architecture more maintanable and scalable?” because any project is seen to evolve over time and to be maintained and most of the time by a different team than the one that developed it.
But what is the perfect architecture to use?
There isn’t one architecture or ONE perfect architecture and another isn’t, but we can make our project’s architecture almost perfect by following a few steps.
On this article I explain in 10 steps how to make the architecture of your project “PERFECT”:
- Step 1: Create a folder structure
- Step 2: Define your database schema
- Step 3: Create Models
- Step 4: Create DTOs
- Step 5: Create Repository classes
- Step 6: Create Service classes
- Step 7: Create Controllers
- Step 8: Wire up the layers of your application
- Step 9: Define your application routes
- Step 10: Test your application
Step 1: Create a folder structure
The first step in creating a perfect architecture in Laravel is to create a folder structure that will house the various components of your application. You can create folders named Models, DTOs, Repositories, Services, and Controllers. This will help keep your code organized and make it easier to maintain.
The next folders are already created by default in any Laravel project: Models and Controllers
So, your project structure will look to something like the following:
app/
├─ DTO/
├─ Http/
│ ├─ Controllers/
├─ Models/
├─ Services/
├─ Repositories/
As you can see all the folders we have created are located in the app/
root folder.
Step 2: Define your database schema
The next step is to define your database schema. This involves defining your database tables and their relationships. You can use Laravel’s built-in migration tool to create your database tables.
Of course, before you start defining your migrations you need to do your designing phase, … then you can use the Laravel migrations to make it easy to create your database schema.
To create a migration you can use the following artisan command to have more information:
php artisan make:migration -h
Step 3: Create Models
After defining your database schema, you can create your Models by extending Laravel’s Eloquent Model class. Your Models will represent the entities in your database schema.
At least, for each of your database table you need a model that defines this table as an entity into your Laravel project.
To create a model you can use the following artisan command to have more information:
php artisan make:model -h
Step 4: Create DTOs
Create DTOs (Data Transfer Objects) which are classes that contain only properties that you want to transfer between layers of your application, such as between the Controller and the Service layers. These DTOs help to decouple the layers of your application.
To have more information about using DTO in Laravel you can check my other Medium article here: https://medium.com/@eloufirhatim/what-is-dto-and-how-to-use-it-in-a-laravel-application-7ca1e9045985
Step 5: Create Repository classes
Create Repository classes that will handle all database queries related to a specific entity. These classes will use the Model classes to interact with the database. The Repository classes will provide an interface for the Service classes to interact with the database.
But why using repositories instead of directly playing around with Model classes?
That’s simple! If you are using Model to communicate with your database you will have the same code (logic) everywhere on your application, and when you have make some changes on your code, you have to modify everywhere!
Otherwise, by using Repositories, all you have to do is to modify a specific function so the new logic will be implemented, and you’re good to go!
Step 6: Create Service classes
Create Service classes that will handle the business logic of your application. Services will use Repositories to interact with the database and perform actions on the Models. The Services will also use the DTOs to transfer data between layers.
This pattern is used to centralize your functionalities, and allow your application when needed to call the service to perform this functionality. The same for Repositories, all your logic is centralized in one place and by modifying your service makes it available on all your application.
Step 7: Create Controllers
Create Controllers that will handle HTTP requests and responses. Controllers will use the Service classes to execute business logic and return responses to the client.
To create a controller you can use the following artisan command to have more information:
php artisan make:controller -h
What you need to know, all your business logic must be located in your services and the controllers are here to call the services to do the job. You can see a controller like an “Orchestra Conductor”.
Step 8: Wire up the layers of your application
In Laravel, you can use Service Providers to bind your classes to the Laravel service container. Use Dependency Injection to inject the necessary dependencies into your classes. This will help to keep your code decoupled and easy to maintain.
When creating Repositories and Services, you should use interfaces to define your classes methods signatures, let’s make an example:
<?php
namespace App\Services;
use App\DTO\UserDTO;
interface IUserService
{
public function findAllUsers();
public function createUser(UserDTO $userDto);
public function updateUser(int $id, UserDTO $userDto);
public function deleteUser(int $id);
}
Then you need to define your class, so let’s continue:
<?php
namespace App\Services;
use App\DTO\UserDTO;
use App\Repositories\IUserRepository;
class UserService implements IUserService
{
private $userRepository;
public function __construct(IUserRepository $userRepository) {
$this->userRepository = $userRepository;
}
public function findAllUsers() {
return $this->userRepository->findAll();
}
public function createUser(UserDTO $userDto) {
return $this->userRepository->create([
'name' => $userDto->name,
'email' => $userDto->email,
// ... other fields
]);
}
public function updateUser(int $id, UserDTO $userDto) {
$user = $this->userRepository->findById($id);
$user->name = $userDto->name;
$user->email = $userDto->email;
// ... other fields
return $this->userRepository->save($user);
}
public function deleteUser(int $id) {
$user = $this->userRepository->findById($id);
$user->delete();
}
}
You can see that we are using here a Dependency Injection in our class constructor, and it’s the interface that is used in the injection.
To make this link between the interface and it’s implementing class, you need to add a bind
call into your provider (you can use a specific provider to bind all your interfaces, or add it to your AppServiceProvider
), the following code should be placed into the register()
function of your provider:
// ...
use App\Repositories\IUserRepository;
use App\Repositories\UserRepository;
// ...
$this->app->bind(IUserRepository:class, UserRepository::class);
And you can do the same for your services so you can use them into your controllers.
Step 9: Define your application routes
Define your application routes in Laravel’s web.php or api.php files. Map each route to a Controller method. This will help to define the endpoints of your application and how they interact with the Controllers.
For more details about Laravel routes, check the official docs here: https://laravel.com/docs/routing
Step 10: Test your application
Test your application to ensure that everything is working as expected. You can use Laravel’s built-in testing framework to write tests for your Controllers, Services, and Repositories. This will help to ensure that your application is robust and free from bugs.
For more details about Laravel testing, check the official docs here: https://laravel.com/docs/testing
Happy coding!
33
4
Enjoy the read? Reward the writer.Beta
Your tip will go to EL OUFIR Hatim through a third-party platform of their choice, letting them know you appreciate their story.Give a tip
More from EL OUFIR Hatim
Follow
I’m a Full Stack developer who is passionate about making open-source more accessible and building community.
SOLID principles in Laravel

Share your ideas with millions of readers.
What is DTO and how to use it in a Laravel application?

Laravel – Generate translations automatically

Make your Laravel 9 faster!
