Laravel — Your controllers should look like this
Tags: laravel, webdev, programming, php
Published: 2022-12-30 09:48:04

## The scenario

It’s not rare to start working on a project and need to deal with god classes controllers. Do you know what I mean? Who never faced a controller store method that validates, persists, creates a relation, sends emails, …, and return a response?

I see it as a very common approach in the Laravel community, while the Rails devs tend to do almost the same in models classes. I don’t think it is that bad to have something else (in addition to handle the requests and responses) inside the controllers in some specific situations, but in general I would prefer to use the first principle of SOLID: Single-responsibility principle (SRP) doing a little more now to make it easier in the future.

The benefits of moving business logic from controllers to new classes are countless, but let me mention three of them:

- You’ll be able to reuse your code
- Your code will be easy to understand and maintain
- You’ll be the responsible for part of the next developer happiness 😊

![funny developer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yte7krrbfkuu2rp6i45p.gif)


---


## Let’s see how to apply this concept refactoring a controller

To make it simple let’s see an example where a UserController just validates the data, creates a new user, his roles and redirects with a status message:

```
public function store(Request  $request)
{
  # Validate data
  $request->validate([
    'name' => 'required',
    'email' => 'required|unique:users',
    'phone_number' => 'required',
  ]);

  # Create a user
  $user = User::create([
      'name' => $request->name,
      'email' => $request->email,
      'phone_number' => $request->phone_number,
  ]);
    
  # Create the user's roles
  if(!empty($request->roles)) {
    $user->roles()->sync($request->roles);
  }
  
  #  Redirect with a status message
  return redirect()
    ->route('user.index')
    ->with('message','User created successfully.');
}
```

It looks fine, right? But we can make it better. First of all, lets move this validation to a Form Request by running this command:
`php artisan make:request StoreUserRequest`


It will create a new file in this directory: App\Http\Requests. I’ll just authorize the use and cut my validation rules from controller and paste it in the rules method like this:
```
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
          'name' => 'required',
          'email' => 'required|unique:users',
          'phone_number' => 'required',
        ];
    }
}
```
[How to use](https://laravel.com/docs/9.x/validation) this class:
> All you need to do is type-hint the request on your controller method. The incoming form request is validated before the controller method is called, meaning you do not need to clutter your controller with any validation logic

```
use App\Http\Requests\StoreUserRequest;


public function store(StoreUserRequest $request)
{
  # Create a user
  $user = User::create([
      'name' => $request->name,
      'email' => $request->email,
      'phone_number' => $request->phone_number,
  ]);
    
  # Create the user's roles
  if(!empty($request->roles)) {
    $user->roles()->sync($request->roles);
  }
  
  #  Redirect with a status message
  return redirect()
    ->route('user.index')
    ->with('message','User created successfully.');
}
```
A little better. Now we are going to create a new service class. This one will be the responsible for creating Users.

Since we don’t have artisan commands to do it, we will need to create it manually. Inside the app directory I have created a service folder with my new class: app/Services/UserService.php and moved the logic from the controller to this class:

```
<?php
namespace App\Services;
 
use App\Models\User;
use Illuminate\Http\Request;
 
class UserService
{
    public function createUser(Request $request): User
    {
        # Create a user
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'phone_number' => $request->phone_number,
        ]);
          
        # Create user's roles
        if(!empty($request->roles)) {
          $user->roles()->sync($request->roles);
        }
        return $user;
    }
}
```

And now, in the controller, lets import and type-hint the dependency we just created:

```
use App\Services\UserService;

public function store(StoreUserRequest $request, UserService $userService)
{
    $userService->createUser($request);

    return redirect()
      ->route('user.index')
      ->with('message','User created successfully.');
}
```

Could you notice the difference?
Yeah, now we have more classes and files to work with, but in the other hand each one of them have it’s own responsibilities, they can be reused in other parts of the application and individually tested.

Not to mention the controller that is now responsible only to receive the request, call the right service and return a response.

Prettier, isn’t it?

---

## Should I use service classes?

Well it’s up to you to evaluate and decide what will work for your project. I personally prefer it, but I already have worked on projects where the approach was totally different.

It is not a general rule, but when building a new application you should consider to keep each class as clean as possible including your controllers.

Thank you for reading!

![thumbs up](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgr96luyfdyr77ub29u0.gif)