Skip to content

Commit 572d007

Browse files
committed
[DoctrineBridge] Allow invokable event listeners
1 parent 25f1804 commit 572d007

File tree

3 files changed

+107
-31
lines changed

3 files changed

+107
-31
lines changed

src/Symfony/Bridge/Doctrine/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* added `DoctrineClearEntityManagerMiddleware`
8+
* added support for invokable event listeners
89

910

1011
4.3.0

src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php

+38-15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class ContainerAwareEventManager extends EventManager
2929
*/
3030
private $listeners = [];
3131
private $initialized = [];
32+
private $methods = [];
3233
private $container;
3334

3435
public function __construct(ContainerInterface $container)
@@ -52,7 +53,7 @@ public function dispatchEvent($eventName, EventArgs $eventArgs = null)
5253
}
5354

5455
foreach ($this->listeners[$eventName] as $hash => $listener) {
55-
$listener->$eventName($eventArgs);
56+
$listener->{$this->methods[$eventName][$hash]}($eventArgs);
5657
}
5758
}
5859

@@ -91,12 +92,7 @@ public function hasListeners($event)
9192
*/
9293
public function addEventListener($events, $listener)
9394
{
94-
if (\is_string($listener)) {
95-
$hash = '_service_'.$listener;
96-
} else {
97-
// Picks the hash code related to that listener
98-
$hash = spl_object_hash($listener);
99-
}
95+
$hash = $this->getHash($listener);
10096

10197
foreach ((array) $events as $event) {
10298
// Overrides listener if a previous one was associated already
@@ -105,6 +101,8 @@ public function addEventListener($events, $listener)
105101

106102
if (\is_string($listener)) {
107103
unset($this->initialized[$event]);
104+
} else {
105+
$this->methods[$event][$hash] = $this->getMethod($listener, $event);
108106
}
109107
}
110108
}
@@ -114,18 +112,17 @@ public function addEventListener($events, $listener)
114112
*/
115113
public function removeEventListener($events, $listener)
116114
{
117-
if (\is_string($listener)) {
118-
$hash = '_service_'.$listener;
119-
} else {
120-
// Picks the hash code related to that listener
121-
$hash = spl_object_hash($listener);
122-
}
115+
$hash = $this->getHash($listener);
123116

124117
foreach ((array) $events as $event) {
125-
// Check if actually have this listener associated
118+
// Check if we actually have this listener associated
126119
if (isset($this->listeners[$event][$hash])) {
127120
unset($this->listeners[$event][$hash]);
128121
}
122+
123+
if (isset($this->methods[$event][$hash])) {
124+
unset($this->methods[$event][$hash]);
125+
}
129126
}
130127
}
131128

@@ -136,9 +133,35 @@ private function initializeListeners($eventName)
136133
{
137134
foreach ($this->listeners[$eventName] as $hash => $listener) {
138135
if (\is_string($listener)) {
139-
$this->listeners[$eventName][$hash] = $this->container->get($listener);
136+
$this->listeners[$eventName][$hash] = $listener = $this->container->get($listener);
137+
138+
$this->methods[$eventName][$hash] = $this->getMethod($listener, $eventName);
140139
}
141140
}
142141
$this->initialized[$eventName] = true;
143142
}
143+
144+
/**
145+
* @param string|object $listener
146+
*/
147+
private function getHash($listener): string
148+
{
149+
if (\is_string($listener)) {
150+
return '_service_'.$listener;
151+
}
152+
153+
return spl_object_hash($listener);
154+
}
155+
156+
/**
157+
* @param object $listener
158+
*/
159+
private function getMethod($listener, string $event): string
160+
{
161+
if (!method_exists($listener, $event) && method_exists($listener, '__invoke')) {
162+
return '__invoke';
163+
}
164+
165+
return $event;
166+
}
144167
}

src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php

+68-16
Original file line numberDiff line numberDiff line change
@@ -28,34 +28,80 @@ protected function setUp()
2828

2929
public function testDispatchEvent()
3030
{
31-
$this->container->set('lazy', $listener1 = new MyListener());
32-
$this->evm->addEventListener('foo', 'lazy');
31+
$this->container->set('lazy1', $listener1 = new MyListener());
32+
$this->evm->addEventListener('foo', 'lazy1');
3333
$this->evm->addEventListener('foo', $listener2 = new MyListener());
34+
$this->container->set('lazy2', $listener3 = new MyListener());
35+
$this->evm->addEventListener('bar', 'lazy2');
36+
$this->evm->addEventListener('bar', $listener4 = new MyListener());
37+
$this->container->set('lazy3', $listener5 = new MyListener());
38+
$this->evm->addEventListener('foo', $listener5 = new MyListener());
39+
$this->evm->addEventListener('bar', $listener5);
3440

3541
$this->evm->dispatchEvent('foo');
36-
37-
$this->assertTrue($listener1->called);
38-
$this->assertTrue($listener2->called);
42+
$this->evm->dispatchEvent('bar');
43+
44+
$this->assertSame(0, $listener1->calledByInvokeCount);
45+
$this->assertSame(1, $listener1->calledByEventNameCount);
46+
$this->assertSame(0, $listener2->calledByInvokeCount);
47+
$this->assertSame(1, $listener2->calledByEventNameCount);
48+
$this->assertSame(1, $listener3->calledByInvokeCount);
49+
$this->assertSame(0, $listener3->calledByEventNameCount);
50+
$this->assertSame(1, $listener4->calledByInvokeCount);
51+
$this->assertSame(0, $listener4->calledByEventNameCount);
52+
$this->assertSame(1, $listener5->calledByInvokeCount);
53+
$this->assertSame(1, $listener5->calledByEventNameCount);
3954
}
4055

4156
public function testAddEventListenerAfterDispatchEvent()
4257
{
4358
$this->container->set('lazy1', $listener1 = new MyListener());
4459
$this->evm->addEventListener('foo', 'lazy1');
4560
$this->evm->addEventListener('foo', $listener2 = new MyListener());
46-
47-
$this->evm->dispatchEvent('foo');
48-
4961
$this->container->set('lazy2', $listener3 = new MyListener());
50-
$this->evm->addEventListener('foo', 'lazy2');
51-
$this->evm->addEventListener('foo', $listener4 = new MyListener());
62+
$this->evm->addEventListener('bar', 'lazy2');
63+
$this->evm->addEventListener('bar', $listener4 = new MyListener());
64+
$this->container->set('lazy3', $listener5 = new MyListener());
65+
$this->evm->addEventListener('foo', $listener5 = new MyListener());
66+
$this->evm->addEventListener('bar', $listener5);
5267

5368
$this->evm->dispatchEvent('foo');
69+
$this->evm->dispatchEvent('bar');
70+
71+
$this->container->set('lazy4', $listener6 = new MyListener());
72+
$this->evm->addEventListener('foo', 'lazy4');
73+
$this->evm->addEventListener('foo', $listener7 = new MyListener());
74+
$this->container->set('lazy5', $listener8 = new MyListener());
75+
$this->evm->addEventListener('bar', 'lazy5');
76+
$this->evm->addEventListener('bar', $listener9 = new MyListener());
77+
$this->container->set('lazy6', $listener10 = new MyListener());
78+
$this->evm->addEventListener('foo', $listener10 = new MyListener());
79+
$this->evm->addEventListener('bar', $listener10);
5480

55-
$this->assertTrue($listener1->called);
56-
$this->assertTrue($listener2->called);
57-
$this->assertTrue($listener3->called);
58-
$this->assertTrue($listener4->called);
81+
$this->evm->dispatchEvent('foo');
82+
$this->evm->dispatchEvent('bar');
83+
84+
$this->assertSame(0, $listener1->calledByInvokeCount);
85+
$this->assertSame(2, $listener1->calledByEventNameCount);
86+
$this->assertSame(0, $listener2->calledByInvokeCount);
87+
$this->assertSame(2, $listener2->calledByEventNameCount);
88+
$this->assertSame(2, $listener3->calledByInvokeCount);
89+
$this->assertSame(0, $listener3->calledByEventNameCount);
90+
$this->assertSame(2, $listener4->calledByInvokeCount);
91+
$this->assertSame(0, $listener4->calledByEventNameCount);
92+
$this->assertSame(2, $listener5->calledByInvokeCount);
93+
$this->assertSame(2, $listener5->calledByEventNameCount);
94+
95+
$this->assertSame(0, $listener6->calledByInvokeCount);
96+
$this->assertSame(1, $listener6->calledByEventNameCount);
97+
$this->assertSame(0, $listener7->calledByInvokeCount);
98+
$this->assertSame(1, $listener7->calledByEventNameCount);
99+
$this->assertSame(1, $listener8->calledByInvokeCount);
100+
$this->assertSame(0, $listener8->calledByEventNameCount);
101+
$this->assertSame(1, $listener9->calledByInvokeCount);
102+
$this->assertSame(0, $listener9->calledByEventNameCount);
103+
$this->assertSame(1, $listener10->calledByInvokeCount);
104+
$this->assertSame(1, $listener10->calledByEventNameCount);
59105
}
60106

61107
public function testGetListenersForEvent()
@@ -107,10 +153,16 @@ public function testRemoveEventListenerAfterDispatchEvent()
107153

108154
class MyListener
109155
{
110-
public $called = false;
156+
public $calledByInvokeCount = 0;
157+
public $calledByEventNameCount = 0;
158+
159+
public function __invoke(): void
160+
{
161+
$this->calledByInvokeCount++;
162+
}
111163

112164
public function foo()
113165
{
114-
$this->called = true;
166+
$this->calledByEventNameCount++;
115167
}
116168
}

0 commit comments

Comments
 (0)