Change layout outside controller context

I have a controller action that triggers a Zend\EventManager\Event to which I have attached a listener that calls a service to do the heavy lifting of sending an email message. I would like to be able to set the layout, then set the rendered view ouput as the message body. There is no problem getting my multipart/alternative email together. The problem is rendering the HTML content.

It happens to be a new user registration scenario, so the AccountManager class goes

public function onRegistrationSubmitted(EventInterface $event)
{
     // do stuff
}

and in that method body I have tried things like

    $controller = $event->getTarget();
    $controller->layout()->setTemplate(
            'my/email/layout.phtml'
     );

followed by

$view = new ViewModel();
$view->setTemplate('my/email/view_script.phtml');
$html = $this->viewRenderer->render($view);
 // P.S:  $this->viewRenderer comes from the service manager,
// and is injected by our factory

but the result is the layout, fine, but the nested $this->content is null.

Then I tried creating my own layout and child, as it were, by doing

$layout = (new ViewModel())->setTemplate( 'my/email/layout.phtml');
$child   = (new ViewModel())->setTemplate( 'my/email/view_script.phtml');
$layout->addChild($child,'content');

but when we look at $html = $this->viewRenderer->render($layout) it’s the same story: no nested content, just layout. Conversely, if I do $html = $this->viewRenderer->render($child) then I get the $child without the surrounding layout (which is what I’d expect, but hey, I am trying to leave no stone unturned).

I know of at least one way to work around this: do without the layout, just have a flat viewscript. But I am stubborn.

Any thoughts?

you should can set content as variable from $controller->layout():

$controller->layout()->setVariable(
    'content',
    $this->viewRenderer->render('my/email/view_script.phtml');  
);
1 Like

Yay! That works. Thank you.

Just wondering David, why do you prefer the email sending to be an MVC event, rather than just a service that the controller calls?

Fair question, one I too have asked mysell. No compelling reason not to call the service directly. I kind of thought it might somehow be cleaner for the controller simply to broadcast the event and be done. But maybe the opposite is the case, for someone else reading the code in the future. I’m somewhat under the influence of a book about ZF2 that I read a couple years ago. It had examples that used the event-based approach.

Perhaps I’ll change it. Fortunately, that wouldn’t be difficult to do.

UPDATE: upon further reflection I probably will change this to have the controller use the service directly. Why? Because there’s a related action that logically belongs in the same controller, and that needs the service, and for which it makes sense just to use it – the event-based way would be a pointless affectation! So I will end up injecting this service thing into the controller anyway.

One reason for triggering the event was that I could pass $this as the event target, thus giving the listener access to the pluginManager, which it needs, e.g., for changing the layout. I will probably end up injecting that stuff into the service instead.

Whatever you do, it gets a little complicated sometimes. Am I right?

OK I’ll stop jabbering now. I really should lay off the crystal meth.