Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\EventDispatcher; Chris@0: Chris@0: use Symfony\Component\DependencyInjection\ContainerInterface; Chris@0: Chris@0: /** Chris@0: * Lazily loads listeners and subscribers from the dependency injection Chris@0: * container. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: * @author Bernhard Schussek Chris@0: * @author Jordan Alliot Chris@14: * Chris@14: * @deprecated since 3.3, to be removed in 4.0. Use EventDispatcher with closure factories instead. Chris@0: */ Chris@0: class ContainerAwareEventDispatcher extends EventDispatcher Chris@0: { Chris@0: private $container; Chris@0: Chris@0: /** Chris@0: * The service IDs of the event listeners and subscribers. Chris@0: */ Chris@17: private $listenerIds = []; Chris@0: Chris@0: /** Chris@0: * The services registered as listeners. Chris@0: */ Chris@17: private $listeners = []; Chris@0: Chris@0: public function __construct(ContainerInterface $container) Chris@0: { Chris@0: $this->container = $container; Chris@14: Chris@17: $class = \get_class($this); Chris@14: if ($this instanceof \PHPUnit_Framework_MockObject_MockObject || $this instanceof \Prophecy\Doubler\DoubleInterface) { Chris@14: $class = get_parent_class($class); Chris@14: } Chris@14: if (__CLASS__ !== $class) { Chris@14: @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED); Chris@14: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds a service as event listener. Chris@0: * Chris@0: * @param string $eventName Event for which the listener is added Chris@0: * @param array $callback The service ID of the listener service & the method Chris@0: * name that has to be called Chris@0: * @param int $priority The higher this value, the earlier an event listener Chris@0: * will be triggered in the chain. Chris@0: * Defaults to 0. Chris@0: * Chris@0: * @throws \InvalidArgumentException Chris@0: */ Chris@0: public function addListenerService($eventName, $callback, $priority = 0) Chris@0: { Chris@14: @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED); Chris@14: Chris@17: if (!\is_array($callback) || 2 !== \count($callback)) { Chris@17: throw new \InvalidArgumentException('Expected an ["service", "method"] argument'); Chris@0: } Chris@0: Chris@17: $this->listenerIds[$eventName][] = [$callback[0], $callback[1], $priority]; Chris@0: } Chris@0: Chris@0: public function removeListener($eventName, $listener) Chris@0: { Chris@0: $this->lazyLoad($eventName); Chris@0: Chris@0: if (isset($this->listenerIds[$eventName])) { Chris@14: foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method)) { Chris@0: $key = $serviceId.'.'.$method; Chris@17: if (isset($this->listeners[$eventName][$key]) && $listener === [$this->listeners[$eventName][$key], $method]) { Chris@0: unset($this->listeners[$eventName][$key]); Chris@0: if (empty($this->listeners[$eventName])) { Chris@0: unset($this->listeners[$eventName]); Chris@0: } Chris@0: unset($this->listenerIds[$eventName][$i]); Chris@0: if (empty($this->listenerIds[$eventName])) { Chris@0: unset($this->listenerIds[$eventName]); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: parent::removeListener($eventName, $listener); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function hasListeners($eventName = null) Chris@0: { Chris@0: if (null === $eventName) { Chris@12: return $this->listenerIds || $this->listeners || parent::hasListeners(); Chris@0: } Chris@0: Chris@0: if (isset($this->listenerIds[$eventName])) { Chris@0: return true; Chris@0: } Chris@0: Chris@0: return parent::hasListeners($eventName); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getListeners($eventName = null) Chris@0: { Chris@0: if (null === $eventName) { Chris@0: foreach ($this->listenerIds as $serviceEventName => $args) { Chris@0: $this->lazyLoad($serviceEventName); Chris@0: } Chris@0: } else { Chris@0: $this->lazyLoad($eventName); Chris@0: } Chris@0: Chris@0: return parent::getListeners($eventName); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function getListenerPriority($eventName, $listener) Chris@0: { Chris@0: $this->lazyLoad($eventName); Chris@0: Chris@0: return parent::getListenerPriority($eventName, $listener); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Adds a service as event subscriber. Chris@0: * Chris@0: * @param string $serviceId The service ID of the subscriber service Chris@0: * @param string $class The service's class name (which must implement EventSubscriberInterface) Chris@0: */ Chris@0: public function addSubscriberService($serviceId, $class) Chris@0: { Chris@14: @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED); Chris@14: Chris@0: foreach ($class::getSubscribedEvents() as $eventName => $params) { Chris@17: if (\is_string($params)) { Chris@17: $this->listenerIds[$eventName][] = [$serviceId, $params, 0]; Chris@17: } elseif (\is_string($params[0])) { Chris@17: $this->listenerIds[$eventName][] = [$serviceId, $params[0], isset($params[1]) ? $params[1] : 0]; Chris@0: } else { Chris@0: foreach ($params as $listener) { Chris@17: $this->listenerIds[$eventName][] = [$serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0]; Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: public function getContainer() Chris@0: { Chris@14: @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 as its class will be removed in 4.0. Inject the container or the services you need in your listeners/subscribers instead.', E_USER_DEPRECATED); Chris@14: Chris@0: return $this->container; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Lazily loads listeners for this event from the dependency injection Chris@0: * container. Chris@0: * Chris@0: * @param string $eventName The name of the event to dispatch. The name of Chris@0: * the event is the name of the method that is Chris@0: * invoked on listeners. Chris@0: */ Chris@0: protected function lazyLoad($eventName) Chris@0: { Chris@0: if (isset($this->listenerIds[$eventName])) { Chris@0: foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) { Chris@0: $listener = $this->container->get($serviceId); Chris@0: Chris@0: $key = $serviceId.'.'.$method; Chris@0: if (!isset($this->listeners[$eventName][$key])) { Chris@17: $this->addListener($eventName, [$listener, $method], $priority); Chris@14: } elseif ($this->listeners[$eventName][$key] !== $listener) { Chris@17: parent::removeListener($eventName, [$this->listeners[$eventName][$key], $method]); Chris@17: $this->addListener($eventName, [$listener, $method], $priority); Chris@0: } Chris@0: Chris@0: $this->listeners[$eventName][$key] = $listener; Chris@0: } Chris@0: } Chris@0: } Chris@0: }