1

My Laravel project starts to grow up and I'm starting to dealing with fat Controllers and Models. Probably I'm for away from the SOLID principles path and my code is not DRY.

I decided to refactor my layers logic to follow more SOLID and try to be more DRY. After some research over the internet I ended up with the following conclusion:

enter image description here

Let me explain this diagram:

  1. First, we start with a view, where the user performs some action and the request is sent to the Controller.
  2. Controller responsibility is to handle the request and give the response to the user. It will be able to call 3 different layers (blue numbers):
    • Service: to handle business logic like calculations, special actions, etc.
    • Repository: where all query logic will be placed. For example, if on index method we want to return the users list with users that have more than 100 posts and are ordered by name (Example 1).
    • Laravel Resource (Transformers): with the responsibility to transform a model into JSON. When we change our table we don't have to change all the views and controllers or models affected by that change. It will be all done in one place.

Example 1:

 # UserController.php
 public function index()
 {
     $users = new UserCollection($this->UserRep->usersWithPost());
     return view('user-list', compact('users'));
 }

 # UserRepository.php
 public function usersWithPost($min = 100)
 {
     return $this->model->where('post_count', '>=', $min)->orderBy('name');
 }

 # UserResource.php
 public function toArray($request)
 {
     return [
         'id' => $this->id,
         'name' => $this->name,
         'email' => $this->email,
         'post_count' => $this->post_count,
         'created_at' => $this->created_at,
         'updated_at' => $this->updated_at,
     ];
 }

  1. Service calls (green numbers):
    • It may call Repository if it needs any data from my model to perform some action.
    • It also may call Laravel Resource "Transformers" if there were repository calls.
  2. The repository will use the eloquent model to persist query on my data storage (MySQL).

This is how I plan to refactor my code, however, I do not have experience with Laravel and I would like to ask more experienced developers if they can indicate me if I'm on the right path.

Do you think it makes sense and it is a good practice?

I would like to highlight that I will not switch between ORMs. I will use eloquent with MySQL as my data storage, that's why I'm planning to put all my queries to repositories to have a different layer for queries logic.

1
0

I use a similar structure of controller -> service -> repository -> model and I am sticking with it now just fine. But there are a few things that I would change if I could:

Regarding the inconsistency of calling services / repositories on controllers

It is better and more clear for your team to stick always to the same application flow, even if it is something as simple as retrieving a user list, the service exists there to allow you to easily extend your functionality without having to modify the controllers.

For example, you may want to apply filters or pagination to that query, and you will end up moving your calls from the repository to the service to deal with that.

Regarding repositories

They are great to create a bridge between the controller and the model, but when you have services in the middle, then it becomes redundant. Eloquent already implements a pretty nice interface to deal with all the things regarding model manipulation.

I find it better to just place this code in the services, and only extract to other classes when dealing with specific cases, for example extracting the filtering from get parameters onto its own class and re-use it across all services would make sense.

I started out creating repositories, but it became a burden after I realized that it's basically replicating eloquent one-liners most of the time in there.

Transformers

They are a process that you have to go through to prepare the data for the client if I understood correctly. If that is so, then your approach seems fine, I would retrieve the data from the service and pass it onto the transformer before returning to the client.

So to sum up, I think your structure looks good with the minor change of getting the repositories out of the way and sticking with a consistent application flow that would look like
controller->service->model
controller->transformer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.