My project has a core bundle which holds the main templates, and I have optional features implemented as bundles. Different clients get copies of the project with different bundles(=features) activated.
One thing that the feature bundles need to be able to do is add things to the main templates (in the core bundle). Obviously I don't want the templates in the core bundle to "know" about the optional bundles, so I want to have "hooks" in the templates that other bundles can pour content into.
I have one solution, which seems to work. I would appreciate feedback/suggestions.
I have a twig function which gets a "hook" name. I place that function at different locations in my template.
That function raises an event (through the event dispatcher) that collects html snippets from various event listeners (the feature bundles are responsible for those listeners), joins those snippets and returns them.
code:
twig function:
new \Twig_SimpleFunction('template_hook', array( $this, 'templateHookFunction' ), array('is_safe' => array('html'))),
public function templateHookFunction($hookName)
{
$hookData = $this->eventDispatcher->dispatch(
TemplateHookEvent::TEMPLATE_HOOK,
new TemplateHookEvent($hookName)
)->getData();
return $this->hookDataRenderer->render($hookData);
}
the event:
<?php
namespace CRM\TwigBundle\Event;
use CRM\TwigBundle\Hook\HookData;
use Symfony\Component\EventDispatcher\Event;
class TemplateHookEvent extends Event
{
const TEMPLATE_HOOK = 'crm_twig.template_hook';
private $hookName;
/** @var HookData $data */
private $data;
function __construct($hookName)
{
$this->hookName = $hookName;
$this->data = new HookData();
}
/**
* @return mixed
*/
public function getHookName()
{
return $this->hookName;
}
/**
* @return HookData
*/
public function getData()
{
return $this->data;
}
/**
* @param HookData $data
*/
public function setData(HookData $data)
{
$this->data = $data;
}
public function addData($label, $html, $overwrite = true)
{
if ($overwrite || !isset($this->data[$label])) {
$this->data[$label] = $html;
} else {
$this->data[$label] .= $html;
}
}
}
an example for a listener:
<?php
namespace CRM\ComputersBundle\EventListener;
use CRM\TwigBundle\Event\TemplateHookEvent;
class TemplateHookListener {
public function onTemplateHook(TemplateHookEvent $event)
{
$event->addData('computersBundle', '<li>CAKE</li>');
}
}
HookData is just a wrapper for an array (for now), each listener can push to it its own snippet.
and the HookDataRenderer just joins(implode) the array, and returns the result.