/src/Symfony/Bundle/FrameworkBundle/ContainerAwareEventDispatcher.php

http://github.com/symfony/symfony · PHP · 175 lines · 83 code · 21 blank · 71 comment · 11 complexity · fa9b7eed2108af6b624fee458b156a5e MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle;
  11. use Symfony\Component\DependencyInjection\ContainerInterface;
  12. use Symfony\Component\EventDispatcher\EventDispatcher;
  13. use Symfony\Component\EventDispatcher\Event;
  14. /**
  15. * Lazily loads listeners and subscribers from the dependency injection
  16. * container
  17. *
  18. * @author Fabien Potencier <fabien@symfony.com>
  19. * @author Bernhard Schussek <bernhard.schussek@symfony.com>
  20. * @author Jordan Alliot <jordan.alliot@gmail.com>
  21. */
  22. class ContainerAwareEventDispatcher extends EventDispatcher
  23. {
  24. /**
  25. * The container from where services are loaded
  26. * @var ContainerInterface
  27. */
  28. private $container;
  29. /**
  30. * The service IDs of the event listeners and subscribers
  31. * @var array
  32. */
  33. private $listenerIds = array();
  34. /**
  35. * The services registered as listeners
  36. * @var array
  37. */
  38. private $listeners = array();
  39. /**
  40. * Constructor.
  41. *
  42. * @param ContainerInterface $container A ContainerInterface instance
  43. */
  44. public function __construct(ContainerInterface $container)
  45. {
  46. $this->container = $container;
  47. }
  48. /**
  49. * Adds a service as event listener
  50. *
  51. * @param string $eventName Event for which the listener is added
  52. * @param array $callback The service ID of the listener service & the method
  53. * name that has to be called
  54. * @param integer $priority The higher this value, the earlier an event listener
  55. * will be triggered in the chain.
  56. * Defaults to 0.
  57. */
  58. public function addListenerService($eventName, $callback, $priority = 0)
  59. {
  60. if (!is_array($callback) || 2 !== count($callback)) {
  61. throw new \InvalidArgumentException('Expected an array("service", "method") argument');
  62. }
  63. $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority);
  64. }
  65. /**
  66. * @see EventDispatcherInterface::hasListeners
  67. */
  68. public function hasListeners($eventName = null)
  69. {
  70. if (null === $eventName) {
  71. return (Boolean) count($this->listenerIds) || (Boolean) count($this->listeners);
  72. }
  73. if (isset($this->listenerIds[$eventName])) {
  74. return true;
  75. }
  76. return parent::hasListeners($eventName);
  77. }
  78. /**
  79. * @see EventDispatcherInterface::getListeners
  80. */
  81. public function getListeners($eventName = null)
  82. {
  83. if (null === $eventName) {
  84. foreach ($this->listenerIds as $serviceEventName => $listners) {
  85. $this->lazyLoad($serviceEventName);
  86. }
  87. } else {
  88. $this->lazyLoad($eventName);
  89. }
  90. return parent::getListeners($eventName);
  91. }
  92. /**
  93. * Adds a service as event subscriber
  94. *
  95. * @param string $serviceId The service ID of the subscriber service
  96. * @param string $class The service's class name (which must implement EventSubscriberInterface)
  97. */
  98. public function addSubscriberService($serviceId, $class)
  99. {
  100. foreach ($class::getSubscribedEvents() as $eventName => $params) {
  101. if (is_string($params)) {
  102. $this->listenerIds[$eventName][] = array($serviceId, $params, 0);
  103. } elseif (is_string($params[0])) {
  104. $this->listenerIds[$eventName][] = array($serviceId, $params[0], $params[1]);
  105. } else {
  106. foreach ($params as $listener) {
  107. $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0);
  108. }
  109. }
  110. }
  111. }
  112. /**
  113. * {@inheritDoc}
  114. *
  115. * Lazily loads listeners for this event from the dependency injection
  116. * container.
  117. *
  118. * @throws \InvalidArgumentException if the service is not defined
  119. */
  120. public function dispatch($eventName, Event $event = null)
  121. {
  122. $this->lazyLoad($eventName);
  123. parent::dispatch($eventName, $event);
  124. }
  125. public function getContainer()
  126. {
  127. return $this->container;
  128. }
  129. /**
  130. * Lazily loads listeners for this event from the dependency injection
  131. * container.
  132. *
  133. * @param string $eventName The name of the event to dispatch. The name of
  134. * the event is the name of the method that is
  135. * invoked on listeners.
  136. */
  137. protected function lazyLoad($eventName)
  138. {
  139. if (isset($this->listenerIds[$eventName])) {
  140. foreach ($this->listenerIds[$eventName] as $args) {
  141. list($serviceId, $method, $priority) = $args;
  142. $listener = $this->container->get($serviceId);
  143. $key = $serviceId.'.'.$method;
  144. if (!isset($this->listeners[$eventName][$key])) {
  145. $this->addListener($eventName, array($listener, $method), $priority);
  146. } elseif ($listener !== $this->listeners[$eventName][$key]) {
  147. $this->removeListener($eventName, array($this->listeners[$eventName][$key], $method));
  148. $this->addListener($eventName, array($listener, $method), $priority);
  149. }
  150. $this->listeners[$eventName][$key] = $listener;
  151. }
  152. }
  153. }
  154. }