getRegistry()->add($key, $value); return $this; } /** * Get the current registry object * * @return Params * @throws Exception */ public function getRegistry(): Params { if (!(self::$_registry instanceof Params)) { self::$_registry = new Params(is_array(self::$_registry) ? self::$_registry : []); } return self::$_registry; } /** * Set the components used throughout the application lifecyle. * * Each component config array needs to have a `class` key containing a class name that can be autoloaded. * For example, adding a cache component would be done like : * *
     * $components = array(
     *     'cache'=>array(
     *         'class'             => \EmsApi\Cache\Sqlite::class,
     *         'connectionString'  => 'sqlite:/absolute/path/to/your/sqlite.db',
     *     ),
     * );
     * $context->setComponents($components);
     * 
* * Please note, if a named component exists, and you assign one with the same name, * it will get overriden by the second one. * * @param array $components * * @return Base * @throws Exception */ public function setComponents(array $components): self { /** * @var string $componentName * @var array $config */ foreach ($components as $componentName => $config) { $this->setComponent($componentName, $config); } return $this; } /** * Set a single component used throughout the application lifecyle. * * The component config array needs to have a `class` key containing a class name that can be autoloaded. * For example, adding a cache component would be done like : * *
     * $context->setComponent('cache', array(
     *    'class'             => \EmsApi\Cache\Sqlite::class,
     *    'connectionString'  => 'sqlite:/absolute/path/to/your/sqlite.db',
     * ));
     * 
* * Please note, if a named component exists, and you assign one with the same name, * it will get overriden by the second one. * * @param string $componentName the name of the component accessed later via $context->componentName * @param array $config the component configuration array * * @return Base * @throws ReflectionException * @throws Exception */ public function setComponent($componentName, array $config): self { if (empty($config['class'])) { throw new Exception('Please set the class property for "'.htmlspecialchars($componentName, ENT_QUOTES, 'utf-8').'" component.'); } $component = new $config['class']; if ($component instanceof Base) { $component->populateFromArray($config); } else { unset($config['class']); foreach ($config as $property => $value) { if (property_exists($component, $property)) { $reflection = new ReflectionProperty($component, $property); if ($reflection->isPublic()) { $component->$property = $value; } } } } $this->addToRegistry($componentName, $component); return $this; } /** * Register one or more callbacks/event handlers for the given event(s) * * A valid registration would be: * *
     * $eventHandlers = array(
     *     'eventName1' => array($object, 'method'),
     *     'eventName2' => array(
     *         array($object, 'method'),
     *         array($object, 'otherMethod'),
     *     )
     * );
     * 
* * @param array $eventHandlers * * @return Base * @throws Exception */ public function setEventHandlers(array $eventHandlers): self { foreach ($eventHandlers as $eventName => $callback) { if (empty($callback) || !is_array($callback)) { continue; } if (!is_array($callback[0]) && is_callable($callback)) { $this->getEventHandlers($eventName)->add(null, $callback); continue; } if (is_array($callback[0])) { foreach ($callback as $cb) { if (is_callable($cb)) { $this->getEventHandlers($eventName)->add(null, $cb); } } } } return $this; } /** * Return a list of callbacks/event handlers for the given event * * @param string $eventName * * @return Params * @throws Exception */ public function getEventHandlers(string $eventName): Params { if (!(self::$_eventHandlers instanceof Params)) { self::$_eventHandlers = new Params(self::$_eventHandlers); } if (!self::$_eventHandlers->contains($eventName) || !(self::$_eventHandlers->itemAt($eventName) instanceof Params)) { self::$_eventHandlers->add($eventName, new Params()); } return self::$_eventHandlers->itemAt($eventName); } /** * Remove all the event handlers bound to the event name * * @param string $eventName * * @return Base * @throws Exception */ public function removeEventHandlers(string $eventName): self { self::$_eventHandlers->remove($eventName); return $this; } /** * Called from within a child class, will populate * all the setters matching the array keys with the array values * * @param array $params * * @return Base * @throws ReflectionException */ protected function populateFromArray(array $params = []): self { /** * @var string $name * @var mixed $value */ foreach ($params as $name => $value) { $found = false; if (property_exists($this, $name)) { $param = (string)$name; } else { $asSetterName = str_replace('_', ' ', $name); $asSetterName = ucwords($asSetterName); $asSetterName = str_replace(' ', '', $asSetterName); $asSetterName[0] = strtolower($asSetterName[0]); $param = (string)(property_exists($this, $asSetterName) ? $asSetterName : ''); } if ($param) { $reflection = new ReflectionProperty($this, $param); if ($reflection->isPublic()) { $this->$param = $value; $found = true; } } if (!$found) { $methodName = str_replace('_', ' ', $name); $methodName = ucwords($methodName); $methodName = str_replace(' ', '', $methodName); $methodName = 'set'.$methodName; if (method_exists($this, $methodName)) { $reflection = new ReflectionMethod($this, $methodName); if ($reflection->isPublic()) { $this->$methodName($value); } } } } return $this; } /** * Magic setter * * This method should never be called directly from outside of the class. * * @param string $name * @param mixed $value * * @return void * @throws ReflectionException * @throws Exception */ public function __set(string $name, $value) { $methodName = 'set'.ucfirst($name); if (!method_exists($this, $methodName)) { $this->addToRegistry($name, $value); } else { $method = new ReflectionMethod($this, $methodName); if ($method->isPublic()) { $this->$methodName($value); } } } /** * Magic getter * * This method should never be called directly from outside of the class. * * @param string $name * * @return mixed * @throws ReflectionException * @throws Exception */ public function __get(string $name) { $methodName = 'get'.ucfirst($name); if (!method_exists($this, $methodName) && $this->getRegistry()->contains($name)) { return $this->getRegistry()->itemAt($name); } elseif (method_exists($this, $methodName)) { $method = new ReflectionMethod($this, $methodName); if ($method->isPublic()) { return $this->$methodName(); } } } }