diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index e0b365f442..434446c992 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -6,7 +6,7 @@ CHANGELOG * added `DoctrineClearEntityManagerMiddleware` * deprecated `RegistryInterface`, use `Doctrine\Common\Persistence\ManagerRegistry` - + * added support for invokable event listeners 4.3.0 ----- diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php index 8ecf2135d9..0c1ad35f0b 100644 --- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php +++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php @@ -29,6 +29,7 @@ class ContainerAwareEventManager extends EventManager */ private $listeners = []; private $initialized = []; + private $methods = []; private $container; public function __construct(ContainerInterface $container) @@ -52,7 +53,7 @@ class ContainerAwareEventManager extends EventManager } foreach ($this->listeners[$eventName] as $hash => $listener) { - $listener->$eventName($eventArgs); + $listener->{$this->methods[$eventName][$hash]}($eventArgs); } } @@ -91,12 +92,7 @@ class ContainerAwareEventManager extends EventManager */ public function addEventListener($events, $listener) { - if (\is_string($listener)) { - $hash = '_service_'.$listener; - } else { - // Picks the hash code related to that listener - $hash = spl_object_hash($listener); - } + $hash = $this->getHash($listener); foreach ((array) $events as $event) { // Overrides listener if a previous one was associated already @@ -105,6 +101,8 @@ class ContainerAwareEventManager extends EventManager if (\is_string($listener)) { unset($this->initialized[$event]); + } else { + $this->methods[$event][$hash] = $this->getMethod($listener, $event); } } } @@ -114,18 +112,17 @@ class ContainerAwareEventManager extends EventManager */ public function removeEventListener($events, $listener) { - if (\is_string($listener)) { - $hash = '_service_'.$listener; - } else { - // Picks the hash code related to that listener - $hash = spl_object_hash($listener); - } + $hash = $this->getHash($listener); foreach ((array) $events as $event) { - // Check if actually have this listener associated + // Check if we actually have this listener associated if (isset($this->listeners[$event][$hash])) { unset($this->listeners[$event][$hash]); } + + if (isset($this->methods[$event][$hash])) { + unset($this->methods[$event][$hash]); + } } } @@ -133,9 +130,35 @@ class ContainerAwareEventManager extends EventManager { foreach ($this->listeners[$eventName] as $hash => $listener) { if (\is_string($listener)) { - $this->listeners[$eventName][$hash] = $this->container->get($listener); + $this->listeners[$eventName][$hash] = $listener = $this->container->get($listener); + + $this->methods[$eventName][$hash] = $this->getMethod($listener, $eventName); } } $this->initialized[$eventName] = true; } + + /** + * @param string|object $listener + */ + private function getHash($listener): string + { + if (\is_string($listener)) { + return '_service_'.$listener; + } + + return spl_object_hash($listener); + } + + /** + * @param object $listener + */ + private function getMethod($listener, string $event): string + { + if (!method_exists($listener, $event) && method_exists($listener, '__invoke')) { + return '__invoke'; + } + + return $event; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php index b3fb8bc3ac..5941df8906 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php @@ -28,14 +28,29 @@ class ContainerAwareEventManagerTest extends TestCase public function testDispatchEvent() { - $this->container->set('lazy', $listener1 = new MyListener()); - $this->evm->addEventListener('foo', 'lazy'); + $this->container->set('lazy1', $listener1 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy1'); $this->evm->addEventListener('foo', $listener2 = new MyListener()); + $this->container->set('lazy2', $listener3 = new MyListener()); + $this->evm->addEventListener('bar', 'lazy2'); + $this->evm->addEventListener('bar', $listener4 = new MyListener()); + $this->container->set('lazy3', $listener5 = new MyListener()); + $this->evm->addEventListener('foo', $listener5 = new MyListener()); + $this->evm->addEventListener('bar', $listener5); $this->evm->dispatchEvent('foo'); + $this->evm->dispatchEvent('bar'); - $this->assertTrue($listener1->called); - $this->assertTrue($listener2->called); + $this->assertSame(0, $listener1->calledByInvokeCount); + $this->assertSame(1, $listener1->calledByEventNameCount); + $this->assertSame(0, $listener2->calledByInvokeCount); + $this->assertSame(1, $listener2->calledByEventNameCount); + $this->assertSame(1, $listener3->calledByInvokeCount); + $this->assertSame(0, $listener3->calledByEventNameCount); + $this->assertSame(1, $listener4->calledByInvokeCount); + $this->assertSame(0, $listener4->calledByEventNameCount); + $this->assertSame(1, $listener5->calledByInvokeCount); + $this->assertSame(1, $listener5->calledByEventNameCount); } public function testAddEventListenerAfterDispatchEvent() @@ -43,19 +58,50 @@ class ContainerAwareEventManagerTest extends TestCase $this->container->set('lazy1', $listener1 = new MyListener()); $this->evm->addEventListener('foo', 'lazy1'); $this->evm->addEventListener('foo', $listener2 = new MyListener()); - - $this->evm->dispatchEvent('foo'); - $this->container->set('lazy2', $listener3 = new MyListener()); - $this->evm->addEventListener('foo', 'lazy2'); - $this->evm->addEventListener('foo', $listener4 = new MyListener()); + $this->evm->addEventListener('bar', 'lazy2'); + $this->evm->addEventListener('bar', $listener4 = new MyListener()); + $this->container->set('lazy3', $listener5 = new MyListener()); + $this->evm->addEventListener('foo', $listener5 = new MyListener()); + $this->evm->addEventListener('bar', $listener5); $this->evm->dispatchEvent('foo'); + $this->evm->dispatchEvent('bar'); - $this->assertTrue($listener1->called); - $this->assertTrue($listener2->called); - $this->assertTrue($listener3->called); - $this->assertTrue($listener4->called); + $this->container->set('lazy4', $listener6 = new MyListener()); + $this->evm->addEventListener('foo', 'lazy4'); + $this->evm->addEventListener('foo', $listener7 = new MyListener()); + $this->container->set('lazy5', $listener8 = new MyListener()); + $this->evm->addEventListener('bar', 'lazy5'); + $this->evm->addEventListener('bar', $listener9 = new MyListener()); + $this->container->set('lazy6', $listener10 = new MyListener()); + $this->evm->addEventListener('foo', $listener10 = new MyListener()); + $this->evm->addEventListener('bar', $listener10); + + $this->evm->dispatchEvent('foo'); + $this->evm->dispatchEvent('bar'); + + $this->assertSame(0, $listener1->calledByInvokeCount); + $this->assertSame(2, $listener1->calledByEventNameCount); + $this->assertSame(0, $listener2->calledByInvokeCount); + $this->assertSame(2, $listener2->calledByEventNameCount); + $this->assertSame(2, $listener3->calledByInvokeCount); + $this->assertSame(0, $listener3->calledByEventNameCount); + $this->assertSame(2, $listener4->calledByInvokeCount); + $this->assertSame(0, $listener4->calledByEventNameCount); + $this->assertSame(2, $listener5->calledByInvokeCount); + $this->assertSame(2, $listener5->calledByEventNameCount); + + $this->assertSame(0, $listener6->calledByInvokeCount); + $this->assertSame(1, $listener6->calledByEventNameCount); + $this->assertSame(0, $listener7->calledByInvokeCount); + $this->assertSame(1, $listener7->calledByEventNameCount); + $this->assertSame(1, $listener8->calledByInvokeCount); + $this->assertSame(0, $listener8->calledByEventNameCount); + $this->assertSame(1, $listener9->calledByInvokeCount); + $this->assertSame(0, $listener9->calledByEventNameCount); + $this->assertSame(1, $listener10->calledByInvokeCount); + $this->assertSame(1, $listener10->calledByEventNameCount); } public function testGetListenersForEvent() @@ -107,10 +153,16 @@ class ContainerAwareEventManagerTest extends TestCase class MyListener { - public $called = false; + public $calledByInvokeCount = 0; + public $calledByEventNameCount = 0; + + public function __invoke(): void + { + ++$this->calledByInvokeCount; + } public function foo() { - $this->called = true; + ++$this->calledByEventNameCount; } }