3
votes

I have a layout with 4 separate "chunks". They are:

  • A nav panel with a menu and breadcrumbs. This is constructed using Zend_Navigation.
  • A sidebar, which shows general "news" by default
  • A content area, where the main output from each controller action would be placed
  • A header area, which is the above the navigation, which normally displays just some stock text and a photo.

The content area fits in with the traditional single view model that the documentation for Zend_Application states, but the other three do not. They all have reasonable default views to use, but a controller needs to be able to override them if needed. For example, it makes sense for an administration page to override the "newsy" view to display a log of recent administrative actions taken on the system.

The Zend_Layout/Zend_Application examples, however, all assume a single view (they call <?php echo $this->layout()->content; ?>.

How can one accomplish this kind of overriding of the layout? The only solution I've thought of would be to store overridden Zend_Views inside Zend_Registry, but that seems like holding things together with duct tape ;)

2

2 Answers

4
votes

I believe what you are referring to are called "Named segments". Zend Framework's response object has support for these so called "named segments", and will allows you to segregate body content into different segments.

For example take the following layout file:

<div id="nav">
    <?php echo $this->layout()->nav ?>
</div>
<div id="content">
    <?php echo $this->layout()->content ?>
</div>

Here you have 2 named segments, being "content" and "nav". By default, output from your view scripts will be rendered to the "content" segment. In order to render output to the "nav" segment, you could do the following in a controller:

<?php

$response = $this->getResponse();
$response->insert('nav', $view->render('nav.phtml'));

?>

This feature gets particularly useful when used in conjunction with the ActionStack action helper. Take for instance that you are at an administration page, and you would like to override the "nav" section, then you could determine per controller which part you want render to that segment. The best way to explain this would be by a code example:

<?php

class PageController extends Zend_Controller_Action
{
    public function barAction()
    {
        // this would render the output of NavController::menuAction()
        // to the "nav" segment (note how we set the response segment in the
        // NavController in order to do this)
        $this->_helper->actionStack('menu', 'nav');
    }
}

class NavController extends Zend_Controller_Action
{
    public function menuAction()
    {
        $this->_helper->viewRenderer->setResponseSegment('nav'); 
        // do stuff
    }
}

?>
3
votes

Normally you would have a layout which contains your header area, nav panel, content area and sidebar. The content area would be loaded using the $this->layout()->content snippet you included, the other chunks could either be called in the main layout or included via. partials. If you go with the latter approach, your layout file might look something like this:

<html>
<head>
<title><?=$this->headTitle()?></title>
</head>

<body>

<?=$this->render('_header.phtml')?>

<?=$this->render('_navigation.phtml')?>

<?=$this->render('_sidebar.phtml')?>

<?=$this->layout()->content?>

</body>
</html>

If you find your partials are including more PHP code than HTML, you might consider writing a helper instead. So you might create a sidebar helper along these lines:

<?php
class My_View_Helper_Sidebar extends Zend_view_Helper_Abstract
{
    public function sidebar()
    {
        $html = '';

        // code to generate side bar here

        return $html;
    }
}
?>

and then instead of rendering a partial as I did above, you would call your sidebar helper:

<?=$this->sidebar()?>

It's fairly easy for controllers to override layouts, so you might create an admin layout that looks like my example above but without the sidebar, and perhaps with a different header. You'd then get your admin controller to use this instead of the default.

I can think of few situations where you would need to configure multiple Zend_View objects, which you implied you were considering.