问题
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