diff --git a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php index 0888f97ca91d8..09653a10db9fd 100644 --- a/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php +++ b/src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php @@ -11,133 +11,19 @@ namespace Symfony\Bridge\Doctrine; -use Doctrine\Common\EventArgs; -use Doctrine\Common\EventManager; use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Allows lazy loading of listener services. + * Lazily loads listeners from the dependency injection container. * - * @author Johannes M. Schmitt + * @author Jáchym Toušek */ -class ContainerAwareEventManager extends EventManager +class ContainerAwareEventManager extends LazyEventManager { - /** - * Map of registered listeners. - * - * => - * - * @var array - */ - private $listeners = array(); - private $initialized = array(); - private $container; - public function __construct(ContainerInterface $container) { - $this->container = $container; - } - - /** - * Dispatches an event to all registered listeners. - * - * @param string $eventName The name of the event to dispatch. The name of the event is - * the name of the method that is invoked on listeners. - * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. - * If not supplied, the single empty EventArgs instance is used. - * - * @return bool - */ - public function dispatchEvent($eventName, EventArgs $eventArgs = null) - { - if (isset($this->listeners[$eventName])) { - $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs; - - $initialized = isset($this->initialized[$eventName]); - - foreach ($this->listeners[$eventName] as $hash => $listener) { - if (!$initialized && is_string($listener)) { - $this->listeners[$eventName][$hash] = $listener = $this->container->get($listener); - } - - $listener->$eventName($eventArgs); - } - $this->initialized[$eventName] = true; - } - } - - /** - * Gets the listeners of a specific event or all listeners. - * - * @param string $event The name of the event - * - * @return array The event listeners for the specified event, or all event listeners - */ - public function getListeners($event = null) - { - return $event ? $this->listeners[$event] : $this->listeners; - } - - /** - * Checks whether an event has any registered listeners. - * - * @param string $event - * - * @return bool TRUE if the specified event has any listeners, FALSE otherwise - */ - public function hasListeners($event) - { - return isset($this->listeners[$event]) && $this->listeners[$event]; - } - - /** - * Adds an event listener that listens on the specified events. - * - * @param string|array $events The event(s) to listen on - * @param object|string $listener The listener object - * - * @throws \RuntimeException - */ - public function addEventListener($events, $listener) - { - if (is_string($listener)) { - if ($this->initialized) { - throw new \RuntimeException('Adding lazy-loading listeners after construction is not supported.'); - } - - $hash = '_service_'.$listener; - } else { - // Picks the hash code related to that listener - $hash = spl_object_hash($listener); - } - - foreach ((array) $events as $event) { - // Overrides listener if a previous one was associated already - // Prevents duplicate listeners on same event (same instance only) - $this->listeners[$event][$hash] = $listener; - } - } - - /** - * Removes an event listener from the specified events. - * - * @param string|array $events - * @param object|string $listener - */ - 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); - } - - foreach ((array) $events as $event) { - // Check if actually have this listener associated - if (isset($this->listeners[$event][$hash])) { - unset($this->listeners[$event][$hash]); - } - } + parent::__construct(function ($serviceId) use ($container) { + return $container->get($serviceId); + }); } } diff --git a/src/Symfony/Bridge/Doctrine/LazyEventManager.php b/src/Symfony/Bridge/Doctrine/LazyEventManager.php new file mode 100644 index 0000000000000..aa316351400fb --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/LazyEventManager.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine; + +use Doctrine\Common\EventArgs; +use Doctrine\Common\EventManager; + +/** + * Allows lazy loading of listeners. + * + * @author Johannes M. Schmitt + */ +class LazyEventManager extends EventManager +{ + /** + * Map of registered listeners. + * + * => + * + * @var array + */ + private $listeners = array(); + private $initialized = array(); + + /** + * The resolver used for lazy loading. + * + * @var callable + */ + private $listenerResolver; + + /** + * Constructor. + * + * @param callable $listenerResolver The resolver receives a string identifier of the listener + * and should return an instance of EventSubscriber. + */ + public function __construct(callable $listenerResolver) + { + $this->listenerResolver = $listenerResolver; + } + + /** + * Dispatches an event to all registered listeners. + * + * @param string $eventName The name of the event to dispatch. The name of the event is + * the name of the method that is invoked on listeners. + * @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners. + * If not supplied, the single empty EventArgs instance is used. + * + * @return bool + */ + public function dispatchEvent($eventName, EventArgs $eventArgs = null) + { + if (isset($this->listeners[$eventName])) { + $eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs; + + $initialized = isset($this->initialized[$eventName]); + + foreach ($this->listeners[$eventName] as $hash => $listener) { + if (!$initialized && is_string($listener)) { + $this->listeners[$eventName][$hash] = $listener = call_user_func($this->listenerResolver, $listener); + } + + $listener->$eventName($eventArgs); + } + $this->initialized[$eventName] = true; + } + } + + /** + * Gets the listeners of a specific event or all listeners. + * + * @param string $event The name of the event + * + * @return array The event listeners for the specified event, or all event listeners + */ + public function getListeners($event = null) + { + return $event ? $this->listeners[$event] : $this->listeners; + } + + /** + * Checks whether an event has any registered listeners. + * + * @param string $event + * + * @return bool TRUE if the specified event has any listeners, FALSE otherwise + */ + public function hasListeners($event) + { + return isset($this->listeners[$event]) && $this->listeners[$event]; + } + + /** + * Adds an event listener that listens on the specified events. + * + * @param string|array $events The event(s) to listen on + * @param object|string $listener The listener object + * + * @throws \RuntimeException + */ + public function addEventListener($events, $listener) + { + if (is_string($listener)) { + if ($this->initialized) { + throw new \RuntimeException('Adding lazy-loading listeners after construction is not supported.'); + } + + $hash = '_service_'.$listener; + } else { + // Picks the hash code related to that listener + $hash = spl_object_hash($listener); + } + + foreach ((array) $events as $event) { + // Overrides listener if a previous one was associated already + // Prevents duplicate listeners on same event (same instance only) + $this->listeners[$event][$hash] = $listener; + } + } + + /** + * Removes an event listener from the specified events. + * + * @param string|array $events + * @param object|string $listener + */ + 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); + } + + foreach ((array) $events as $event) { + // Check if actually have this listener associated + if (isset($this->listeners[$event][$hash])) { + unset($this->listeners[$event][$hash]); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php index 55991dbf4f653..7ec987d626ba5 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ContainerAwareEventManagerTest.php @@ -14,52 +14,16 @@ use Symfony\Bridge\Doctrine\ContainerAwareEventManager; use Symfony\Component\DependencyInjection\Container; -class ContainerAwareEventManagerTest extends \PHPUnit_Framework_TestCase +class ContainerAwareEventManagerTest extends LazyEventManagerTest { - private $container; - private $evm; - - protected function setUp() - { - $this->container = new Container(); - $this->evm = new ContainerAwareEventManager($this->container); - } - - public function testDispatchEvent() - { - $this->container->set('foobar', $listener1 = new MyListener()); - $this->evm->addEventListener('foo', 'foobar'); - $this->evm->addEventListener('foo', $listener2 = new MyListener()); - - $this->evm->dispatchEvent('foo'); - - $this->assertTrue($listener1->called); - $this->assertTrue($listener2->called); - } - - public function testRemoveEventListener() + protected function createEventManager($id = null, $listener = null) { - $this->evm->addEventListener('foo', 'bar'); - $this->evm->addEventListener('foo', $listener = new MyListener()); - - $listeners = array('foo' => array('_service_bar' => 'bar', spl_object_hash($listener) => $listener)); - $this->assertSame($listeners, $this->evm->getListeners()); - $this->assertSame($listeners['foo'], $this->evm->getListeners('foo')); - - $this->evm->removeEventListener('foo', $listener); - $this->assertSame(array('_service_bar' => 'bar'), $this->evm->getListeners('foo')); - - $this->evm->removeEventListener('foo', 'bar'); - $this->assertSame(array(), $this->evm->getListeners('foo')); - } -} + $container = new Container(); -class MyListener -{ - public $called = false; + if ($id && $listener) { + $container->set($id, $listener); + } - public function foo() - { - $this->called = true; + return new ContainerAwareEventManager($container); } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/LazyEventManagerTest.php b/src/Symfony/Bridge/Doctrine/Tests/LazyEventManagerTest.php new file mode 100644 index 0000000000000..d9e8d1c0df041 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/LazyEventManagerTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests; + +use Symfony\Bridge\Doctrine\LazyEventManager; + +class LazyEventManagerTest extends \PHPUnit_Framework_TestCase +{ + protected function createEventManager($id = null, $listener = null) + { + $resolver = $this->getMock('stdClass', array('__invoke')); + + if ($id && $listener) { + $resolver + ->method('__invoke') + ->with($id) + ->willReturn($listener) + ; + } + + return new LazyEventManager($resolver); + } + + public function testDispatchEvent() + { + $evm = $this->createEventManager('foobar', $listener1 = new MyListener()); + + $evm->addEventListener('foo', 'foobar'); + $evm->addEventListener('foo', $listener2 = new MyListener()); + + $evm->dispatchEvent('foo'); + + $this->assertTrue($listener1->called); + $this->assertTrue($listener2->called); + } + + public function testRemoveEventListener() + { + $evm = $this->createEventManager(); + + $evm->addEventListener('foo', 'bar'); + $evm->addEventListener('foo', $listener = new MyListener()); + + $listeners = array('foo' => array('_service_bar' => 'bar', spl_object_hash($listener) => $listener)); + $this->assertSame($listeners, $evm->getListeners()); + $this->assertSame($listeners['foo'], $evm->getListeners('foo')); + + $evm->removeEventListener('foo', $listener); + $this->assertSame(array('_service_bar' => 'bar'), $evm->getListeners('foo')); + + $evm->removeEventListener('foo', 'bar'); + $this->assertSame(array(), $evm->getListeners('foo')); + } +} + +class MyListener +{ + public $called = false; + + public function foo() + { + $this->called = true; + } +} diff --git a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php index 5982b85f3021d..3f00d57fcf5f4 100644 --- a/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.php @@ -14,14 +14,11 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** - * Lazily loads listeners and subscribers from the dependency injection - * container. + * Lazily loads listeners from the dependency injection container. * - * @author Fabien Potencier - * @author Bernhard Schussek - * @author Jordan Alliot + * @author Jáchym Toušek */ -class ContainerAwareEventDispatcher extends EventDispatcher +class ContainerAwareEventDispatcher extends LazyEventDispatcher { /** * The container from where services are loaded. @@ -30,20 +27,6 @@ class ContainerAwareEventDispatcher extends EventDispatcher */ private $container; - /** - * The service IDs of the event listeners and subscribers. - * - * @var array - */ - private $listenerIds = array(); - - /** - * The services registered as listeners. - * - * @var array - */ - private $listeners = array(); - /** * Constructor. * @@ -52,144 +35,13 @@ class ContainerAwareEventDispatcher extends EventDispatcher public function __construct(ContainerInterface $container) { $this->container = $container; - } - - /** - * Adds a service as event listener. - * - * @param string $eventName Event for which the listener is added - * @param array $callback The service ID of the listener service & the method - * name that has to be called - * @param int $priority The higher this value, the earlier an event listener - * will be triggered in the chain. - * Defaults to 0. - * - * @throws \InvalidArgumentException - */ - public function addListenerService($eventName, $callback, $priority = 0) - { - if (!is_array($callback) || 2 !== count($callback)) { - throw new \InvalidArgumentException('Expected an array("service", "method") argument'); - } - - $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); - } - - public function removeListener($eventName, $listener) - { - $this->lazyLoad($eventName); - - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method, $priority)) { - $key = $serviceId.'.'.$method; - if (isset($this->listeners[$eventName][$key]) && $listener === array($this->listeners[$eventName][$key], $method)) { - unset($this->listeners[$eventName][$key]); - if (empty($this->listeners[$eventName])) { - unset($this->listeners[$eventName]); - } - unset($this->listenerIds[$eventName][$i]); - if (empty($this->listenerIds[$eventName])) { - unset($this->listenerIds[$eventName]); - } - } - } - } - - parent::removeListener($eventName, $listener); - } - - /** - * {@inheritdoc} - */ - public function hasListeners($eventName = null) - { - if (null === $eventName) { - return (bool) count($this->listenerIds) || (bool) count($this->listeners); - } - - if (isset($this->listenerIds[$eventName])) { - return true; - } - - return parent::hasListeners($eventName); - } - - /** - * {@inheritdoc} - */ - public function getListeners($eventName = null) - { - if (null === $eventName) { - foreach ($this->listenerIds as $serviceEventName => $args) { - $this->lazyLoad($serviceEventName); - } - } else { - $this->lazyLoad($eventName); - } - - return parent::getListeners($eventName); - } - - /** - * {@inheritdoc} - */ - public function getListenerPriority($eventName, $listener) - { - $this->lazyLoad($eventName); - - return parent::getListenerPriority($eventName, $listener); - } - - /** - * Adds a service as event subscriber. - * - * @param string $serviceId The service ID of the subscriber service - * @param string $class The service's class name (which must implement EventSubscriberInterface) - */ - public function addSubscriberService($serviceId, $class) - { - foreach ($class::getSubscribedEvents() as $eventName => $params) { - if (is_string($params)) { - $this->listenerIds[$eventName][] = array($serviceId, $params, 0); - } elseif (is_string($params[0])) { - $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); - } else { - foreach ($params as $listener) { - $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); - } - } - } + parent::__construct(function ($serviceId) use ($container) { + return $container->get($serviceId); + }); } public function getContainer() { return $this->container; } - - /** - * Lazily loads listeners for this event from the dependency injection - * container. - * - * @param string $eventName The name of the event to dispatch. The name of - * the event is the name of the method that is - * invoked on listeners. - */ - protected function lazyLoad($eventName) - { - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) { - $listener = $this->container->get($serviceId); - - $key = $serviceId.'.'.$method; - if (!isset($this->listeners[$eventName][$key])) { - $this->addListener($eventName, array($listener, $method), $priority); - } elseif ($listener !== $this->listeners[$eventName][$key]) { - parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); - $this->addListener($eventName, array($listener, $method), $priority); - } - - $this->listeners[$eventName][$key] = $listener; - } - } - } } diff --git a/src/Symfony/Component/EventDispatcher/LazyEventDispatcher.php b/src/Symfony/Component/EventDispatcher/LazyEventDispatcher.php new file mode 100644 index 0000000000000..46bceae21f71a --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/LazyEventDispatcher.php @@ -0,0 +1,187 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +/** + * Allows lazy loading of listeners. + * + * @author Fabien Potencier + * @author Bernhard Schussek + * @author Jordan Alliot + */ +class LazyEventDispatcher extends EventDispatcher +{ + /** + * The service IDs of the event listeners and subscribers. + * + * @var array + */ + private $listenerIds = array(); + + /** + * The services registered as listeners. + * + * @var array + */ + private $listeners = array(); + + /** + * The resolver used for lazy loading. + * + * @var callable + */ + private $listenerResolver; + + /** + * Constructor. + * + * @param callable $listenerResolver The resolver receives a string identifier of the listener + * and should return an instance of EventSubscriberInterface. + */ + public function __construct(callable $listenerResolver) + { + $this->listenerResolver = $listenerResolver; + } + + /** + * Adds a service as event listener. + * + * @param string $eventName Event for which the listener is added + * @param array $callback The service ID of the listener service & the method + * name that has to be called + * @param int $priority The higher this value, the earlier an event listener + * will be triggered in the chain. + * Defaults to 0. + * + * @throws \InvalidArgumentException + */ + public function addListenerService($eventName, $callback, $priority = 0) + { + if (!is_array($callback) || 2 !== count($callback)) { + throw new \InvalidArgumentException('Expected an array("service", "method") argument'); + } + + $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); + } + + public function removeListener($eventName, $listener) + { + $this->lazyLoad($eventName); + + if (isset($this->listenerIds[$eventName])) { + foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method, $priority)) { + $key = $serviceId.'.'.$method; + if (isset($this->listeners[$eventName][$key]) && $listener === array($this->listeners[$eventName][$key], $method)) { + unset($this->listeners[$eventName][$key]); + if (empty($this->listeners[$eventName])) { + unset($this->listeners[$eventName]); + } + unset($this->listenerIds[$eventName][$i]); + if (empty($this->listenerIds[$eventName])) { + unset($this->listenerIds[$eventName]); + } + } + } + } + + parent::removeListener($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null) + { + if (null === $eventName) { + return (bool) count($this->listenerIds) || (bool) count($this->listeners); + } + + if (isset($this->listenerIds[$eventName])) { + return true; + } + + return parent::hasListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function getListeners($eventName = null) + { + if (null === $eventName) { + foreach ($this->listenerIds as $serviceEventName => $args) { + $this->lazyLoad($serviceEventName); + } + } else { + $this->lazyLoad($eventName); + } + + return parent::getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function getListenerPriority($eventName, $listener) + { + $this->lazyLoad($eventName); + + return parent::getListenerPriority($eventName, $listener); + } + + /** + * Adds a service as event subscriber. + * + * @param string $serviceId The service ID of the subscriber service + * @param string $class The service's class name (which must implement EventSubscriberInterface) + */ + public function addSubscriberService($serviceId, $class) + { + foreach ($class::getSubscribedEvents() as $eventName => $params) { + if (is_string($params)) { + $this->listenerIds[$eventName][] = array($serviceId, $params, 0); + } elseif (is_string($params[0])) { + $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); + } else { + foreach ($params as $listener) { + $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); + } + } + } + } + + /** + * Lazily loads listeners for event. + * + * @param string $eventName The name of the event to dispatch. The name of + * the event is the name of the method that is + * invoked on listeners. + */ + protected function lazyLoad($eventName) + { + if (isset($this->listenerIds[$eventName])) { + foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) { + $listener = call_user_func($this->listenerResolver, $serviceId); + + $key = $serviceId.'.'.$method; + if (!isset($this->listeners[$eventName][$key])) { + $this->addListener($eventName, array($listener, $method), $priority); + } elseif ($listener !== $this->listeners[$eventName][$key]) { + parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); + $this->addListener($eventName, array($listener, $method), $priority); + } + + $this->listeners[$eventName][$key] = $listener; + } + } + } +} diff --git a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php index 04b1ec145dc74..4f1363e5f6e2e 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/ContainerAwareEventDispatcherTest.php @@ -13,195 +13,15 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest +class ContainerAwareEventDispatcherTest extends LazyEventDispatcherTest { - protected function createEventDispatcher() + protected function createEventDispatcher($id = null, $listener = null) { $container = new Container(); - return new ContainerAwareEventDispatcher($container); - } - - public function testAddAListenerService() - { - $event = new Event(); - - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $dispatcher->dispatch('onEvent', $event); - } - - public function testAddASubscriberService() - { - $event = new Event(); - - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\SubscriberService'); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $service - ->expects($this->once()) - ->method('onEventWithPriority') - ->with($event) - ; - - $service - ->expects($this->once()) - ->method('onEventNested') - ->with($event) - ; - - $container = new Container(); - $container->set('service.subscriber', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService'); - - $dispatcher->dispatch('onEvent', $event); - $dispatcher->dispatch('onEventWithPriority', $event); - $dispatcher->dispatch('onEventNested', $event); - } - - public function testPreventDuplicateListenerService() - { - $event = new Event(); - - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10); - - $dispatcher->dispatch('onEvent', $event); - } - - public function testHasListenersOnLazyLoad() - { - $event = new Event(); - - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $this->assertTrue($dispatcher->hasListeners()); - - if ($dispatcher->hasListeners('onEvent')) { - $dispatcher->dispatch('onEvent'); - } - } + $container->set($id, $listener); - public function testGetListenersOnLazyLoad() - { - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $listeners = $dispatcher->getListeners(); - - $this->assertTrue(isset($listeners['onEvent'])); - - $this->assertCount(1, $dispatcher->getListeners('onEvent')); - } - - public function testRemoveAfterDispatch() - { - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $dispatcher->dispatch('onEvent', new Event()); - $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); - $this->assertFalse($dispatcher->hasListeners('onEvent')); - } - - public function testRemoveBeforeDispatch() - { - $service = $this->getMock('Symfony\Component\EventDispatcher\Tests\Service'); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); - $this->assertFalse($dispatcher->hasListeners('onEvent')); - } -} - -class Service -{ - public function onEvent(Event $e) - { - } -} - -class SubscriberService implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return array( - 'onEvent' => 'onEvent', - 'onEventWithPriority' => array('onEventWithPriority', 10), - 'onEventNested' => array(array('onEventNested')), - ); - } - - public function onEvent(Event $e) - { - } - - public function onEventWithPriority(Event $e) - { - } - - public function onEventNested(Event $e) - { + return new ContainerAwareEventDispatcher($container); } } diff --git a/src/Symfony/Component/EventDispatcher/Tests/LazyEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/LazyEventDispatcherTest.php new file mode 100644 index 0000000000000..3e9b8d0698b0c --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/Tests/LazyEventDispatcherTest.php @@ -0,0 +1,193 @@ + + * + * 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\LazyEventDispatcher; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +class LazyEventDispatcherTest extends AbstractEventDispatcherTest +{ + protected function createEventDispatcher($id = null, $listener = null) + { + $resolver = $this->getMock('stdClass', array('__invoke')); + + if ($id && $listener) { + $resolver + ->method('__invoke') + ->with($id) + ->willReturn($listener) + ; + } + + return new LazyEventDispatcher($resolver); + } + + public function testAddAListenerService() + { + $event = new Event(); + + $listener = $this->getMock('Symfony\Component\EventDispatcher\Tests\Listener'); + + $listener + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $dispatcher = $this->createEventDispatcher('listener', $listener); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent')); + + $dispatcher->dispatch('onEvent', $event); + } + + public function testAddASubscriberService() + { + $event = new Event(); + + $subscriber = $this->getMock('Symfony\Component\EventDispatcher\Tests\Subscriber'); + + $subscriber + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $subscriber + ->expects($this->once()) + ->method('onEventWithPriority') + ->with($event) + ; + + $subscriber + ->expects($this->once()) + ->method('onEventNested') + ->with($event) + ; + + $dispatcher = $this->createEventDispatcher('subscriber', $subscriber); + $dispatcher->addSubscriberService('subscriber', 'Symfony\Component\EventDispatcher\Tests\Subscriber'); + + $dispatcher->dispatch('onEvent', $event); + $dispatcher->dispatch('onEventWithPriority', $event); + $dispatcher->dispatch('onEventNested', $event); + } + + public function testPreventDuplicateListenerService() + { + $event = new Event(); + + $listener = $this->getMock('Symfony\Component\EventDispatcher\Tests\Listener'); + + $listener + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $dispatcher = $this->createEventDispatcher('listener', $listener); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent'), 5); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent'), 10); + + $dispatcher->dispatch('onEvent', $event); + } + + public function testHasListenersOnLazyLoad() + { + $event = new Event(); + + $listener = $this->getMock('Symfony\Component\EventDispatcher\Tests\Listener'); + + $dispatcher = $this->createEventDispatcher('listener', $listener); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent')); + + $listener + ->expects($this->once()) + ->method('onEvent') + ->with($event) + ; + + $this->assertTrue($dispatcher->hasListeners()); + + if ($dispatcher->hasListeners('onEvent')) { + $dispatcher->dispatch('onEvent'); + } + } + + public function testGetListenersOnLazyLoad() + { + $listener = $this->getMock('Symfony\Component\EventDispatcher\Tests\Listener'); + + $dispatcher = $this->createEventDispatcher('listener', $listener); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent')); + + $listeners = $dispatcher->getListeners(); + + $this->assertTrue(isset($listeners['onEvent'])); + + $this->assertCount(1, $dispatcher->getListeners('onEvent')); + } + + public function testRemoveAfterDispatch() + { + $listener = $this->getMock('Symfony\Component\EventDispatcher\Tests\Listener'); + + $dispatcher = $this->createEventDispatcher('listener', $listener); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent')); + + $dispatcher->dispatch('onEvent', new Event()); + $dispatcher->removeListener('onEvent', array($listener, 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + } + + public function testRemoveBeforeDispatch() + { + $listener = $this->getMock('Symfony\Component\EventDispatcher\Tests\Listener'); + + $dispatcher = $this->createEventDispatcher('listener', $listener); + $dispatcher->addListenerService('onEvent', array('listener', 'onEvent')); + + $dispatcher->removeListener('onEvent', array($listener, 'onEvent')); + $this->assertFalse($dispatcher->hasListeners('onEvent')); + } +} + +class Listener +{ + public function onEvent(Event $e) + { + } +} + +class Subscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + 'onEvent' => 'onEvent', + 'onEventWithPriority' => array('onEventWithPriority', 10), + 'onEventNested' => array(array('onEventNested')), + ); + } + + public function onEvent(Event $e) + { + } + + public function onEventWithPriority(Event $e) + { + } + + public function onEventNested(Event $e) + { + } +}