Quick introduction to using Zend_Layout

Tags:

Lately, the Zend_Layout component has been a very popular topic on #zftalk. It is indeed a very useful component, but a lot of people are having trouble understanding how it works.

Adding to the confusion is the outdated documentation regarding the component proposal and the equally outdated articles about Zend/Xend_Layout.

Let’s demonstrate the usage of the current Zend_Layout implementation, which can be found from the Zend Framework SVN or Snapshots in the Incubator directory.

Note: if you are using the Zend_Layout from 1.0.3, the stuff mentioned here will still work.

Zend Framework 1.5 users: there is an updated version of this article available here

Getting started with Zend_Layout

First, you need to grab the library and incubator/library directory from the latest snapshot. You can either copy the files from this directory to the main library directory of the snapshot, or create an another directory in your library dir, such as Zend-Incubator.

You can find the latest snapshot at Zend Framework Nightly Snapshots.

If you do create the Zend-Incubator directory in addition to the default Zend directory, remember to add it to your include path!

The next step is to initialize the layout. Put this code in your boostrap, before you dispatch the request:

$layout = new Zend_Layout(array(
                      'layoutPath' => './application/layouts',
                      'layout' => 'default'
                      ));
 
$view = $layout->getView();
$view->addHelperPath('./library/Zend/View/Helper');

Note for Zend Framework 1.0.3 users: the layout constructor needs a parameter to enable MVC support, so use this instead of the above:

$layout = new Zend_Layout(array(
                      'layoutPath' => './application/layouts',
                      'layout' => 'default'
                      ), true);

First we create a new Zend_Layout instance. The parameters define where the layout files will be found and what is the name of the default layout. So create a directory under your application called “layouts” if you’re using that as your layoutPath.

Next we grab the view script from the layout. This allows us to add variables and change the view’s settings. We add a new helper path to the view, which allows us to use the new view helpers which came with Zend_Layout. If you’re using the Zend-Incubator dir, remember to add that as a helper path as well.

Now you have Zend_Layout configured. Create an empty layout file called default.phtml to application/layouts or your layout dir.

Adding things to the layout

Layouts work quite much like your normal view scripts. A lot of the extra features depend on the new view helpers.

Let’s first look at a basic layout file:

<html>
  <head></head>
  <body>
 
    <div>
      The site's menu is here: home | links | stuff
    </div>
 
    <div>
      <?php echo $this->placeholder('Zend_Layout')->content; ?>
    </div>
 
  </body>
</html>

The key here is the placeholder viewhelper. It acts kind of a like a registry, and you can access the Zend_Layout object through it. So we are basically accessing the variable content from the layout instance.

By default, all content that is not rendered in a specific response segment goes into the content variable in the layout, so if you’re letting the viewrenderer render a view script in your controller actions, the content of the rendered view script will be available in the content variable.

We can also expand on this:

<html>
  <head></head>
  <body>
 
    <div>
      The site's menu is here: home | links | stuff
    </div>
 
    <div>
      <?php echo $this->placeholder('Zend_Layout')->content; ?>
    </div>
 
    <div>
      <?php echo $this->placeholder('Zend_Layout')->sidebar; ?>
    </div>
 
  </body>
</html>

Now we have a sidebar placeholder. How do we put any content in it?

We can either have some action render a view into a response segment with the same name, or we can use the layout action helper.

class ExampleController extends Zend_Controller_Action
{
  public function exampleAction()
  {
    $this->_helper->layout()->sidebar = 'This goes into the sidebar variable in the layout!';
  }
 
  public function anotherAction()
  {
    $this->render('sidebar', 'sidebar', true);
 
    //Render the action's own script
    $this->render('another','default');
  }
}

So using the layout with exampleAction would put the text string into the sidebar and the anotherAction would render the contents of the sidebar.phtml script to it.

More helpers

There are also some other helpers for your layouting and viewing pleasure.

The action helper

Some of you may have heard about subrequests. Well, this is what the subrequest turned into: The action view helper.

This can be used in your layouts and views to output content from other controllers.

<div>
  <?php echo $this->action('menu', 'actions', 'default', array('activeLink' => 'Home')); ?>
</div>

This would call the menuAction in ActionsController in the default module and pass a parameter called activeLink to it.

The partial and partialLoop helpers

Partial is similar to using render to include other views.

<div>
  <?php echo $this->partial('profile', null, array('name' => 'Peter')); ?>
</div>

This would include partial “profile.phtml” from the default module with parameter name. Note that unlike when using render(), partials will not inherit the parent view’s variables! This is why you may need to pass them in an array like in the above example.

PartialLoop is like partial, but it will act like a loop:

<table>
  <?php echo $this->partialLoop('table-row', null, array(
                          array('col1' => 'value1', 'col2' => 'value2'),
                          array('col1' => 'value3', 'col2' => 'value4'),
                          array('col1' => 'value5', 'col2' => 'value6')
                         )); ?>
</table>

The above would call the imaginary table-row partial three times with each sub-array as parameter. Note that the parameters don’t have to be hand-written like this, you could use database-rows or other things too.

The headScript, headTitle and others

HeadScript, HeadTitle, HeadStyle, HeadLink and HeadMeta can be used as placeholders in your layouts. For example, your layout can contain the following:

<html>
  <head>
    <?php echo $this->headTitle('My site'); ?>
  </head>
  <body>
    <?php echo $this->placeholder('Zend_Layout')->content; ?>
  </body>
</html>

The headtitle helper will output a title element with the text ‘My site’ in it.

Now, say we want to modify the title in one of our pages. Let’s make a view script for the page:

<?php $this->headTitle()->append(' Example page'); ?>
 
This page changes the title and adds a javascript file.

This would append Example page to the title.

The other Head* helpers work in a similar manner.

As of writing this, HeadScript helper is broken and unusable.

Conclusion

Even though it’s not finished yet (HeadScript…), the Zend_Layout component provides an easy and powerful complex view solution.

Let’s hope they get it quickly finished so we can start using HeadScript and others too.

There are some things to think of, though. For example, what would be the best way to use the sidebar-thing I showed? Should you wire up a dedicated Action helper call? Should you leave that to your controllers? I’d be interested to hear your ideas and how you’ve implemented things like that.