Controllers are taking SRP seriously

In a lot of popular MVC frameworks, each controller action has its own view. If you have learned an MVC framework before, the code below should seem familiar to you:

<?php
class UserController
{
    public function 
add()
    {
        
// some code
    
}

    public function 
edit($id)
    {
        
// some code
    
}

    public function 
delete()
    {
        
// some code
    
}

    public function list()
    {
        
// some code
    
}

    public function 
info($id)
    {
        
// some code
    
}

    
// some more actions
}
?>

The controller above has multiple responsibilities: adding, editing, deleting and listing users.

The Single Responsibility Principle states that if we have 2 reasons to change for a class, we have to split the functionality in two classes. Each class will handle only one responsibility and on future, if we need to make one change, we are going to make it in the class which handles it. When we need to make a change in a class having more responsibilities, the change might affect the other functionality of the classes.

The controller is, in addition to the responsibilities outlined above, also responsible to prepare the view by attaching variables to it, violating SRP once more.
Another drawback is that the dependencies you need to inject for one particular action will intrinsically be injected for any other action call.

Making the Controller and the View a 1:1 relationship

For better decoupling and reuse, we could break these controller actions into multiple controller classes.

<?php
class UserAddController
{
    public function 
add()
    {
        
// some code
    
}
}

class 
UserEditController
{
    public function 
edit($id)
    {
        
// some code
    
}
}

// ...
?>

By doing so, our controllers are thinner, simpler, modular and more robust as they now have only one reason to change.

The controller has still the superfluous responsibility of binding variables to the view.

The original MVC pattern states that the application informs the View to refresh from the Model through the Observer pattern. The part that notifies the View could be either the Controller or the Model. It clearly states that the View gets its own data from the Model. However, popular frameworks refresh the View by binding variables to it from the Controller. This consequently makes views more prone to errors as there is no more contract between the View and the Model; the Controller could send any erroneous data to the View. This common mistake is done because the Observer pattern is for traditional rich-client MVC applications. It doesn't really make sense in a web application, as there is no way for the Model to notify the View unless the Model and View are running continuously and concurrently.
In the next article of this series (The View gets its own data from the Model), an alternative approach is introduced to dispose of the binding logic between Controller and View, and instead get the View read its own data from the Model.