From ea03fa5897bfc01e0014e42e65f889b32ea09340 Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Tue, 23 Sep 2014 21:47:06 +0200 Subject: [PATCH 1/7] feature #12007 make ContainerAwareEventDispatcher even lazier --- .../ContainerAwareEventDispatcher.php | 128 ++---------------- 1 file changed, 11 insertions(+), 117 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php index e97d427ea15eb..3528da6e36558 100644 --- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -29,18 +29,6 @@ class ContainerAwareEventDispatcher extends EventDispatcher */ private $container; - /** - * The service IDs of the event listeners and subscribers - * @var array - */ - private $listenerIds = array(); - - /** - * The services registered as listeners - * @var array - */ - private $listeners = array(); - /** * Constructor. * @@ -57,7 +45,7 @@ public function __construct(ContainerInterface $container) * @param string $eventName Event for which the listener is added * @param array $callback The service ID of the listener service & the method * name that has to be called - * @param int $priority The higher this value, the earlier an event listener + * @param integer $priority The higher this value, the earlier an event listener * will be triggered in the chain. * Defaults to 0. * @@ -69,66 +57,15 @@ public function addListenerService($eventName, $callback, $priority = 0) throw new \InvalidArgumentException('Expected an array("service", "method") argument'); } - $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); - } - - public function removeListener($eventName, $listener) - { - $this->lazyLoad($eventName); - - if (isset($this->listeners[$eventName])) { - foreach ($this->listeners[$eventName] as $key => $l) { - foreach ($this->listenerIds[$eventName] as $i => $args) { - list($serviceId, $method, $priority) = $args; - if ($key === $serviceId.'.'.$method) { - if ($listener === array($l, $method)) { - unset($this->listeners[$eventName][$key]); - if (empty($this->listeners[$eventName])) { - unset($this->listeners[$eventName]); - } - unset($this->listenerIds[$eventName][$i]); - if (empty($this->listenerIds[$eventName])) { - unset($this->listenerIds[$eventName]); - } - } - } - } - } - } - - parent::removeListener($eventName, $listener); - } - - /** - * @see EventDispatcherInterface::hasListeners - */ - public function hasListeners($eventName = null) - { - if (null === $eventName) { - return (bool) count($this->listenerIds) || (bool) count($this->listeners); - } - - if (isset($this->listenerIds[$eventName])) { - return true; - } - - return parent::hasListeners($eventName); - } + $container = $this->container; + list($serviceId, $method) = $callback; - /** - * @see EventDispatcherInterface::getListeners - */ - public function getListeners($eventName = null) - { - if (null === $eventName) { - foreach (array_keys($this->listenerIds) as $serviceEventName) { - $this->lazyLoad($serviceEventName); - } - } else { - $this->lazyLoad($eventName); - } + $listener = function ($event, $eventName, $dispatcher) use ($container, $serviceId, $method) { + $service = $container->get($serviceId); + call_user_func(array($service, $method), $event, $eventName, $dispatcher); + }; - return parent::getListeners($eventName); + parent::addListener($eventName, $listener, $priority); } /** @@ -141,62 +78,19 @@ public function addSubscriberService($serviceId, $class) { foreach ($class::getSubscribedEvents() as $eventName => $params) { if (is_string($params)) { - $this->listenerIds[$eventName][] = array($serviceId, $params, 0); + $this->addListenerService($eventName, array($serviceId, $params), 0); } elseif (is_string($params[0])) { - $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); + $this->addListenerService($eventName, array($serviceId, $params[0]), isset($params[1]) ? $params[1] : 0); } else { foreach ($params as $listener) { - $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); + $this->addListenerService($eventName, array($serviceId, $listener[0]), isset($listener[1]) ? $listener[1] : 0); } } } } - /** - * {@inheritdoc} - * - * Lazily loads listeners for this event from the dependency injection - * container. - * - * @throws \InvalidArgumentException if the service is not defined - */ - public function dispatch($eventName, Event $event = null) - { - $this->lazyLoad($eventName); - - return parent::dispatch($eventName, $event); - } - public function getContainer() { return $this->container; } - - /** - * Lazily loads listeners for this event from the dependency injection - * container. - * - * @param string $eventName The name of the event to dispatch. The name of - * the event is the name of the method that is - * invoked on listeners. - */ - protected function lazyLoad($eventName) - { - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as $args) { - list($serviceId, $method, $priority) = $args; - $listener = $this->container->get($serviceId); - - $key = $serviceId.'.'.$method; - if (!isset($this->listeners[$eventName][$key])) { - $this->addListener($eventName, array($listener, $method), $priority); - } elseif ($listener !== $this->listeners[$eventName][$key]) { - parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); - $this->addListener($eventName, array($listener, $method), $priority); - } - - $this->listeners[$eventName][$key] = $listener; - } - } - } } From 7bc9d543a5342ae474c3a7eb554e96e8657c8d8e Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Wed, 24 Sep 2014 17:08:20 +0200 Subject: [PATCH 2/7] Add back removeListener() and add a test for the lazy-instantiation --- .../ContainerAwareEventDispatcher.php | 42 ++++++++++++++++--- .../ContainerAwareEventDispatcherTest.php | 30 +++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php index 3528da6e36558..0c52ee6701611 100644 --- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -29,6 +29,12 @@ class ContainerAwareEventDispatcher extends EventDispatcher */ private $container; + /** + * A list of proxy closures indexed by eventName, serviceId, method. + * @var ContainerInterface + */ + private $proxies; + /** * Constructor. * @@ -45,7 +51,7 @@ public function __construct(ContainerInterface $container) * @param string $eventName Event for which the listener is added * @param array $callback The service ID of the listener service & the method * name that has to be called - * @param integer $priority The higher this value, the earlier an event listener + * @param int $priority The higher this value, the earlier an event listener * will be triggered in the chain. * Defaults to 0. * @@ -60,12 +66,38 @@ public function addListenerService($eventName, $callback, $priority = 0) $container = $this->container; list($serviceId, $method) = $callback; - $listener = function ($event, $eventName, $dispatcher) use ($container, $serviceId, $method) { - $service = $container->get($serviceId); - call_user_func(array($service, $method), $event, $eventName, $dispatcher); + if (isset($this->proxies[$eventName][$serviceId][$method])) { + $proxy = $this->proxies[$eventName][$serviceId][$method]; + unset($this->proxies[$eventName][$serviceId][$method]); + parent::removeListener($eventName, $proxy); + } + + $proxy = function ($event, $eventName, $dispatcher) use ($container, $serviceId, $method) { + call_user_func(array($container->get($serviceId), $method), $event, $eventName, $dispatcher); }; - parent::addListener($eventName, $listener, $priority); + $this->proxies[$eventName][$serviceId][$method] = $proxy; + parent::addListener($eventName, $proxy, $priority); + } + + /** + * @see EventDispatcherInterface::removeListener + */ + public function removeListener($eventName, $listener) + { + if (isset($this->proxies[$eventName])) { + foreach ($this->proxies[$eventName] as $serviceId => $methods) { + foreach ($methods as $method => $proxy) { + if ($listener === array($this->container->get($serviceId), $method)) { + unset($this->proxies[$eventName][$serviceId][$method]); + parent::removeListener($eventName, $proxy); + return; + } + } + } + } + + parent::removeListener($eventName, $listener); } /** diff --git a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php index fb3b4caa26624..93e67b28a70e8 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -218,6 +218,36 @@ public function testRemoveBeforeDispatch() $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); $this->assertFalse($dispatcher->hasListeners('onEvent')); } + + public function testLazyInstantiation() + { + $event = new Event(); + + $non_propagating_service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); + + $non_propagating_service + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ->will($this->returnCallback(function($event) { + $event->stopPropagation(); + })) + ; + + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $container + ->expects($this->at(0)) + ->method('get') + ->with('service.listener') + ->will($this->returnValue($non_propagating_service)) + ; + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + $dispatcher->addListenerService('onEvent', array('service.listener.omitted', 'onEvent')); + + $dispatcher->dispatch('onEvent', $event); + } } class Service From 2232862a6ec34a0111f4842b3f732c436fba536b Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Thu, 25 Sep 2014 10:18:24 +0200 Subject: [PATCH 3/7] Fix code style issues, use ContainerBuilder in lazy-loading test, do not instantiate services in removeListener, if not necessary --- .../ContainerAwareEventDispatcher.php | 13 +++-- .../ContainerAwareEventDispatcherTest.php | 51 +++++++++++-------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php index 0c52ee6701611..50ec31272149e 100644 --- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -12,6 +12,7 @@ namespace Symfony\Component\EventDispatcher; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\IntrospectableContainerInterface; /** * Lazily loads listeners and subscribers from the dependency injection @@ -85,13 +86,17 @@ public function addListenerService($eventName, $callback, $priority = 0) */ public function removeListener($eventName, $listener) { + $introspect = ($this->container instanceof IntrospectableContainerInterface); if (isset($this->proxies[$eventName])) { foreach ($this->proxies[$eventName] as $serviceId => $methods) { foreach ($methods as $method => $proxy) { - if ($listener === array($this->container->get($serviceId), $method)) { - unset($this->proxies[$eventName][$serviceId][$method]); - parent::removeListener($eventName, $proxy); - return; + if (!$introspect || $this->container->initialized($serviceId)) { + if ($listener === array($this->container->get($serviceId), $method)) { + unset($this->proxies[$eventName][$serviceId][$method]); + parent::removeListener($eventName, $proxy); + + return; + } } } } diff --git a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php index 93e67b28a70e8..166001010aacf 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\EventDispatcher\Tests; use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Scope; use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; use Symfony\Component\EventDispatcher\Event; @@ -28,8 +30,7 @@ public function testAddAListenerService() $service ->expects($this->once()) ->method('onEvent') - ->with($event) - ; + ->with($event); $container = new Container(); $container->set('service.listener', $service); @@ -49,8 +50,7 @@ public function testAddASubscriberService() $service ->expects($this->once()) ->method('onEvent') - ->with($event) - ; + ->with($event); $container = new Container(); $container->set('service.subscriber', $service); @@ -70,8 +70,7 @@ public function testPreventDuplicateListenerService() $service ->expects($this->once()) ->method('onEvent') - ->with($event) - ; + ->with($event); $container = new Container(); $container->set('service.listener', $service); @@ -113,8 +112,7 @@ public function testReEnteringAScope() $service1 ->expects($this->exactly(2)) ->method('onEvent') - ->with($event) - ; + ->with($event); $scope = new Scope('scope'); $container = new Container(); @@ -132,8 +130,7 @@ public function testReEnteringAScope() $service2 ->expects($this->once()) ->method('onEvent') - ->with($event) - ; + ->with($event); $container->enterScope('scope'); $container->set('service.listener', $service2, 'scope'); @@ -163,8 +160,7 @@ public function testHasListenersOnLazyLoad() $service ->expects($this->once()) ->method('onEvent') - ->with($event) - ; + ->with($event); $this->assertTrue($dispatcher->hasListeners()); @@ -231,23 +227,36 @@ public function testLazyInstantiation() ->with($event) ->will($this->returnCallback(function($event) { $event->stopPropagation(); - })) - ; + })); - $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); - $container - ->expects($this->at(0)) - ->method('get') - ->with('service.listener') - ->will($this->returnValue($non_propagating_service)) - ; + $container = new ContainerBuilder(); + $container->set('service.listener', $non_propagating_service); + $container->setDefinition('service.listener.omitted', new Definition('Symfony\Component\EventDispatcher\Tests\Service')); $dispatcher = new ContainerAwareEventDispatcher($container); $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); $dispatcher->addListenerService('onEvent', array('service.listener.omitted', 'onEvent')); $dispatcher->dispatch('onEvent', $event); + + $this->assertFalse($container->initialized('service.listener.omitted')); } + + public function testRemoveLazyInstantiation() + { + $container = new ContainerBuilder(); + $container->setDefinition('service.listener', new Definition('Symfony\Component\EventDispatcher\Tests\Service')); + $container->setDefinition('service.listener.second', new Definition('Symfony\Component\EventDispatcher\Tests\Service')); + + $dispatcher = new ContainerAwareEventDispatcher($container); + $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); + $this->assertFalse($container->initialized('service.listener')); + + $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + $this->assertFalse($container->initialized('service.listener.second')); + } + } class Service From cb3f1cf5ff4995075c76b050a851282c7a3bc40f Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Thu, 25 Sep 2014 10:21:11 +0200 Subject: [PATCH 4/7] Fix cs again --- .../Tests/ContainerAwareEventDispatcherTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php index 166001010aacf..4478a6970ef80 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -225,7 +225,7 @@ public function testLazyInstantiation() ->expects($this->once()) ->method('onEvent') ->with($event) - ->will($this->returnCallback(function($event) { + ->will($this->returnCallback(function ($event) { $event->stopPropagation(); })); @@ -256,7 +256,6 @@ public function testRemoveLazyInstantiation() $this->assertFalse($dispatcher->hasListeners('onEvent')); $this->assertFalse($container->initialized('service.listener.second')); } - } class Service From 4df2bf94b5bb15d2f57862e807dec7cce82ff91f Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Thu, 25 Sep 2014 13:29:48 +0200 Subject: [PATCH 5/7] Extract condition-check from loop, fix parenthesis --- .../EventDispatcher/ContainerAwareEventDispatcher.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php index 50ec31272149e..dc830f00502ed 100644 --- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -86,11 +86,11 @@ public function addListenerService($eventName, $callback, $priority = 0) */ public function removeListener($eventName, $listener) { - $introspect = ($this->container instanceof IntrospectableContainerInterface); + $introspect = $this->container instanceof IntrospectableContainerInterface; if (isset($this->proxies[$eventName])) { foreach ($this->proxies[$eventName] as $serviceId => $methods) { - foreach ($methods as $method => $proxy) { - if (!$introspect || $this->container->initialized($serviceId)) { + if (!$introspect || $this->container->initialized($serviceId)) { + foreach ($methods as $method => $proxy) { if ($listener === array($this->container->get($serviceId), $method)) { unset($this->proxies[$eventName][$serviceId][$method]); parent::removeListener($eventName, $proxy); From 1285f3603686a904d90b5cdca65c8249ebd1fd8e Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Fri, 26 Sep 2014 08:58:28 +0200 Subject: [PATCH 6/7] Replace closure with LazyServiceListener --- .../ContainerAwareEventDispatcher.php | 5 +- .../Debug/TraceableEventDispatcher.php | 8 ++ .../EventDispatcher/LazyServiceListener.php | 83 +++++++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Component/EventDispatcher/LazyServiceListener.php diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php index dc830f00502ed..f748410129412 100644 --- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -73,10 +73,7 @@ public function addListenerService($eventName, $callback, $priority = 0) parent::removeListener($eventName, $proxy); } - $proxy = function ($event, $eventName, $dispatcher) use ($container, $serviceId, $method) { - call_user_func(array($container->get($serviceId), $method), $event, $eventName, $dispatcher); - }; - + $proxy = new LazyServiceListener($container, $serviceId, $method); $this->proxies[$eventName][$serviceId][$method] = $proxy; parent::addListener($eventName, $proxy, $priority); } diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index b797667208bb5..8e4cd6b7ce8b7 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -14,6 +14,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\LazyServiceListener; use Symfony\Component\Stopwatch\Stopwatch; use Psr\Log\LoggerInterface; @@ -268,6 +269,13 @@ private function getListenerInfo($listener, $eventName) $info = array( 'event' => $eventName, ); + // Unpack lazy container service listener. + if ($listener instanceof LazyServiceListener) { + $container = $listener->getContainer(); + $method = $listener->getMethod(); + $serviceId = $listener->getServiceId(); + $listener = array($container->get($serviceId), $method); + } if ($listener instanceof \Closure) { $info += array( 'type' => 'Closure', diff --git a/src/Symfony/Component/EventDispatcher/LazyServiceListener.php b/src/Symfony/Component/EventDispatcher/LazyServiceListener.php new file mode 100644 index 0000000000000..5b047a1299af0 --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/LazyServiceListener.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * A listener forwarding its invocation to a service. + */ +class LazyServiceListener +{ + /** + * The container from where service is loaded + * @var ContainerInterface + */ + private $container; + + /** + * The service id. + * @var string + */ + private $serviceId; + + /** + * The name of a method on the service. + * @var string + */ + private $method; + + /** + * Constructor. + * + * @param ContainerInterface $container The service container + * @param string $serviceId The service identifier + * @param string $method The method name + */ + public function __construct(ContainerInterface $container, $serviceId, $method) { + $this->container = $container; + $this->serviceId = $serviceId; + $this->method = $method; + } + + /** + * Retrieves the service from the container and forwards the method call. + */ + public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) { + $service = $this->container->get($this->serviceId); + $service->{$this->method}($event, $eventName, $dispatcher); + } + + /** + * Returns the container. + */ + public function getContainer() + { + return $this->container; + } + + /** + * Returns the service id. + */ + public function getServiceId() + { + return $this->serviceId; + } + + /** + * Returns the method name. + */ + public function getMethod() + { + return $this->method; + } +} From da10aa9da187c102215db7d55ac85f01f0b62829 Mon Sep 17 00:00:00 2001 From: Lorenz Schori Date: Fri, 26 Sep 2014 09:08:20 +0200 Subject: [PATCH 7/7] Fix coding style --- .../EventDispatcher/LazyServiceListener.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/LazyServiceListener.php b/src/Symfony/Component/EventDispatcher/LazyServiceListener.php index 5b047a1299af0..f8a557e606b3f 100644 --- a/src/Symfony/Component/EventDispatcher/LazyServiceListener.php +++ b/src/Symfony/Component/EventDispatcher/LazyServiceListener.php @@ -43,16 +43,18 @@ class LazyServiceListener * @param string $serviceId The service identifier * @param string $method The method name */ - public function __construct(ContainerInterface $container, $serviceId, $method) { - $this->container = $container; - $this->serviceId = $serviceId; - $this->method = $method; + public function __construct(ContainerInterface $container, $serviceId, $method) + { + $this->container = $container; + $this->serviceId = $serviceId; + $this->method = $method; } /** * Retrieves the service from the container and forwards the method call. */ - public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) { + public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) + { $service = $this->container->get($this->serviceId); $service->{$this->method}($event, $eventName, $dispatcher); }