In some situations you might want to render a ViewModel (which may or may not have childs) outside of the regular MVC flow. In my case I needed the raw html output to feed to mPDF.
Here’s a function that takes a ViewModel and renders it, including all of its childs.
public function renderViewModel($vm) {
$vm->setOption('has_parent', true);
$renderer = $this->getRendererFromVM($vm);
if ($vm->hasChildren()) {
foreach ($vm->getChildren() as $child) {
if($vm->terminate() && $child->terminate()) {
throw new DomainException('Inconsistent state; child view model is marked as terminal');
}
$child->setOption('has_parent', true);
$result = $this->renderViewModel($child);
$child->setOption('has_parent', null);
$capture = $child->captureTo();
if (!empty($capture)) {
if ($child->isAppend()) {
$oldResult=$vm->{$capture};
$vm->setVariable($capture, $oldResult . $result);
} else {
$vm->setVariable($capture, $result);
}
}
}
}
$html = $renderer->render($vm);
return $html;
}
Because ViewModel classes can have different Renderer classes we need a function to determine what Renderer class to use.
public function getRendererFromVM($vm) {
$template = $vm->getTemplate();
$ext = pathinfo($template, PATHINFO_EXTENSION);
switch($ext) {
case self::SMARTY_RENDERER_SUFFIX:
return $this->getServiceLocator()->get('Smarty\View\Renderer');
default:
return $this->getServiceLocator()->get('Zend\View\Renderer\PhpRenderer');
}
}
In my case I was using ViewModel classes with Smarty templates and one of them had a ViewModel child with a phtml layout. Based on the extension of the template file (.tpl) I decide what Renderer class to use.
Here’s an example how to use these functions from within an Action in a Controller class. Please note that this is just for demonstration; ViewModel’s should be created within models, not controllers.
private function someAction() {
//Create main ViewModel
$vm = new ViewModel();
$vm->setTemplate('path/to/some_template.tpl');
$vm->setTerminal(true);
//Create child ViewModel
$vmChild = new ViewModel();
$vmChild->setTemplate('path/to/another_template.phtml');
$vm->addChild($vmChild, 'vmChild');
//Render ViewModel including childs
$html = $this->renderViewModel($vm);
//Create a Response object
$response = new Response();
$response->setContent($html);
return $response;
}

No Comments