Zend Framework 2 - Wrapping $this->content with another layout

*爱你&永不变心* 提交于 2019-12-11 11:18:28

问题


I am trying to create a wrapper for the $this->content of a specific Module.

What I have is a main layout (All the modules will follow this layout) which builds the base layout with headers and footers, etc. These will stay the same across all the Modules.

However I want to have modules with a custom layout for their body content. I.e. for custom nav bars, etc.

So with the following structure:

module
  / ModuleName
    / view
      / layout
        / modulelayout.phtml
      / modulename
        / index
          / index.phtml
view
  / layout
    / layout.phtml

The /view/layout/layout.phtml:

<?= $this->doctype(); ?>
<html lang="en">
    <head>
      ...
    </head>
    <body>
        <header>...</header>

        <div id='body'>
            <?= $this->content; ?>
        </div>

           <footer>...</footer>
    </body>
</html>

The /module/ModuleName/view/layout/modulelayout.phtml:

<div>...</div>

<div>
    <?= $this->content; ?>
</div>

The /module/ModuleName/view/modulename/index/index.phtml:

Hello World
...

So I want all of the actions inside of ModuleName (their $this->content that is displayed), to be wrapped with the layout from modulelayout.phtml.

I created a listener on the dispatch event of a controller to capture it for all controller actions:

public function onBootstrap($e) {
    $app = $e->getApplication();
    $app->getEventManager()
        ->getSharedManager()
            ->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', array($this, 'dispatchControllerStrategy'));
}

Now I need to know how to I retain the base layout, and add my module layout as a wrapper?

public function dispatchControllerStrategy($e) {
    $controller = $e->getTarget();

    $layout = $controller->layout();

    $wrapper = new ViewModel();
    $wrapper->setTemplate('layout/modulelayout');

    $layout->addChild($wrapper, 'content');
}

^^^ The adding of the child layout does not seem to wrap $this->content in any way, and the child layout does not render. To bring it all together, this is what I expect the final source to look like:

<!DOCTYPE html>
<html lang="en">
    <head>
      ...
    </head>
    <body>
        <header>...</header>

        <div id='body'>
            <div>...</div>

            <div>
              Hello World
              ...
            </div>
        </div>

           <footer>...</footer>
    </body>
</html>

Thanks!


回答1:


Well after a lot of messing around I finally found my solution. And it appears that comment of SlmThreeStepView user2257808 was what I wanted to begin with, but my solution fit my need exactly so I am just going to share it here:

I stopped worrying about trying to modify the layout on controller dispatch and focused on the View with the EVENT_RENDERER_POST event:

->attach('Zend\View\View', \Zend\View\ViewEvent::EVENT_RENDERER_POST, array($this, 'renderViewStrategy'));

I then modify my model on render:

private $renderdedOuterView = false;
public function renderViewStrategy($e) {
    if ($this->renderdedOuterView) {
        return;
    } else {
        $this->renderdedOuterView = true;
    }

    $layout = $e->getModel();

    $children = $layout->getChildren();
    $layout->clearChildren();

    $wrapper = new ViewModel();
    $wrapper->setTemplate('layout/modulelayout');
    $wrapper->addChild($children[0], 'content');

    $layout->addChild($wrapper, 'content');
}

I used $renderedOuterView to only do any render modification for the main layout.

Then for the main layout, I get the Model, and grab the attached child which would be the layout for the current action.

I then clear the main template of that child and add my wrapper in its place. Then as a child of my wrapper, I add the layout for the current action I had just removed from the main template.

My not be the best option, but this solution fits exactly what I was trying to accomplish with my question.

UPDATE

I wanted to add that I found out another issue. All the onBootstraps for each Module get called, regardless if they are the active module.

This was causing a different module to get this layout. The change was adding an EVENT_DISPATCH first:

$evtMgr = $e->getApplication()->getEventManager();
$evtMgr->attach(MvcEvent::EVENT_DISPATCH, array($this, 'handleEventStrategy'));

Then inside of the handleEventStrategy, I check to make sure that the active Module is the module's bootstrap that is being called. If it is, then I attach the EVENT_RENDER_POST and use the renderViewStrategy that I had defined.

If the active module is not the module with the render view strategy, the if condition will fail and no other module will get that modified layout.




回答2:


Did you try this module: https://github.com/EvanDotPro/EdpModuleLayouts

And then add the config in your module config file

array(
    'module_layouts' => array(
        'ModuleName' => 'layout/some-layout',
    ),
);


来源:https://stackoverflow.com/questions/18003563/zend-framework-2-wrapping-this-content-with-another-layout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!