1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
<?php
namespace Rain\Tpl;
/**
* Maintains template plugins and call hook methods.
*/
class PluginContainer
{
/**
* Hook callables sorted by hook name.
*
* @var array
*/
private $hooks = array();
/**
* Registered plugin instances sorted by name.
*
* @var array
*/
private $plugins = array();
/**
* Safe method that will not override plugin of same name.
* Instead an exception is thrown.
*
* @param string $name
* @param IPlugin $plugin
* @throws \InvalidArgumentException Plugin of same name already exists in container.
* @return PluginContainer
*/
public function addPlugin($name, IPlugin $plugin) {
if (isset($this->plugins[(string) $name])) {
throw new \InvalidArgumentException('Plugin named "' . $name . '" already exists in container');
}
return $this->setPlugin($name, $plugin);
}
/**
* Sets plugin by name. Plugin of same name is replaced when exists.
*
* @param string $name
* @param IPlugin $plugin
* @return PluginContainer
*/
public function setPlugin($name, IPlugin $plugin) {
$this->removePlugin($name);
$this->plugins[(string) $name] = $plugin;
foreach ((array) $plugin->declareHooks() as $hook => $method) {
if (is_int($hook)) {
// numerical key, method has same name as hook
$hook = $method;
}
$callable = array($plugin, $method);
if (!is_callable($callable)) {
throw new \InvalidArgumentException(sprintf(
'Wrong callcable suplied by %s for "%s" hook ',
get_class($plugin), $hook
));
}
$this->hooks[$hook][] = $callable;
}
return $this;
}
public function removePlugin($name) {
$name = (string) $name;
if (!isset($this->plugins[$name])) {
return;
}
$plugin = $this->plugins[$name];
unset($this->plugins[$name]);
// remove all registered callables
foreach ($this->hooks as $hook => &$callables) {
foreach ($callables as $i => $callable) {
if ($callable[0] === $plugin) {
unset($callables[$i]);
}
}
}
return $this;
}
/**
* Passes the context object to registered plugins.
*
* @param string $hook_name
* @param \ArrayAccess $context
* @return PluginContainer
*/
public function run($hook_name, \ArrayAccess $context ){
if (!isset($this->hooks[$hook_name])) {
return $this;
}
$context['_hook_name'] = $hook_name;
foreach( $this->hooks[$hook_name] as $callable ){
call_user_func($callable, $context);
}
return $this;
}
/**
* Retuns context object that will be passed to plugins.
*
* @param array $params
* @return \ArrayObject
*/
public function createContext($params = array())
{
return new \ArrayObject((array) $params, \ArrayObject::ARRAY_AS_PROPS);
}
}
|