ContainerAwareEventManager.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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\Bridge\Doctrine;
  11. use Doctrine\Common\EventArgs;
  12. use Doctrine\Common\EventManager;
  13. use Psr\Container\ContainerInterface;
  14. /**
  15. * Allows lazy loading of listener and subscriber services.
  16. *
  17. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  18. */
  19. class ContainerAwareEventManager extends EventManager
  20. {
  21. /**
  22. * Map of registered listeners.
  23. *
  24. * <event> => <listeners>
  25. */
  26. private $listeners = [];
  27. private $subscribers;
  28. private $initialized = [];
  29. private $initializedSubscribers = false;
  30. private $methods = [];
  31. private $container;
  32. public function __construct(ContainerInterface $container, array $subscriberIds = [])
  33. {
  34. $this->container = $container;
  35. $this->subscribers = $subscriberIds;
  36. }
  37. /**
  38. * {@inheritdoc}
  39. *
  40. * @return void
  41. */
  42. public function dispatchEvent($eventName, EventArgs $eventArgs = null)
  43. {
  44. if (!$this->initializedSubscribers) {
  45. $this->initializeSubscribers();
  46. }
  47. if (!isset($this->listeners[$eventName])) {
  48. return;
  49. }
  50. $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs;
  51. if (!isset($this->initialized[$eventName])) {
  52. $this->initializeListeners($eventName);
  53. }
  54. foreach ($this->listeners[$eventName] as $hash => $listener) {
  55. $listener->{$this->methods[$eventName][$hash]}($eventArgs);
  56. }
  57. }
  58. /**
  59. * {@inheritdoc}
  60. *
  61. * @return object[][]
  62. */
  63. public function getListeners($event = null)
  64. {
  65. if (!$this->initializedSubscribers) {
  66. $this->initializeSubscribers();
  67. }
  68. if (null !== $event) {
  69. if (!isset($this->initialized[$event])) {
  70. $this->initializeListeners($event);
  71. }
  72. return $this->listeners[$event];
  73. }
  74. foreach ($this->listeners as $event => $listeners) {
  75. if (!isset($this->initialized[$event])) {
  76. $this->initializeListeners($event);
  77. }
  78. }
  79. return $this->listeners;
  80. }
  81. /**
  82. * {@inheritdoc}
  83. *
  84. * @return bool
  85. */
  86. public function hasListeners($event)
  87. {
  88. if (!$this->initializedSubscribers) {
  89. $this->initializeSubscribers();
  90. }
  91. return isset($this->listeners[$event]) && $this->listeners[$event];
  92. }
  93. /**
  94. * {@inheritdoc}
  95. *
  96. * @return void
  97. */
  98. public function addEventListener($events, $listener)
  99. {
  100. $hash = $this->getHash($listener);
  101. foreach ((array) $events as $event) {
  102. // Overrides listener if a previous one was associated already
  103. // Prevents duplicate listeners on same event (same instance only)
  104. $this->listeners[$event][$hash] = $listener;
  105. if (\is_string($listener)) {
  106. unset($this->initialized[$event]);
  107. } else {
  108. $this->methods[$event][$hash] = $this->getMethod($listener, $event);
  109. }
  110. }
  111. }
  112. /**
  113. * {@inheritdoc}
  114. *
  115. * @return void
  116. */
  117. public function removeEventListener($events, $listener)
  118. {
  119. $hash = $this->getHash($listener);
  120. foreach ((array) $events as $event) {
  121. // Check if we actually have this listener associated
  122. if (isset($this->listeners[$event][$hash])) {
  123. unset($this->listeners[$event][$hash]);
  124. }
  125. if (isset($this->methods[$event][$hash])) {
  126. unset($this->methods[$event][$hash]);
  127. }
  128. }
  129. }
  130. private function initializeListeners(string $eventName)
  131. {
  132. $this->initialized[$eventName] = true;
  133. foreach ($this->listeners[$eventName] as $hash => $listener) {
  134. if (\is_string($listener)) {
  135. $this->listeners[$eventName][$hash] = $listener = $this->container->get($listener);
  136. $this->methods[$eventName][$hash] = $this->getMethod($listener, $eventName);
  137. }
  138. }
  139. }
  140. private function initializeSubscribers()
  141. {
  142. $this->initializedSubscribers = true;
  143. $eventListeners = $this->listeners;
  144. // reset eventListener to respect priority: EventSubscribers have a higher priority
  145. $this->listeners = [];
  146. foreach ($this->subscribers as $id => $subscriber) {
  147. if (\is_string($subscriber)) {
  148. parent::addEventSubscriber($this->subscribers[$id] = $this->container->get($subscriber));
  149. }
  150. }
  151. foreach ($eventListeners as $event => $listeners) {
  152. if (!isset($this->listeners[$event])) {
  153. $this->listeners[$event] = [];
  154. }
  155. unset($this->initialized[$event]);
  156. $this->listeners[$event] += $listeners;
  157. }
  158. $this->subscribers = [];
  159. }
  160. /**
  161. * @param string|object $listener
  162. */
  163. private function getHash($listener): string
  164. {
  165. if (\is_string($listener)) {
  166. return '_service_'.$listener;
  167. }
  168. return spl_object_hash($listener);
  169. }
  170. /**
  171. * @param object $listener
  172. */
  173. private function getMethod($listener, string $event): string
  174. {
  175. if (!method_exists($listener, $event) && method_exists($listener, '__invoke')) {
  176. return '__invoke';
  177. }
  178. return $event;
  179. }
  180. }