The Single Responsibility Principle - SOLID

Posted on

A Brief Explanation

The Single Responsibility Principle will help you create DRY, modular and easier to maintain code. In short the principle states that each class should have a single responsibility, one job. With that in mind lets get started!

In Practice

Please study the controller class below;

class UserController {

    public function allUsers()

    {
        $allUsers = User::all();

        return view('users.index')->with(['users' => $allUsers]);
    }
    public function notifyUser ($userId)

    {
        $user = User::find($userId);
        Mail::send(['text'=>'mail'], $data, function($message) {
            $message->to($user->email, 'New Notification')
            ->subject('You have a new notification');
            $message->from('info@someservice.com','Admin user');
        });
        return view('users.index')->with(['message' => 'Notifcation sent!']);
    }
}

If each class is to have one job, this controllers is doing too much. The job of this controller is to gather the information needed and render the correct page, but this controller is executing a database query and sending an email.

The code also is not very modular. What if sometime in the future we want to alter the way we send a notification email? We will have to alter the code in every controller we have written it in.

To fix this we need to separate out the logic so that we should be able to alter the DB query and/or Mailer functionality without touhing (or very little touching) this class.

FIRST: remove the user queries out into their own repo, if in the future you need to ammend the database system used or the particular query for getting all the users, you will only have to change it in the repo.

class UserRepository {
    public function getAllUsers () {
        return User::all();
    }
}

Second: We will need to move out the mailer functionality, remember the controller should have only one job, and should not know how to send an email, only what to call to get the job done.

class NotificationMailer {

    public function sendNotification ($user, $subject, $body)
    {
        Mail::send(['text'=>'mail'], $data, function($message) {
            $message->to($user->email, $user->fullName())
            ->subject($subject)
            ->body($body);
            $message->from('info@someservice.com','Admin user');
        });
    }
}

And now the final product, a controller that is doing one job, with a limited about of knowledge of the tasks been done. This fits with the mantra we started with.

“Gather the information and get me the page that i need to render”

We can now alter the way the getAllUsers(), or the NotificationMailer::sendNotification() functions works and we will not break anything in this controller, everything is modular. And easily scalable

use app\Repositories\UserRepository;

use NotificationMailer;

class UserController {
    protected $repo;
    public function _construct (UserRepository $repo)
    {
        $this->repo = $repo;
    }
    public function allUsers()
    {
        $allUsers = $this->repo->getAllUsers();
        return view('users.index')->with(['users' => $allUsers]);
    }

    public function notifyUser ($userId)
    {
        $user = User::find($userId);
        NotificationMailer::sendNotification($user, 'New Notification', 'You have a new notification')
        return view('users.index')->with(['message' => 'Notifcation sent!']);
    }
}