View Models and Rendering Demystified

“View Models and Rendering Demystified” or the View Model is not your burger!

Often beginner Zend Framework 2  (ZF2) developers are confused about  view models and the whole rendering process.  In this article I will try to explain them making an analogy to ordering a burger at a restaurant. Bear in mind that I will use some terms from the ZF2 world and you may need a bit of support from books like “Learn ZF2” or the online manual to understand the explanations better.

Imagine that you went to a restaurant and ordered cheese burger. In ZF2 terms this will mean that your browser made an HTTP request to a ZF2 application and as a path in the URL it had  /order/cheeseBurger. Also you are not in a hurry and want to eat your burger at the restaurant. The HTTP request for this may look like that:

GET /order/cheeseBurger/?takeAway=0
Host: zf2burger.com

Routing Event

In a real restaurant the person at the desk will check if there is cheese burger in the menu(hopefully he knows that) and if it can be ordered. In ZF2 this means that the router checks the routing rules and tries to map your URL to a valid routing definition.

In the module.config.php file for the Restaurant module you should have something like this:

'routes' => array(
            'ordercheeseburger' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/order/cheeseBurger',
                    'defaults' => array(
                        'controller' => 'Restaurant\Controller\Order',
                        'action'     => 'cheeseBurger',
                    ),
                ),
            ),
        )

Dispatching Event

The restaurant is offering your favorite cheese burger and the person at the desk instructs the kitchen to prepare your cheese burger. In ZF2 this means that from the routing definition the application has found a controller and action that is responsible for preparing cheese burgers. The action knows what recipe (view name) to use and what ingredients( view variables ) to include in order to prepare the cheese burger.  This is where our View Model  (VM) is created. Think of the VM as a box. Outside of the box stays a label saying the recipe name(view name) to be used and inside of the box we have the ingredients( variables) to use. Every ingredient is labeled (view variable name). At that moment we still do not have the burger ready.

After the box (VM) is ready the person at the desk asks you if you want to eat in the restaurant. If you say yes he opens another box and puts your box in it. In the big box he puts a label saying: decoration. In ZF2 one VM (box ) can have multiple children ( other boxes inside of it) or be part of the content of a bigger box.

namespace Restaurant\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

class OrderController extends AbstractActionController
{	
   	public function cheeseBurgerAction() 
	{
		$viewModel = new ViewModel();
		$viewModel->setTemplate('cheeseburger-recipe');
	       	$viewModel->setVariables(array(
		          'cheese' => $gourmetFrenchCheese,
		          'meat'  => $mincedSuperbBeef,
		          'onions'=> $sweetOnion 
		));

		if($this->params('takeAway', false)) {
		           $viewModel->setTerminal(true);
		}
		
		return $viewModel;
	 }
}

One day in the kitchen came an important person who wanted to optimize the delivery time. He asked all persons working at the front desk to put all orders inside a new box and add a note with the start time when the order was accepted.  In ZF terms this can be a Debug module that adds debug overlay by creating a new view model (box ) and putting the content of the current box inside of it.

public function onBootstrap(MvcEvent $e)
{
	// Below is how we get access to the service manager
	$serviceManager = $e->getApplication()->getServiceManager();

        // ..
		
	$eventManager->attach(MvcEvent::EVENT_RENDER,
                                 array($this,'addDebugOverlay'),
                                 100);
}
    
    
public function addDebugOverlay(MvcEvent $event)
{
    	$viewModel = $event->getViewModel();
    	 
    	$sidebarView = new ViewModel();
    	$sidebarView->setTemplate('debug/layout/sidebar');
    	$sidebarView->addChild($viewModel, 'content');
    	 
    	$event->setViewModel($sidebarView);
}

(See the Learn ZF2 book repository on github)

Rendering Event

Once the person at the kitchen sees that someone ordered cheese burger he tries to apply the recipe instructions and use the ingredients that are given for that burger. He either knows the recipe or looks in cook books to find it. The books are stacked in a pile. The last book to be added is the first book to be read. When he looks in the books he uses the first recipe for cheese burger that he finds.  In ZF2 we have a resolver. The resolver tries to find from the view template name( recipe name)  the actual template file. And it can use either a template map (the cook remembers the recipe) or search for the view template name in a template path stack( multiple stacked cooking books with recipes until he finds the right one).

'view_manager' => array(
    'template_map' => array(
        'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
     ),
     'template_path_stack' => array(
          __DIR__ . '/../view',
      ),
),

One conclusion from the information above is that a fast cook is one who remembers a lot of recipes instead of looking in cooking books for them. In ZF2 application  looking for view template from a template map is much faster than trying to find the template in a template path stack. Which is important for the performance of your application especially when you have a lot of templates. ( In Learn ZF2 you will find detailed explanation in the Performance chapter)

The cook has all the ingredients and the right recipe. He starts opening the boxes until he reaches the innermost one. It contains information about your cheese burger. He cooks your juicy burger. Then he sees that there is a bigger box and he uses that information to add some salad in your plate as a decoration. In ZF2 the rendering process tries to render(cook) the innermost VM(box), and the content from the rendered VM is used in the parent VM. The decoration is stored in the layout template. The rendered content is the result from rendering the outermost VM.

Event Finish

Finally your burger is ready and served to you with a nice decoration. In ZF2 this is the moment where the rendered content is delivered to the browser.

Enjoy 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

Captcha check * Time limit is exhausted. Please reload CAPTCHA.