bug #14633 [2.3][EventDispatcher] make listeners removable from an executed listener (xabbuh)

This PR was merged into the 2.3 branch.

Discussion
----------

[2.3][EventDispatcher] make listeners removable from an executed listener

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #13972
| License       | MIT
| Doc PR        |

This fixes #13972 for Symfony 2.3. On Symfony 2.6 and higher, this has already been fixed with #14355.

Commits
-------

54bb399 [EventDispatcher] make listeners removable from an executed listener
This commit is contained in:
Fabien Potencier 2015-05-14 19:40:02 +02:00
commit 291cf61616
2 changed files with 25 additions and 0 deletions

View File

@ -88,6 +88,18 @@ class TraceableEventDispatcher implements EventDispatcherInterface, TraceableEve
*/
public function removeListener($eventName, $listener)
{
if (isset($this->wrappedListeners[$this->lastEventId])) {
foreach ($this->wrappedListeners[$this->lastEventId] as $wrappedListener) {
$originalListener = $this->wrappedListeners[$this->lastEventId][$wrappedListener];
if ($originalListener === $listener) {
unset($this->wrappedListeners[$this->lastEventId][$wrappedListener]);
return $this->dispatcher->removeListener($eventName, $wrappedListener);
}
}
}
return $this->dispatcher->removeListener($eventName, $listener);
}

View File

@ -223,6 +223,19 @@ class TraceableEventDispatcherTest extends \PHPUnit_Framework_TestCase
$kernel->handle($request);
}
public function testListenerCanRemoveItselfWhenExecuted()
{
$eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
$listener1 = function () use ($eventDispatcher, &$listener1) {
$eventDispatcher->removeListener('foo', $listener1);
};
$eventDispatcher->addListener('foo', $listener1);
$eventDispatcher->addListener('foo', function () {});
$eventDispatcher->dispatch('foo');
$this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
}
protected function getHttpKernel($dispatcher, $controller)
{
$resolver = $this->getMock('Symfony\Component\HttpKernel\Controller\ControllerResolverInterface');