Using layouts with Zend ViewRenderer helper
Friday, 14. September 2007, 07:31:40
When working with views in the Zend Framework, you normally have a view for each action in your controllers. Each of the views run a view script, which then include header and footer views in them. This may lead to some repetitive code and may cause a problem if you want to modify the way the header and footer are included in your views.
A better approach could be to use a "layout". A layour is a master view, perhaps similar to the master page in ASP.NET - it has the header, footer and all other code except the content. It effectively replaces the header and footer and is used to include the content (the action view script) inside itself instead of the action view script including the header and footer.
By default, ZF doesn't support this very well: You would need to manually set the view in every action to the layout script and set a variable in that to point to the action view script.
However, we can easily change this behavior. As you may know, the ViewRenderer helper automatically renders the action's own view. If we modify the ViewRenderer, we won't have to do anything at all - just like when not using layouts.
Making a custom ViewRenderer
We can simply extends the Zend_Controller_Action_Helper_ViewRenderer class to change its behavior to use layouts.
We need to override the renderScript method so, that instead of rendering the action's script, it renders the layout and assigns the name of the action script to the view so that the layout can use it to include the action's script.
I'll call my ViewRenderer simply ViewRenderer_Layout. Like this:
<?php
require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';
class ViewRenderer_Layout extends Zend_Controller_Action_Helper_ViewRenderer
{
public function renderScript($script,$name=null)
{
if($name===null)
$name = $this->getResponseSegment();
//Name of the action script is assigned to LAYOUT_CONTENT
$this->view->assign('LAYOUT_CONTENT',$script);
$this->getResponse()->appendBody(
$this->view->render('layout.phtml'),
$name
);
$this->setNoRender();
}
public function getName()
{
return 'ViewRenderer';
}
}
?>
So that's quite simple. We also override the getName function so that it correctly returns the class' name as "ViewRenderer" which is needed so that it properly replaces the old ViewRenderer when assigned to the HelperBroker.
Using our custom renderer
To use this instead of the default one, we simply replace the ViewRenderer in the HelperBroker with our shiny new one:
$viewHelper = new ViewRenderer_Layout(); Zend_Controller_Action_HelperBroker::addHelper($viewHelper);
If you're using the default view paths, you need to put your layout.phtml file to application/views/scripts/layout.phtml. With this done, you should have a working layout ViewRenderer.
A small improvement
You might want to use a different layout on some pages, so let's add the option of changing the name of the layout file to the class.
<?php
require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';
class ViewRenderer_Layout extends Zend_Controller_Action_Helper_ViewRenderer
{
protected $_layoutFileName = 'layout.phtml';
public function setLayoutFileName($name)
{
$this->_layoutFileName = $name;
}
public function renderScript($script,$name=null)
{
if($name===null)
$name = $this->getResponseSegment();
$this->view->assign('LAYOUT_CONTENT',$script);
$this->getResponse()->appendBody(
$this->view->render($this->_layoutFileName),
$name
);
$this->setNoRender();
}
public function getName()
{
return 'ViewRenderer';
}
}
?>
So we add a variable which shall store the name of our layout and a method for setting it. You may also want to define a method for getting it, but I'll leave that up to you. We use the _layoutFileName variable in the render method's parameters instead of the hardcoded value and that's it.
Note that if you change the viewBasePathSpec to something like application/views/:module like I do in one of my projects, the layout.phtml file will be automatically loaded from application/views/modulename/scripts/layout.phtml, so you can define a different layout based on the module even without using the method for changing it.
So there we have it. I hope you find it useful, I sure do.








zomg # 10. November 2007, 10:55
Anonymous # 12. November 2007, 21:14
Very helpful. Thanks for that script!
I've put the lines
"$viewHelper = new ViewRenderer_Layout();
Zend_Controller_Action_HelperBroker::addHelper($viewHelper);"
into the bootstrapper. Is that a good place to load the new ViewRenderer or should these 2 lines better be placed within the init-method of each controller-skript to avoid overhead?
zomg # 13. November 2007, 14:23
Anyways, I'm glad you found this useful.
Anonymous # 21. November 2007, 12:00
How the variable 'LAYOUT_CONTENT' should be placed in the layout template?
zomg # 21. November 2007, 15:51
zomg # 28. November 2007, 08:59
Read up my quick introduction to Zend_Layout for more details
Anonymous # 13. December 2007, 14:00
It was exactly what I was looking for
Thanks.
Anonymous # 17. October 2008, 07:40
Hi,
this is a great tutorial...
I did everything as directed above.
But i get this error:
Fatal error: Using $this when not in object context in C:\xampp\htdocs\zendproj\application\views\scripts\layout.phtml on line 3
why does this happen?
Anonymous # 21. October 2008, 07:30
:yikes: :yikes:
zomg # 21. October 2008, 07:41