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

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 $listenerstring $event): string
  211.     {
  212.         if (!method_exists($listener$event) && method_exists($listener'__invoke')) {
  213.             return '__invoke';
  214.         }
  215.         return $event;
  216.     }
  217. }