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.
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:
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:
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:
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.