[DoctrineBridge] Allow invokable event listeners

This commit is contained in:
Thomas Calvet 2019-07-10 17:55:50 +02:00
parent f64d3fc23e
commit 47e872a826
3 changed files with 106 additions and 31 deletions

View File

@ -6,7 +6,7 @@ CHANGELOG
* added `DoctrineClearEntityManagerMiddleware`
* deprecated `RegistryInterface`, use `Doctrine\Common\Persistence\ManagerRegistry`
* added support for invokable event listeners
4.3.0
-----

View File

@ -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;
}
}

View File

@ -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;
}
}