The View gets its own data from the Model

As I mentioned in the previous article of this series, in most frameworks the Controller sets up the View by attaching variables to it. The issue with that is it adds a responsibility to the Controller, but it also adds binding logic between the Controller and the View, which inherently leads to more bugs and makes the View more tightly coupled to the Controller. The Controller can send any data, there is nothing to stop it to send erroneous data to the View.

By letting the View get its own data from the Model, the View has a contract with the Model.
This allows to:

  • have a less error-prone View.
  • avoid any binding logic in the Controller and thus have smaller Controllers.
  • take the responsibility away for the Controller to prepare the View.

How do we achieve this?
We can assign the responsibility of fetching the model to prepare the view to another class, which I will call the View Model.
The View Model contains all the methods to fetch the needed data from the Domain Models. It can be seen as an abstraction for the View of the Domain Models.

Each Controller has its associated View Model; there is a 1:1 relationship between Controller and View Model. The application executes the requested Controller's action, and the associated View Model is passed to the View. The View fetches its own data from the View Model, avoiding any binding logic between the Controller and the View.

Consider an example where the user's profile is requested.
The Controller UserInfoController's action gets the user id from the request query string, and passes it to the View Model UserInfoViewModel.
The View gets the user details through the View Model, which fetches the user from the Domain Model.

<?php
class UserInfoController
{
    public function 
index()
    {
        
$this->viewModel->setUserId($this->request->getParam('user'));
    }
}

class 
UserInfoViewModel
{
    private 
$orm;
    private 
$id;

    public function 
__construct($orm)
    {
        
$this->orm $orm;
    }

    public function 
setUserId($id)
    {
        
$this->id $id;
    }

    public function 
getUser()
    {
        return 
$this->orm->find($this->id);
    }
}
?>

<!-- user-info.phtml -->

<label>First name</label>
<div><?= $viewModel->getUser()->getFirstName() ?></div>

<label>Last name</label>
<div><?= $viewModel->getUser()->getLastName() ?></div>

If the View now needs to display the user's address, you won't have to edit both Controller and View. You would only need to edit the View as it fetches all the data it needs itself from the Model. The Controller and the View are no longer tightly-coupled and the components can potentially be re-usable independently.

This design offers us:

  • smaller, simpler controllers
  • less error-prone views, the View has now a contract with the Model
  • a better demarcation of responsibilities (better Separation of Concerns)
  • a better OOP approach
  • code easier to maintain, test and reuse

The controller is now only responsible for updating the Model, and setting the application state.
The View Model is an abstraction of the Domain Model for the View. It provides the View with a contract for fetching data from the Domain Model.