Software Engineering

ZF2: Custom view rendering (within a model)

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;
}
Previous Post Next Post

You Might Also Like

No Comments

Leave a Reply