Fun with the ViewRenderer

by Naneau

The ViewRenderer

Really, there is fun to be had! Since it’s introduction, the ViewRenderer had caused headaches and frustration. It is the one thing that glues the Controller and View parts of Zend’s MVC implementation together. As such, it ties in strongly with your code and is likely to cause confusion if you don’t know what it does.

Retrieving the helper

The ViewRenderer is an action helper. This means that it is stored in the helper broker. You can retrieve it anywhere in your code with:

1
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');

There is one small catch. If you retrieve it before dispatch, the view object it contains has not been initialized. You can do that yourself by calling initView() on the object:

1
2
3
4
5
6
7
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer');
$viewRenderer->initView();
//retrieve the helper and initialize the view

$viewRenderer->view->someVar = 'someValue';
//set a variable in the view
//this will be available in all your view scripts

The view object contained in the helper is the only view object your application will work with. Any variable you assign to it will be available in all the view scripts you render. If you want to modify the view script, for instance if you want to pass extra configuration options, you can do it like this:

1
2
3
4
$view = new Zend_View(array('encoding' => 'utf-8'));
//a view object with the encoding option set to utf-8
$viewRenderer->setView($view);
//set the object in the viewRenderer

In this example, all I do is set up a configuration setting. As is made clear in the comments for this post, this could also be done with:

1
$viewRenderer->view->setEncoding(’utf-8′);

If you want to use a custom view object, like one with Smarty rendering, you do need to set up the property yourself.

Setting up your view scripts

Unless you disable it, the ViewRenderer action helper will try to render a view for every action that gets called. I am sure that by now you know that for a controller FruitController, with an action appleAction() you need to create a view file “/views/scripts/fruit/apple.phtml”. View scripts are stored in the “views” directory of your module. If you use a directory layout without modules (i.e. you only have a single non-namespaced module “default”) you should have it in the same directory as you “controllers” directory.

You can immediately see the problem here. If you don’t follow the convention for naming your view scripts you get an exception like:

1
script 'index/index.phtml' not found in path (/your/path/to/view/scripts/)

The assumption that every action will have a view may be false for you. Luckily, the helper is smart enough to not try to render a view when you do _forward() and _redirect(). If you render a view manually (using $this->render()) it won’t try to find the default view either. If that is not enough for you, you can disable the view rendering for a specific action with:

1
2
$this->_helper->viewRenderer->setNoRender();
//disable the view rendering for an action

Advanced ViewRenderer magic

When you start writing view helpers you’ll probably put them in the “helpers” subdirectory of your “views” directory. This is fine, but it will start causing problems as soon as you want to use the same helper in other modules. To get around this you could put the helpers in your library and add the containing directory like this:

1
2
3
4
5
6
$viewRenderer->view->addHelperPath(
'Naneau/View/Helper/',
//the path to the helpers
'Naneau_View_Helper'
//the class prefix
);

As you can see, the addHelperPath function of Zend_View expects two arguments, one is the path to where your helpers are located. The second is the prefix for the helpers. I use “Naneau” as my namespace, so my helpers start with Naneau_View_Helper.

Another thing that people regularly ask is how to put the content the helper renders into a sidewide layout file. There are several solutions for this. The most interesting at the moment is called Xend_Layout. It will, in modified form, be included in the 1.1 release of the framework as Zend_Layout. SpotSec has written a nice article about it, which I suggest you read ;) . Just remember that even advanced solutions like Xend_Layout use the ViewRenderer. Also, please note that Xend_Layout is currently a proposal, and is likely to undergo significant changes before it moves to Zend_Layout.