The Action Helper merely adds a method addToStack($layout) which adds the all the layouts you want to nest into a stack.
The Plugin renders the "default" segment into the first layout on the stack and renders this into the content variable of the next layout.
When all is said and done, I replace the "default" segment of the response with this result, and let the original Plugin take control.
Here is the code for the action helper:
| namespace AB\Controller\Action; class LayoutHelper extends \Zend_Layout_Controller_Action_Helper_Layout { |
| private $_layoutStack; |
| |
| public function addToStack($layout) { |
| if (!is_array($this->_layoutStack)) { |
| $this->_layoutStack = array(); |
| $this->getLayoutInstance()->setLayout($layout); |
| } |
| else { |
| array_push($this->_layoutStack, $layout); |
| } |
| } |
| |
| public function getStack() { |
| return $this->_layoutStack; |
| } |
| } |
Here is the code for the plugin:
| namespace AB\Controller\Plugin; class NestedLayout extends \Zend_Layout_Controller_Plugin_Layout { |
| |
| public function postDispatch(\Zend_Controller_Request_Abstract $request) { |
| $layout = $this->getLayout(); |
| $helper = $this->getLayoutActionHelper(); |
| $stack = $helper->getStack(); |
| $response = $this->getResponse(); |
| |
| if (!$request->isDispatched()) return; |
| |
| $content = $response->getBody('default'); |
| |
| while (count($stack) > 0) { |
| $layout_script = array_pop($stack); |
| $layout->content = $content; |
| $content = $layout->render($layout_script); |
| } |
| |
| $response->setBody($content, 'default'); |
| |
| parent::postDispatch($request); |
| } |
| } |
I have not really tested this in production so use at you're own risk...but I the idea is there.
Now somewhere (you'll have to decide this youself), like in the init method of a controller, you can do something like this:
$this->_helper->layout->addToStack('main'); $this->_helper->layout->addToStack('sublevel');Where "main" is your main layout and "sublevel" is a layout nested within your main layout. On Mon, Apr 20, 2009 at 7:29 PM, Matthew Weier O'Phinney <matthew@zend.com> wrote:
-- Ryan Hagan <ryan@ryanhagan.net> wrote
(on Monday, 20 April 2009, 04:03 PM -0400):
> I'm trying to figure out the best way to handle slightly (veryThe easiest solution to this common problem for some reason is often
> slightly) complex views with Zend and constantly running into a road
> block. I'm hoping you guys can help guide me down the right path
> here.
>
> Basically, I have several elements that get used in different parts of
> the system in different ways. The elements are things like Twitter
> updates, blog posts, current media, etc. Each element has its own
> view script which I want to include at higher levels. For instance,
> twitter updates get displayed in different places on my index page
> than they do on my dedicated Twitter page, but the basic view is the
> same in all cases. It's the layout that is different.
overlooked here.
In your action's main view script, have it specify the alternate layout:
<?php $this->layout()->setLayout('alternate.phtml'); ?>
Zend_Layout will look for that layout script in the layout script
directory you specified when instantiating Zend_Layout. (This is just
like resolving view scripts.)
In that layout script, simply call render() or partial() to include
those view scripts that pull in the elements you need:
<?php // if no clean variable scope is necessary, render(): ?>
<?php echo $this->render('twitterfeed.phtml'); ?>
<?php // if a clean variable scope is necessary, partial(): ?>
<?php echo $this->partial('blogposts.phtml', null, array('foo' => 'bar'); ?>
You can then render the various scripts you need in the appropriate
positions in the final layout, as well as the final content.
That's really all you need to do. If you need something more complex,
consider making view helpers.
--
> Here is some pseudo-code. I'm primarily concerned with how to handle
> the view aggregation from the controller side.
>
> TwitterController extends Zend_Controller_Action
> {
> public function recentAction()
> {
> $this->view->headLink()->appendStylesheet('css/twitter.css');
> $twitter = new Zend_Service_Twitter('username','password');
> $this->view->tweets = $twitter->status->userTimeLine('me');
> }
> }
>
> recent.phtml
> <?php foreach ($this->tweets as $tweet) { ?>
> <div class="tweet">
> <p><?= $tweet->text ?></p><br/>
> <em>via <?= $tweet->source ?></em>
> </div>
> <?php } ?>
>
>
> IndexController extends Zend_Controller_Action
> {
> public function indexAction()
> {
> $this->_helper->actionStack('recent', 'twitter');
> $this->_helper->actionStack('curmonth', 'blog');
> $this->_helper->actionStack('curlistening', 'media');
> $this->_helper->actionStack('curwatching', 'media');
> $this->_helper->actionStack('curreading', 'media');
> }
> }
>
> index.phtml
> <div id="blog-col">
> <?= $this->blog ?>
> </div>
>
> <div id="whatnow-col">
> <?= $this->tweets ?>
> <?= $this->songs ?>
> <?= $this->shows ?>
> <?= $this->books ?>
> </div>
>
>
> Obviously, actionStack doesn't work like I want it to. What I would
> REALLY like, is something along these lines...
>
> IndexController extends Zend_Controller_Action
> {
> public function indexAction()
> {
> $this->view->tweets = $this->_helper->actionStack('recent', 'twitter');
> $this->view->blog = $this->_helper->actionStack('curmonth', 'blog');
> $this->view->songs =
> $this->_helper->actionStack('curlistening', 'media');
> $this->view->shows =
> $this->_helper->actionStack('curwatching', 'media');
> $this->view->books = $this->_helper->actionStack('curreading', 'media');
> }
> }
>
>
> Thank you!!
>
> --
>
> Ryan Hagan
> ryan@ryanhagan.net
>
Matthew Weier O'Phinney
Project Lead | matthew@zend.com
Zend Framework | http://framework.zend.com/
没有评论:
发表评论