Skip navigation

Sign up | Lost password? | Help

Hello World

Practical programming... and stuff...

Using layouts with Zend ViewRenderer helper

,

Note: this post is very outdated. Unless you're into archeology, I suggest using Zend_Layout.

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.

Building a CMS with the Zend FrameworkOpera has tab jumpback!

Comments

zomg 10. November 2007, 10:55

Well, of course I forgot to mention that the name of the view script you want to render (not the layout's) goes into the template variable LAYOUT_CONTENT, so use that to include/render the content.

Anonymous 12. November 2007, 21:14

NinSky writes:

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

I think its best to do it in the bootstrap. You see, if you did it in init for controllers, you might have to put the same code in more than one place. What if you wanted to stop using the layout renderer? You'd have to go through all your controllers to remove the code.

Anyways, I'm glad you found this useful.

Anonymous 21. November 2007, 12:00

Anonymous writes:

How the variable 'LAYOUT_CONTENT' should be placed in the layout template?

zomg 21. November 2007, 15:51

<?php echo $this->render($this->LAYOUT_CONTENT); ?>

zomg 28. November 2007, 08:59

If you are reading this post now, you may also want to check out the Zend_Layout component which is almost finished now.

Read up my quick introduction to Zend_Layout for more details :smile:

Anonymous 13. December 2007, 14:00

Patrick writes:

It was exactly what I was looking for

Thanks.

Anonymous 17. October 2008, 07:40

Neo Developer writes:

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

Anonymous writes:

:yikes: :yikes:

zomg 21. October 2008, 07:41

This is very outdated. I highly recommend just using Zend_Layout which does this task very well.

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies