Code Coverage  | 
     ||||||||||
Classes and Traits  | 
      Functions and Methods  | 
      Lines  | 
     ||||||||
| Total |         | 
      100.00%  | 
      1 / 1  | 
              | 
      100.00%  | 
      8 / 8  | 
      CRAP |         | 
      100.00%  | 
      65 / 65  | 
     
| ContainerAwareEventDispatcher |         | 
      100.00%  | 
      1 / 1  | 
              | 
      100.00%  | 
      8 / 8  | 
      40 |         | 
      100.00%  | 
      65 / 65  | 
     
| __construct |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      4 / 4  | 
     |||
| dispatch |         | 
      100.00%  | 
      1 / 1  | 
      8 |         | 
      100.00%  | 
      16 / 16  | 
     |||
| getListeners |         | 
      100.00%  | 
      1 / 1  | 
      9 |         | 
      100.00%  | 
      16 / 16  | 
     |||
| hasListeners |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      1 / 1  | 
     |||
| addListener |         | 
      100.00%  | 
      1 / 1  | 
      1 |         | 
      100.00%  | 
      3 / 3  | 
     |||
| removeListener |         | 
      100.00%  | 
      1 / 1  | 
      7 |         | 
      100.00%  | 
      11 / 11  | 
     |||
| addSubscriber |         | 
      100.00%  | 
      1 / 1  | 
      7 |         | 
      100.00%  | 
      8 / 8  | 
     |||
| removeSubscriber |         | 
      100.00%  | 
      1 / 1  | 
      6 |         | 
      100.00%  | 
      6 / 6  | 
     |||
| <?php | |
| /** | |
| * @file | |
| * Contains \Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher. | |
| */ | |
| namespace Drupal\Component\EventDispatcher; | |
| use Symfony\Component\DependencyInjection\IntrospectableContainerInterface; | |
| use Symfony\Component\EventDispatcher\Event; | |
| use Symfony\Component\EventDispatcher\EventDispatcherInterface; | |
| use Symfony\Component\EventDispatcher\EventSubscriberInterface; | |
| /** | |
| * A performance optimized container aware event dispatcher. | |
| * | |
| * This version of the event dispatcher contains the following optimizations | |
| * in comparison to the Symfony event dispatcher component: | |
| * | |
| * <dl> | |
| * <dt>Faster instantiation of the event dispatcher service</dt> | |
| * <dd> | |
| * Instead of calling <code>addSubscriberService</code> once for each | |
| * subscriber, a precompiled array of listener definitions is passed | |
| * directly to the constructor. This is faster by roughly an order of | |
| * magnitude. The listeners are collected and prepared using a compiler | |
| * pass. | |
| * </dd> | |
| * <dt>Lazy instantiation of listeners</dt> | |
| * <dd> | |
| * Services are only retrieved from the container just before invocation. | |
| * Especially when dispatching the KernelEvents::REQUEST event, this leads | |
| * to a more timely invocation of the first listener. Overall dispatch | |
| * runtime is not affected by this change though. | |
| * </dd> | |
| * </dl> | |
| */ | |
| class ContainerAwareEventDispatcher implements EventDispatcherInterface { | |
| /** | |
| * The service container. | |
| * | |
| * @var \Symfony\Component\DependencyInjection\IntrospectableContainerInterface; | |
| */ | |
| protected $container; | |
| /** | |
| * Listener definitions. | |
| * | |
| * A nested array of listener definitions keyed by event name and priority. | |
| * A listener definition is an associative array with one of the following key | |
| * value pairs: | |
| * - callable: A callable listener | |
| * - service: An array of the form [service id, method] | |
| * | |
| * A service entry will be resolved to a callable only just before its | |
| * invocation. | |
| * | |
| * @var array | |
| */ | |
| protected $listeners; | |
| /** | |
| * Whether listeners need to be sorted prior to dispatch, keyed by event name. | |
| * | |
| * @var TRUE[] | |
| */ | |
| protected $unsorted; | |
| /** | |
| * Constructs a container aware event dispatcher. | |
| * | |
| * @param \Symfony\Component\DependencyInjection\IntrospectableContainerInterface $container | |
| * The service container. | |
| * @param array $listeners | |
| * A nested array of listener definitions keyed by event name and priority. | |
| * The array is expected to be ordered by priority. A listener definition is | |
| * an associative array with one of the following key value pairs: | |
| * - callable: A callable listener | |
| * - service: An array of the form [service id, method] | |
| * A service entry will be resolved to a callable only just before its | |
| * invocation. | |
| */ | |
| public function __construct(IntrospectableContainerInterface $container, array $listeners = []) { | |
| $this->container = $container; | |
| $this->listeners = $listeners; | |
| $this->unsorted = []; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function dispatch($event_name, Event $event = NULL) { | |
| if ($event === NULL) { | |
| $event = new Event(); | |
| } | |
| $event->setDispatcher($this); | |
| $event->setName($event_name); | |
| if (isset($this->listeners[$event_name])) { | |
| // Sort listeners if necessary. | |
| if (isset($this->unsorted[$event_name])) { | |
| krsort($this->listeners[$event_name]); | |
| unset($this->unsorted[$event_name]); | |
| } | |
| // Invoke listeners and resolve callables if necessary. | |
| foreach ($this->listeners[$event_name] as $priority => &$definitions) { | |
| foreach ($definitions as $key => &$definition) { | |
| if (!isset($definition['callable'])) { | |
| $definition['callable'] = [$this->container->get($definition['service'][0]), $definition['service'][1]]; | |
| } | |
| $definition['callable']($event, $event_name, $this); | |
| if ($event->isPropagationStopped()) { | |
| return $event; | |
| } | |
| } | |
| } | |
| } | |
| return $event; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function getListeners($event_name = NULL) { | |
| $result = []; | |
| if ($event_name === NULL) { | |
| // If event name was omitted, collect all listeners of all events. | |
| foreach (array_keys($this->listeners) as $event_name) { | |
| $listeners = $this->getListeners($event_name); | |
| if (!empty($listeners)) { | |
| $result[$event_name] = $listeners; | |
| } | |
| } | |
| } | |
| elseif (isset($this->listeners[$event_name])) { | |
| // Sort listeners if necessary. | |
| if (isset($this->unsorted[$event_name])) { | |
| krsort($this->listeners[$event_name]); | |
| unset($this->unsorted[$event_name]); | |
| } | |
| // Collect listeners and resolve callables if necessary. | |
| foreach ($this->listeners[$event_name] as $priority => &$definitions) { | |
| foreach ($definitions as $key => &$definition) { | |
| if (!isset($definition['callable'])) { | |
| $definition['callable'] = [$this->container->get($definition['service'][0]), $definition['service'][1]]; | |
| } | |
| $result[] = $definition['callable']; | |
| } | |
| } | |
| } | |
| return $result; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function hasListeners($event_name = NULL) { | |
| return (bool) count($this->getListeners($event_name)); | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function addListener($event_name, $listener, $priority = 0) { | |
| $this->listeners[$event_name][$priority][] = ['callable' => $listener]; | |
| $this->unsorted[$event_name] = TRUE; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function removeListener($event_name, $listener) { | |
| if (!isset($this->listeners[$event_name])) { | |
| return; | |
| } | |
| foreach ($this->listeners[$event_name] as $priority => $definitions) { | |
| foreach ($definitions as $key => $definition) { | |
| if (!isset($definition['callable'])) { | |
| if (!$this->container->initialized($definition['service'][0])) { | |
| continue; | |
| } | |
| $definition['callable'] = [$this->container->get($definition['service'][0]), $definition['service'][1]]; | |
| } | |
| if ($definition['callable'] === $listener) { | |
| unset($this->listeners[$event_name][$priority][$key]); | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function addSubscriber(EventSubscriberInterface $subscriber) { | |
| foreach ($subscriber->getSubscribedEvents() as $event_name => $params) { | |
| if (is_string($params)) { | |
| $this->addListener($event_name, array($subscriber, $params)); | |
| } | |
| elseif (is_string($params[0])) { | |
| $this->addListener($event_name, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0); | |
| } | |
| else { | |
| foreach ($params as $listener) { | |
| $this->addListener($event_name, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0); | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function removeSubscriber(EventSubscriberInterface $subscriber) { | |
| foreach ($subscriber->getSubscribedEvents() as $event_name => $params) { | |
| if (is_array($params) && is_array($params[0])) { | |
| foreach ($params as $listener) { | |
| $this->removeListener($event_name, array($subscriber, $listener[0])); | |
| } | |
| } | |
| else { | |
| $this->removeListener($event_name, array($subscriber, is_string($params) ? $params : $params[0])); | |
| } | |
| } | |
| } | |
| } |