vendor/symfony/doctrine-bridge/ContainerAwareEventManager.php line 221

Open in your IDE?
  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 Doctrine\Common\EventSubscriber;
  14. use Psr\Container\ContainerInterface;
  15. /**
  16. * Allows lazy loading of listener and subscriber services.
  17. *
  18. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  19. */
  20. class ContainerAwareEventManager extends EventManager
  21. {
  22. /**
  23. * Map of registered listeners.
  24. *
  25. * <event> => <listeners>
  26. */
  27. private $listeners = [];
  28. private $subscribers;
  29. private $initialized = [];
  30. private $initializedSubscribers = false;
  31. private $initializedHashMapping = [];
  32. private $methods = [];
  33. private $container;
  34. /**
  35. * @param list<string|EventSubscriber|array{string[], string|object}> $subscriberIds List of subscribers, subscriber ids, or [events, listener] tuples
  36. */
  37. public function __construct(ContainerInterface $container, array $subscriberIds = [])
  38. {
  39. $this->container = $container;
  40. $this->subscribers = $subscriberIds;
  41. }
  42. /**
  43. * {@inheritdoc}
  44. *
  45. * @return void
  46. */
  47. public function dispatchEvent($eventName, ?EventArgs $eventArgs = null)
  48. {
  49. if (!$this->initializedSubscribers) {
  50. $this->initializeSubscribers();
  51. }
  52. if (!isset($this->listeners[$eventName])) {
  53. return;
  54. }
  55. $eventArgs = $eventArgs ?? EventArgs::getEmptyInstance();
  56. if (!isset($this->initialized[$eventName])) {
  57. $this->initializeListeners($eventName);
  58. }
  59. foreach ($this->listeners[$eventName] as $hash => $listener) {
  60. $listener->{$this->methods[$eventName][$hash]}($eventArgs);
  61. }
  62. }
  63. /**
  64. * {@inheritdoc}
  65. *
  66. * @return object[][]
  67. */
  68. public function getListeners($event = null)
  69. {
  70. if (null === $event) {
  71. return $this->getAllListeners();
  72. }
  73. if (!$this->initializedSubscribers) {
  74. $this->initializeSubscribers();
  75. }
  76. if (!isset($this->initialized[$event])) {
  77. $this->initializeListeners($event);
  78. }
  79. return $this->listeners[$event];
  80. }
  81. public function getAllListeners(): array
  82. {
  83. if (!$this->initializedSubscribers) {
  84. $this->initializeSubscribers();
  85. }
  86. foreach ($this->listeners as $event => $listeners) {
  87. if (!isset($this->initialized[$event])) {
  88. $this->initializeListeners($event);
  89. }
  90. }
  91. return $this->listeners;
  92. }
  93. /**
  94. * {@inheritdoc}
  95. *
  96. * @return bool
  97. */
  98. public function hasListeners($event)
  99. {
  100. if (!$this->initializedSubscribers) {
  101. $this->initializeSubscribers();
  102. }
  103. return isset($this->listeners[$event]) && $this->listeners[$event];
  104. }
  105. /**
  106. * {@inheritdoc}
  107. *
  108. * @return void
  109. */
  110. public function addEventListener($events, $listener)
  111. {
  112. if (!$this->initializedSubscribers) {
  113. $this->initializeSubscribers();
  114. }
  115. $hash = $this->getHash($listener);
  116. foreach ((array) $events as $event) {
  117. // Overrides listener if a previous one was associated already
  118. // Prevents duplicate listeners on same event (same instance only)
  119. $this->listeners[$event][$hash] = $listener;
  120. if (\is_string($listener)) {
  121. unset($this->initialized[$event]);
  122. unset($this->initializedHashMapping[$event][$hash]);
  123. } else {
  124. $this->methods[$event][$hash] = $this->getMethod($listener, $event);
  125. }
  126. }
  127. }
  128. /**
  129. * {@inheritdoc}
  130. *
  131. * @return void
  132. */
  133. public function removeEventListener($events, $listener)
  134. {
  135. if (!$this->initializedSubscribers) {
  136. $this->initializeSubscribers();
  137. }
  138. $hash = $this->getHash($listener);
  139. foreach ((array) $events as $event) {
  140. if (isset($this->initializedHashMapping[$event][$hash])) {
  141. $hash = $this->initializedHashMapping[$event][$hash];
  142. unset($this->initializedHashMapping[$event][$hash]);
  143. }
  144. // Check if we actually have this listener associated
  145. if (isset($this->listeners[$event][$hash])) {
  146. unset($this->listeners[$event][$hash]);
  147. }
  148. if (isset($this->methods[$event][$hash])) {
  149. unset($this->methods[$event][$hash]);
  150. }
  151. }
  152. }
  153. public function addEventSubscriber(EventSubscriber $subscriber): void
  154. {
  155. if (!$this->initializedSubscribers) {
  156. $this->initializeSubscribers();
  157. }
  158. parent::addEventSubscriber($subscriber);
  159. }
  160. public function removeEventSubscriber(EventSubscriber $subscriber): void
  161. {
  162. if (!$this->initializedSubscribers) {
  163. $this->initializeSubscribers();
  164. }
  165. parent::removeEventSubscriber($subscriber);
  166. }
  167. private function initializeListeners(string $eventName)
  168. {
  169. $this->initialized[$eventName] = true;
  170. // We'll refill the whole array in order to keep the same order
  171. $listeners = [];
  172. foreach ($this->listeners[$eventName] as $hash => $listener) {
  173. if (\is_string($listener)) {
  174. $listener = $this->container->get($listener);
  175. $newHash = $this->getHash($listener);
  176. $this->initializedHashMapping[$eventName][$hash] = $newHash;
  177. $listeners[$newHash] = $listener;
  178. $this->methods[$eventName][$newHash] = $this->getMethod($listener, $eventName);
  179. } else {
  180. $listeners[$hash] = $listener;
  181. }
  182. }
  183. $this->listeners[$eventName] = $listeners;
  184. }
  185. private function initializeSubscribers()
  186. {
  187. $this->initializedSubscribers = true;
  188. foreach ($this->subscribers as $subscriber) {
  189. if (\is_array($subscriber)) {
  190. $this->addEventListener(...$subscriber);
  191. continue;
  192. }
  193. if (\is_string($subscriber)) {
  194. $subscriber = $this->container->get($subscriber);
  195. }
  196. parent::addEventSubscriber($subscriber);
  197. }
  198. $this->subscribers = [];
  199. }
  200. /**
  201. * @param string|object $listener
  202. */
  203. private function getHash($listener): string
  204. {
  205. if (\is_string($listener)) {
  206. return '_service_'.$listener;
  207. }
  208. return spl_object_hash($listener);
  209. }
  210. private function getMethod(object $listener, string $event): string
  211. {
  212. if (!method_exists($listener, $event) && method_exists($listener, '__invoke')) {
  213. return '__invoke';
  214. }
  215. return $event;
  216. }
  217. }