ZF-6537: Disabling Zend_Layout does not work correctly when ActionStack used.

Description

This is partly a Zend_Layout issue and partly a problem with ViewRenderer helper, I think.

Suppose one is using Zend_Layout with the ActionStack, as recommended in the docs, and the stack is set up at dispatchLoopStartup (which seems like the right place for it). Content from these actions is assigned to response segments using $this->_helper->viewRenderer->setResponseSegment('someSegment'), in order that it can be rendered in the correct place by Zend_Layout.

I want to disable the layout in one of my actions; however, when I do so (using $this->getHelper('layout')->disableLayout()) , any actions previously called by the ActionStack are then appended to the body - there are no layout placeholders (as layout is disabled), and so these items are simply tagged on to the main body. This is not, I believe, appropriate behaviour.

Psuedo-code may clarify:


  function dispatchLoopStartup
  {
            $actionStack = $front->getPlugin('Zend_Controller_Plugin_ActionStack');
            $menuAction = clone($request);
            $menuAction->setActionName('menu')
                    ->setControllerName('my_controller');
            $actionStack->pushStack($menuAction);
  }

  function menuAction
  {
     // stuff ...
     // menu viewscript renders like 
menu item 1, menu item 2
$this->_helper->viewRenderer->setResponseSegment('menu'); } function withLayoutAction { // stuff ... // withLayout viewscript renders like
some with-layout text
} function noLayoutAction { $this->getHelper('layout')->disableLayout(); // stuff // noLayout viewscript renders like
Some no-layout stuff here
}

Menu

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

Main Content

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

If I go to my_controller/withLayout, I get the menu and withLayout div rendered at the layout placeholders as you'd expect, no problem. If I go to my_controller/noLayout, I the full output is:

Some no-layout stuff here
menu item 1, menu item 2

The content from menuAction is simply appended to the content from noLayoutAction, which is exactly not what I want!

One workaround is rather than disable the layout, to use a layout template with only the 'content' placeholder:


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

and then, rather than disabling the layout, change layout script in the controller action


function noLayoutAction
{
  $this->getHelper('layout')->setLayout('no-layout');
} 

This implies to me that a possible fix would be to never actually disable Zend_Layout, but instead force it to use a basic layout template as above; to rewrite disableLayout:


public function disableLayout()
{
  $this->setLayout('no-layout');
  $this->_enabled = false;
  return($this);
}

Comments

Markup edit for readability.

Assigning to Ralph

Yeah, good one. This is because the response object sticks all its body segments together when outputed, and the layout , when activated pulls them from the response. When the layout is disabled, the segment is not pulled out from the response object, so it gets rendered.

A quick patch could be (Plugin/Layout)


if (!$layout->isEnabled()) {
            if (Zend_Controller_Front::getInstance()->getParam('noViewRenderer') == false && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {
                return;
            }
            $segment = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer')->getResponseSegment();
            if ($segment != null) {
                $response = $this->getResponse();
                $response->setBody('', $segment);
            }
            return;
        }

Bulk change of all issues last updated before 1st January 2010 as "Won't Fix".

Feel free to re-open and provide a patch if you want to fix this issue.