event dispatcher update
This commit is contained in:
		| @@ -0,0 +1,69 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * This file is part of the Symfony package. | ||||||
|  |  * | ||||||
|  |  * (c) Fabien Potencier <fabien@symfony.com> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace Symfony\Component\EventDispatcher\Debug; | ||||||
|  |  | ||||||
|  | use Symfony\Component\Stopwatch\Stopwatch; | ||||||
|  | use Symfony\Component\EventDispatcher\Event; | ||||||
|  | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @author Fabien Potencier <fabien@symfony.com> | ||||||
|  |  */ | ||||||
|  | class WrappedListener | ||||||
|  | { | ||||||
|  |     private $listener; | ||||||
|  |     private $name; | ||||||
|  |     private $called; | ||||||
|  |     private $stoppedPropagation; | ||||||
|  |     private $stopwatch; | ||||||
|  |  | ||||||
|  |     public function __construct($listener, $name, Stopwatch $stopwatch) | ||||||
|  |     { | ||||||
|  |         $this->listener = $listener; | ||||||
|  |         $this->name = $name; | ||||||
|  |         $this->stopwatch = $stopwatch; | ||||||
|  |         $this->called = false; | ||||||
|  |         $this->stoppedPropagation = false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function getWrappedListener() | ||||||
|  |     { | ||||||
|  |         return $this->listener; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function wasCalled() | ||||||
|  |     { | ||||||
|  |         return $this->called; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function stoppedPropagation() | ||||||
|  |     { | ||||||
|  |         return $this->stoppedPropagation; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) | ||||||
|  |     { | ||||||
|  |         $this->called = true; | ||||||
|  |  | ||||||
|  |         $e = $this->stopwatch->start($this->name, 'event_listener'); | ||||||
|  |  | ||||||
|  |         call_user_func($this->listener, $event, $eventName, $dispatcher); | ||||||
|  |  | ||||||
|  |         if ($e->isStarted()) { | ||||||
|  |             $e->stop(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($event->isPropagationStopped()) { | ||||||
|  |             $this->stoppedPropagation = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,369 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * This file is part of the Symfony package. | ||||||
|  |  * | ||||||
|  |  * (c) Fabien Potencier <fabien@symfony.com> | ||||||
|  |  * | ||||||
|  |  * For the full copyright and license information, please view the LICENSE | ||||||
|  |  * file that was distributed with this source code. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | namespace Symfony\Component\EventDispatcher\Tests; | ||||||
|  |  | ||||||
|  | use Symfony\Component\EventDispatcher\Event; | ||||||
|  | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||||||
|  |  | ||||||
|  | abstract class AbstractEventDispatcherTest extends \PHPUnit_Framework_TestCase | ||||||
|  | { | ||||||
|  |     /* Some pseudo events */ | ||||||
|  |     const preFoo = 'pre.foo'; | ||||||
|  |     const postFoo = 'post.foo'; | ||||||
|  |     const preBar = 'pre.bar'; | ||||||
|  |     const postBar = 'post.bar'; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @var EventDispatcher | ||||||
|  |      */ | ||||||
|  |     private $dispatcher; | ||||||
|  |  | ||||||
|  |     private $listener; | ||||||
|  |  | ||||||
|  |     protected function setUp() | ||||||
|  |     { | ||||||
|  |         $this->dispatcher = $this->createEventDispatcher(); | ||||||
|  |         $this->listener = new TestEventListener(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     protected function tearDown() | ||||||
|  |     { | ||||||
|  |         $this->dispatcher = null; | ||||||
|  |         $this->listener = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     abstract protected function createEventDispatcher(); | ||||||
|  |  | ||||||
|  |     public function testInitialState() | ||||||
|  |     { | ||||||
|  |         $this->assertEquals(array(), $this->dispatcher->getListeners()); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddListener() | ||||||
|  |     { | ||||||
|  |         $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); | ||||||
|  |         $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); | ||||||
|  |         $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); | ||||||
|  |         $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); | ||||||
|  |         $this->assertCount(2, $this->dispatcher->getListeners()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetListenersSortsByPriority() | ||||||
|  |     { | ||||||
|  |         $listener1 = new TestEventListener(); | ||||||
|  |         $listener2 = new TestEventListener(); | ||||||
|  |         $listener3 = new TestEventListener(); | ||||||
|  |         $listener1->name = '1'; | ||||||
|  |         $listener2->name = '2'; | ||||||
|  |         $listener3->name = '3'; | ||||||
|  |  | ||||||
|  |         $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); | ||||||
|  |         $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); | ||||||
|  |         $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); | ||||||
|  |  | ||||||
|  |         $expected = array( | ||||||
|  |             array($listener2, 'preFoo'), | ||||||
|  |             array($listener3, 'preFoo'), | ||||||
|  |             array($listener1, 'preFoo'), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetAllListenersSortsByPriority() | ||||||
|  |     { | ||||||
|  |         $listener1 = new TestEventListener(); | ||||||
|  |         $listener2 = new TestEventListener(); | ||||||
|  |         $listener3 = new TestEventListener(); | ||||||
|  |         $listener4 = new TestEventListener(); | ||||||
|  |         $listener5 = new TestEventListener(); | ||||||
|  |         $listener6 = new TestEventListener(); | ||||||
|  |  | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener1, -10); | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener2); | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener3, 10); | ||||||
|  |         $this->dispatcher->addListener('post.foo', $listener4, -10); | ||||||
|  |         $this->dispatcher->addListener('post.foo', $listener5); | ||||||
|  |         $this->dispatcher->addListener('post.foo', $listener6, 10); | ||||||
|  |  | ||||||
|  |         $expected = array( | ||||||
|  |             'pre.foo' => array($listener3, $listener2, $listener1), | ||||||
|  |             'post.foo' => array($listener6, $listener5, $listener4), | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $this->assertSame($expected, $this->dispatcher->getListeners()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testDispatch() | ||||||
|  |     { | ||||||
|  |         $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); | ||||||
|  |         $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); | ||||||
|  |         $this->dispatcher->dispatch(self::preFoo); | ||||||
|  |         $this->assertTrue($this->listener->preFooInvoked); | ||||||
|  |         $this->assertFalse($this->listener->postFooInvoked); | ||||||
|  |         $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); | ||||||
|  |         $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); | ||||||
|  |         $event = new Event(); | ||||||
|  |         $return = $this->dispatcher->dispatch(self::preFoo, $event); | ||||||
|  |         $this->assertEquals('pre.foo', $event->getName()); | ||||||
|  |         $this->assertSame($event, $return); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testDispatchForClosure() | ||||||
|  |     { | ||||||
|  |         $invoked = 0; | ||||||
|  |         $listener = function () use (&$invoked) { | ||||||
|  |             $invoked++; | ||||||
|  |         }; | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener); | ||||||
|  |         $this->dispatcher->addListener('post.foo', $listener); | ||||||
|  |         $this->dispatcher->dispatch(self::preFoo); | ||||||
|  |         $this->assertEquals(1, $invoked); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testStopEventPropagation() | ||||||
|  |     { | ||||||
|  |         $otherListener = new TestEventListener(); | ||||||
|  |  | ||||||
|  |         // postFoo() stops the propagation, so only one listener should | ||||||
|  |         // be executed | ||||||
|  |         // Manually set priority to enforce $this->listener to be called first | ||||||
|  |         $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); | ||||||
|  |         $this->dispatcher->addListener('post.foo', array($otherListener, 'preFoo')); | ||||||
|  |         $this->dispatcher->dispatch(self::postFoo); | ||||||
|  |         $this->assertTrue($this->listener->postFooInvoked); | ||||||
|  |         $this->assertFalse($otherListener->postFooInvoked); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testDispatchByPriority() | ||||||
|  |     { | ||||||
|  |         $invoked = array(); | ||||||
|  |         $listener1 = function () use (&$invoked) { | ||||||
|  |             $invoked[] = '1'; | ||||||
|  |         }; | ||||||
|  |         $listener2 = function () use (&$invoked) { | ||||||
|  |             $invoked[] = '2'; | ||||||
|  |         }; | ||||||
|  |         $listener3 = function () use (&$invoked) { | ||||||
|  |             $invoked[] = '3'; | ||||||
|  |         }; | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener1, -10); | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener2); | ||||||
|  |         $this->dispatcher->addListener('pre.foo', $listener3, 10); | ||||||
|  |         $this->dispatcher->dispatch(self::preFoo); | ||||||
|  |         $this->assertEquals(array('3', '2', '1'), $invoked); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRemoveListener() | ||||||
|  |     { | ||||||
|  |         $this->dispatcher->addListener('pre.bar', $this->listener); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); | ||||||
|  |         $this->dispatcher->removeListener('pre.bar', $this->listener); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); | ||||||
|  |         $this->dispatcher->removeListener('notExists', $this->listener); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddSubscriber() | ||||||
|  |     { | ||||||
|  |         $eventSubscriber = new TestEventSubscriber(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddSubscriberWithPriorities() | ||||||
|  |     { | ||||||
|  |         $eventSubscriber = new TestEventSubscriber(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |  | ||||||
|  |         $eventSubscriber = new TestEventSubscriberWithPriorities(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |  | ||||||
|  |         $listeners = $this->dispatcher->getListeners('pre.foo'); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertCount(2, $listeners); | ||||||
|  |         $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testAddSubscriberWithMultipleListeners() | ||||||
|  |     { | ||||||
|  |         $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |  | ||||||
|  |         $listeners = $this->dispatcher->getListeners('pre.foo'); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertCount(2, $listeners); | ||||||
|  |         $this->assertEquals('preFoo2', $listeners[0][1]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRemoveSubscriber() | ||||||
|  |     { | ||||||
|  |         $eventSubscriber = new TestEventSubscriber(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); | ||||||
|  |         $this->dispatcher->removeSubscriber($eventSubscriber); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRemoveSubscriberWithPriorities() | ||||||
|  |     { | ||||||
|  |         $eventSubscriber = new TestEventSubscriberWithPriorities(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->dispatcher->removeSubscriber($eventSubscriber); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testRemoveSubscriberWithMultipleListeners() | ||||||
|  |     { | ||||||
|  |         $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); | ||||||
|  |         $this->dispatcher->addSubscriber($eventSubscriber); | ||||||
|  |         $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |         $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); | ||||||
|  |         $this->dispatcher->removeSubscriber($eventSubscriber); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testEventReceivesTheDispatcherInstance() | ||||||
|  |     { | ||||||
|  |         $dispatcher = null; | ||||||
|  |         $this->dispatcher->addListener('test', function ($event) use (&$dispatcher) { | ||||||
|  |             $dispatcher = $event->getDispatcher(); | ||||||
|  |         }); | ||||||
|  |         $this->dispatcher->dispatch('test'); | ||||||
|  |         $this->assertSame($this->dispatcher, $dispatcher); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testEventReceivesTheDispatcherInstanceAsArgument() | ||||||
|  |     { | ||||||
|  |         $listener = new TestWithDispatcher(); | ||||||
|  |         $this->dispatcher->addListener('test', array($listener, 'foo')); | ||||||
|  |         $this->assertNull($listener->name); | ||||||
|  |         $this->assertNull($listener->dispatcher); | ||||||
|  |         $this->dispatcher->dispatch('test'); | ||||||
|  |         $this->assertEquals('test', $listener->name); | ||||||
|  |         $this->assertSame($this->dispatcher, $listener->dispatcher); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * @see https://bugs.php.net/bug.php?id=62976 | ||||||
|  |      * | ||||||
|  |      * This bug affects: | ||||||
|  |      *  - The PHP 5.3 branch for versions < 5.3.18 | ||||||
|  |      *  - The PHP 5.4 branch for versions < 5.4.8 | ||||||
|  |      *  - The PHP 5.5 branch is not affected | ||||||
|  |      */ | ||||||
|  |     public function testWorkaroundForPhpBug62976() | ||||||
|  |     { | ||||||
|  |         $dispatcher = $this->createEventDispatcher(); | ||||||
|  |         $dispatcher->addListener('bug.62976', new CallableClass()); | ||||||
|  |         $dispatcher->removeListener('bug.62976', function () {}); | ||||||
|  |         $this->assertTrue($dispatcher->hasListeners('bug.62976')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHasListenersWhenAddedCallbackListenerIsRemoved() | ||||||
|  |     { | ||||||
|  |         $listener = function () {}; | ||||||
|  |         $this->dispatcher->addListener('foo', $listener); | ||||||
|  |         $this->dispatcher->removeListener('foo', $listener); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testGetListenersWhenAddedCallbackListenerIsRemoved() | ||||||
|  |     { | ||||||
|  |         $listener = function () {}; | ||||||
|  |         $this->dispatcher->addListener('foo', $listener); | ||||||
|  |         $this->dispatcher->removeListener('foo', $listener); | ||||||
|  |         $this->assertSame(array(), $this->dispatcher->getListeners()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() | ||||||
|  |     { | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners('foo')); | ||||||
|  |         $this->assertFalse($this->dispatcher->hasListeners()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class CallableClass | ||||||
|  | { | ||||||
|  |     public function __invoke() | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class TestEventListener | ||||||
|  | { | ||||||
|  |     public $preFooInvoked = false; | ||||||
|  |     public $postFooInvoked = false; | ||||||
|  |  | ||||||
|  |     /* Listener methods */ | ||||||
|  |  | ||||||
|  |     public function preFoo(Event $e) | ||||||
|  |     { | ||||||
|  |         $this->preFooInvoked = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function postFoo(Event $e) | ||||||
|  |     { | ||||||
|  |         $this->postFooInvoked = true; | ||||||
|  |  | ||||||
|  |         $e->stopPropagation(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class TestWithDispatcher | ||||||
|  | { | ||||||
|  |     public $name; | ||||||
|  |     public $dispatcher; | ||||||
|  |  | ||||||
|  |     public function foo(Event $e, $name, $dispatcher) | ||||||
|  |     { | ||||||
|  |         $this->name = $name; | ||||||
|  |         $this->dispatcher = $dispatcher; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class TestEventSubscriber implements EventSubscriberInterface | ||||||
|  | { | ||||||
|  |     public static function getSubscribedEvents() | ||||||
|  |     { | ||||||
|  |         return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class TestEventSubscriberWithPriorities implements EventSubscriberInterface | ||||||
|  | { | ||||||
|  |     public static function getSubscribedEvents() | ||||||
|  |     { | ||||||
|  |         return array( | ||||||
|  |             'pre.foo' => array('preFoo', 10), | ||||||
|  |             'post.foo' => array('postFoo'), | ||||||
|  |             ); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface | ||||||
|  | { | ||||||
|  |     public static function getSubscribedEvents() | ||||||
|  |     { | ||||||
|  |         return array('pre.foo' => array( | ||||||
|  |             array('preFoo1'), | ||||||
|  |             array('preFoo2', 10), | ||||||
|  |         )); | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user