SOLID PHP - Uncle Bob
Using Laravel to stay SOLID
by Emin Bayrak
When I was searching for what general principles that I can follow in my code, I discovered the concept of SOLID design. So why would we want to follow such principles in our development process? The answer is simple, it is always the dream of every developer that we want to write code that is well-structured, flexible, easy to maintain and extendable. So using SOLID’s set of rules would guide us on how to achieve that in Object Oriented Programming.
What makes up SOLID is by following the five principles:
-
(S)ingle Responsibility principle
-
(O)pen/Closed principle
-
(L)iskov Substitution principle
-
(I)nterface Segregation principle
-
(D)ependency Inversion principle
So let’s start it, shall we.
Single Responsibility principle (SRP)
As the name suggests, this principle means a class should only be responsible for one thing, eg., the conversion of data types or the management of entities; and as what Uncle Bob says, a class should only have one reason to be changed. As a developer, we are always a fan of loosely coupled architecture, where a class has little or no knowledge of the separate classes. So giving too much responsibility to a class leads to coupling. For example, if the code needs to know a class in order to use a different class, then these two classes are said to be coupled.
Let’s look at this code example:
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\News $news
* @param \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validateData = $request->validate([
'title' => 'required|string',
'body' => 'required|string',
'publish_at' => 'required|date_format:Y-m-d H:i:s'
]);
$news->title = $request->title;
$news->body= $request->body;
$news->publish_at= $request->publish_at;
$news->save();
return response()->json(['news' => $news], 201);
}
As we understand by the SRP, the main flow of a controller should be getting an input and then returning an output. However, in this code example we can clearly see that our controller method knows a lot about what’s happening in the background. It has the knowledge of
- what are the required fields
- how to validate them
- how to save things into the database
- and at the end what type of response to return
Too much responsibility for our controller. Ok, so let’s try to give one simple responsibility to our controller so it can do a better job for us.
One of the great things about Laravel is that it gives us a very nice way of organizing the validation by using FormRequest class. There is an artisan command that we can use to create one.
php artisan make:request NameOfTheFormRequest
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class NewsFormRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required|string',
'body' => 'required|string',
'publish_at' => 'required|date_format:Y-m-d H:i:s'
];
}
}
Moving away the validation
We can see here we took one responsibility out of our controller, validating the input data, and moved it into a separate method in a form of validator class. Now let’s work on separating the section so the controller doesn’t need to know about our database structure or how to handle it. For that purpose, we are going to create a repository that will handle creating our post record in the database.
namespace App\Repositories;
use App\News;
class NewsRepository
{
public function create($newsData)
{
$news = new News();
$news->title = $newsData->title;
$news->body = $newsData->body;
$news->publish_at = $newsData->publish_at;
$news->save();
return $news;
}
}
Moving away creating new record in the database
Let’s look at our controller process flow now
public function store(StoreNewsRequest $request, NewsRepository $newsRepository)
{
$news = $newsRepository->create($request);
return response()->json(['news' => $news], 201);
}
There we have it, we moved away multiple responsibilities from our store function and now it doesn’t need to know anything about required fields, how we handle validation, or creating records in the background. Now it knows that other stuff works and has single responsibility whether something changes on the client side so it can return a different output rather than how everything else is handled. With the help of the SRP we reduce blast radius and code smells of our software.
to be continued…