[EventDispatcher] Replaced EventDispatcher by Doctrine's implementation
This commit is contained in:
parent
25931caeab
commit
699e046b4f
@ -1,136 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
* $Id$
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\EventDispatcher;
|
||||
|
||||
/**
|
||||
* Event.
|
||||
* Event is the base class for classes containing event data.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* This class contains no event data. It is used by events that do not pass
|
||||
* state information to an event handler when an event is raised.
|
||||
*
|
||||
* You can call the method stopPropagation() to abort the execution of
|
||||
* further listeners in your event listener.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class Event implements EventInterface
|
||||
class Event
|
||||
{
|
||||
protected $processed = false;
|
||||
protected $subject;
|
||||
protected $name;
|
||||
protected $parameters;
|
||||
/**
|
||||
* @var Boolean Whether no further event listeners should be triggered
|
||||
*/
|
||||
private $propagationStopped = false;
|
||||
|
||||
/**
|
||||
* Constructs a new Event.
|
||||
* Returns whether further event listeners should be triggered.
|
||||
*
|
||||
* @param mixed $subject The subject
|
||||
* @param string $name The event name
|
||||
* @param array $parameters An array of parameters
|
||||
* @see Event::stopPropagation
|
||||
* @return Boolean Whether propagation was already stopped for this event.
|
||||
*/
|
||||
public function __construct($subject, $name, $parameters = array())
|
||||
public function isPropagationStopped()
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->name = $name;
|
||||
$this->parameters = $parameters;
|
||||
return $this->propagationStopped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subject.
|
||||
* Stops the propagation of the event to further event listeners.
|
||||
*
|
||||
* @return mixed The subject
|
||||
* If multiple event listeners are connected to the same event, no
|
||||
* further event listener will be triggered once any trigger calls
|
||||
* stopPropagation().
|
||||
*/
|
||||
public function getSubject()
|
||||
public function stopPropagation()
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event name.
|
||||
*
|
||||
* @return string The event name
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the processed flag to true.
|
||||
*
|
||||
* This method must be called by listeners when
|
||||
* it has processed the event (it is only meaningful
|
||||
* when the event has been notified with the notifyUntil()
|
||||
* dispatcher method.
|
||||
*/
|
||||
public function setProcessed()
|
||||
{
|
||||
$this->processed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the event has been processed by a listener or not.
|
||||
*
|
||||
* This method is only meaningful for events notified
|
||||
* with notifyUntil().
|
||||
*
|
||||
* @return Boolean true if the event has been processed, false otherwise
|
||||
*/
|
||||
public function isProcessed()
|
||||
{
|
||||
return $this->processed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event parameters.
|
||||
*
|
||||
* @return array The event parameters
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the parameter exists.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return Boolean true if the parameter exists, false otherwise
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return array_key_exists($name, $this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a parameter value.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws \InvalidArgumentException When parameter doesn't exists for this event
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!array_key_exists($name, $this->parameters)) {
|
||||
throw new \InvalidArgumentException(sprintf('The event "%s" has no "%s" parameter.', $this->name, $name));
|
||||
}
|
||||
|
||||
return $this->parameters[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
* @param mixed $value The parameter value
|
||||
*/
|
||||
public function set($name, $value)
|
||||
{
|
||||
$this->parameters[$name] = $value;
|
||||
$this->propagationStopped = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,147 +1,202 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
* $Id$
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\EventDispatcher;
|
||||
|
||||
/**
|
||||
* EventDispatcher implements a dispatcher object.
|
||||
* The EventManager is the central point of Doctrine's event listener system.
|
||||
* Listeners are registered on the manager and events are dispatched through the
|
||||
* manager.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision: 3938 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
class EventDispatcher implements EventDispatcherInterface
|
||||
{
|
||||
protected $listeners = array();
|
||||
/**
|
||||
* Map of registered listeners.
|
||||
* <event> => (<objecthash> => <listener>)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $listeners = array();
|
||||
|
||||
/**
|
||||
* Connects a listener to a given event name.
|
||||
* Map of priorities by the object hashes of their listeners.
|
||||
* <event> => (<objecthash> => <priority>)
|
||||
*
|
||||
* Listeners with a higher priority are executed first.
|
||||
* This property is used for listener sorting.
|
||||
*
|
||||
* @param string $name An event name
|
||||
* @param mixed $listener A PHP callable
|
||||
* @param integer $priority The priority (between -10 and 10 -- defaults to 0)
|
||||
* @var array
|
||||
*/
|
||||
public function connect($name, $listener, $priority = 0)
|
||||
private $priorities = array();
|
||||
|
||||
/**
|
||||
* Stores which event listener lists are currently sorted.
|
||||
* <event> => <sorted>
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $sorted = array();
|
||||
|
||||
/**
|
||||
* @see EventDispatcherInterface::dispatchEvent
|
||||
*/
|
||||
public function dispatchEvent($eventName, Event $event = null)
|
||||
{
|
||||
if (!isset($this->listeners[$name][$priority])) {
|
||||
if (!isset($this->listeners[$name])) {
|
||||
$this->listeners[$name] = array();
|
||||
if (isset($this->listeners[$eventName])) {
|
||||
if (null === $event) {
|
||||
$event = new Event();
|
||||
}
|
||||
$this->listeners[$name][$priority] = array();
|
||||
}
|
||||
|
||||
$this->listeners[$name][$priority][] = $listener;
|
||||
}
|
||||
$this->sortListeners($eventName);
|
||||
|
||||
/**
|
||||
* Disconnects one, or all listeners for the given event name.
|
||||
*
|
||||
* @param string $name An event name
|
||||
* @param mixed|null $listener The listener to remove, or null to remove all
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disconnect($name, $listener = null)
|
||||
{
|
||||
if (!isset($this->listeners[$name])) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->listeners[$eventName] as $listener) {
|
||||
$this->triggerListener($listener, $eventName, $event);
|
||||
|
||||
if (null === $listener) {
|
||||
unset($this->listeners[$name]);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->listeners[$name] as $priority => $callables) {
|
||||
foreach ($callables as $i => $callable) {
|
||||
if ($listener === $callable) {
|
||||
unset($this->listeners[$name][$priority][$i]);
|
||||
if ($event->isPropagationStopped()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners of a given event.
|
||||
* Triggers the listener method for an event.
|
||||
*
|
||||
* @param EventInterface $event An EventInterface instance
|
||||
* This method can be overridden to add functionality that is executed
|
||||
* for each listener.
|
||||
*
|
||||
* @param object $listener The event listener on which to invoke the listener method.
|
||||
* @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 Event $event The event arguments to pass to the event handlers/listeners.
|
||||
*/
|
||||
public function notify(EventInterface $event)
|
||||
protected function triggerListener($listener, $eventName, Event $event)
|
||||
{
|
||||
foreach ($this->getListeners($event->getName()) as $listener) {
|
||||
call_user_func($listener, $event);
|
||||
if ($listener instanceof \Closure) {
|
||||
$listener->__invoke($event);
|
||||
} else {
|
||||
$listener->$eventName($event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all listeners of a given event until one processes the event.
|
||||
* Sorts the internal list of listeners for the given event by priority.
|
||||
*
|
||||
* @param EventInterface $event An EventInterface instance
|
||||
* Calling this method multiple times will not cause overhead unless you
|
||||
* add new listeners. As long as no listener is added, the list for an
|
||||
* event name won't be sorted twice.
|
||||
*
|
||||
* @return mixed The returned value of the listener that processed the event
|
||||
* @param string $event The name of the event.
|
||||
*/
|
||||
public function notifyUntil(EventInterface $event)
|
||||
private function sortListeners($eventName)
|
||||
{
|
||||
foreach ($this->getListeners($event->getName()) as $listener) {
|
||||
$ret = call_user_func($listener, $event);
|
||||
if ($event->isProcessed()) {
|
||||
return $ret;
|
||||
if (!$this->sorted[$eventName]) {
|
||||
$p = $this->priorities[$eventName];
|
||||
|
||||
uasort($this->listeners[$eventName], function ($a, $b) use ($p) {
|
||||
return $p[spl_object_hash($b)] - $p[spl_object_hash($a)];
|
||||
});
|
||||
|
||||
$this->sorted[$eventName] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventDispatcherInterface::getListeners
|
||||
*/
|
||||
public function getListeners($eventName = null)
|
||||
{
|
||||
if ($eventName) {
|
||||
$this->sortListeners($eventName);
|
||||
|
||||
return $this->listeners[$eventName];
|
||||
}
|
||||
|
||||
foreach ($this->listeners as $eventName => $listeners) {
|
||||
$this->sortListeners($eventName);
|
||||
}
|
||||
|
||||
return $this->listeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventDispatcherInterface::hasListeners
|
||||
*/
|
||||
public function hasListeners($eventName)
|
||||
{
|
||||
return isset($this->listeners[$eventName]) && $this->listeners[$eventName];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventDispatcherInterface::addEventListener
|
||||
*/
|
||||
public function addEventListener($eventNames, $listener, $priority = 0)
|
||||
{
|
||||
// Picks the hash code related to that listener
|
||||
$hash = spl_object_hash($listener);
|
||||
|
||||
foreach ((array) $eventNames as $eventName) {
|
||||
if (!isset($this->listeners[$eventName])) {
|
||||
$this->listeners[$eventName] = array();
|
||||
$this->priorities[$eventName] = array();
|
||||
}
|
||||
|
||||
// Prevents duplicate listeners on same event (same instance only)
|
||||
$this->listeners[$eventName][$hash] = $listener;
|
||||
$this->priorities[$eventName][$hash] = $priority;
|
||||
$this->sorted[$eventName] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EventDispatcherInterface::removeEventListener
|
||||
*/
|
||||
public function removeEventListener($eventNames, $listener)
|
||||
{
|
||||
// Picks the hash code related to that listener
|
||||
$hash = spl_object_hash($listener);
|
||||
|
||||
foreach ((array) $eventNames as $eventName) {
|
||||
// Check if actually have this listener associated
|
||||
if (isset($this->listeners[$eventName][$hash])) {
|
||||
unset($this->listeners[$eventName][$hash]);
|
||||
unset($this->priorities[$eventName][$hash]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a value by calling all listeners of a given event.
|
||||
*
|
||||
* @param EventInterface $event An EventInterface instance
|
||||
* @param mixed $value The value to be filtered
|
||||
*
|
||||
* @return mixed The filtered value
|
||||
* @see EventDispatcherInterface::addEventSubscriber
|
||||
*/
|
||||
public function filter(EventInterface $event, $value)
|
||||
public function addEventSubscriber(EventSubscriberInterface $subscriber, $priority = 0)
|
||||
{
|
||||
foreach ($this->getListeners($event->getName()) as $listener) {
|
||||
$value = call_user_func($listener, $event, $value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
$this->addEventListener($subscriber->getSubscribedEvents(), $subscriber, $priority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given event name has some listeners.
|
||||
*
|
||||
* @param string $name The event name
|
||||
*
|
||||
* @return Boolean true if some listeners are connected, false otherwise
|
||||
*/
|
||||
public function hasListeners($name)
|
||||
{
|
||||
return (Boolean) count($this->getListeners($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all listeners associated with a given event name.
|
||||
*
|
||||
* @param string $name The event name
|
||||
*
|
||||
* @return array An array of listeners
|
||||
*/
|
||||
public function getListeners($name)
|
||||
{
|
||||
if (!isset($this->listeners[$name])) {
|
||||
return array();
|
||||
}
|
||||
|
||||
krsort($this->listeners[$name]);
|
||||
|
||||
return call_user_func_array('array_merge', $this->listeners[$name]);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,81 +12,72 @@
|
||||
namespace Symfony\Component\EventDispatcher;
|
||||
|
||||
/**
|
||||
* EventDispatcherInterface describes an event dispatcher class.
|
||||
* The EventManager is the central point of Doctrine's event listener system.
|
||||
* Listeners are registered on the manager and events are dispatched through the
|
||||
* manager.
|
||||
*
|
||||
* @see http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/index.html Apple's Cocoa framework
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface EventDispatcherInterface
|
||||
{
|
||||
/**
|
||||
* Connects a listener to a given event name.
|
||||
* Adds an event listener that listens on the specified events.
|
||||
*
|
||||
* Listeners with a higher priority are executed first.
|
||||
*
|
||||
* @param string $name An event name
|
||||
* @param mixed $listener A PHP callable
|
||||
* @param integer $priority The priority (between -10 and 10 -- defaults to 0)
|
||||
* @param string|array $eventNames The event(s) to listen on.
|
||||
* @param object $listener The listener object.
|
||||
* @param integer $priority The higher this value, the earlier an event
|
||||
* listener will be triggered in the chain.
|
||||
* Defaults to 0.
|
||||
*/
|
||||
function connect($name, $listener, $priority = 0);
|
||||
function addEventListener($eventNames, $listener, $priority = 0);
|
||||
|
||||
/**
|
||||
* Disconnects one, or all listeners for the given event name.
|
||||
* Adds an event subscriber. The subscriber is asked for all the events he is
|
||||
* interested in and added as a listener for these events.
|
||||
*
|
||||
* @param string $name An event name
|
||||
* @param mixed|null $listener The listener to remove, or null to remove all
|
||||
*
|
||||
* @return void
|
||||
* @param EventSubscriberInterface $subscriber The subscriber.
|
||||
* @param integer $priority The higher this value, the earlier an event
|
||||
* listener will be triggered in the chain.
|
||||
* Defaults to 0.
|
||||
*/
|
||||
function disconnect($name, $listener = null);
|
||||
function addEventSubscriber(EventSubscriberInterface $subscriber, $priority = 0);
|
||||
|
||||
/**
|
||||
* Notifies all listeners of a given event.
|
||||
* Removes an event listener from the specified events.
|
||||
*
|
||||
* @param EventInterface $event An EventInterface instance
|
||||
* @param string|array $eventNames The event(s) to remove a listener from.
|
||||
* @param object $listener The listener object to remove.
|
||||
*/
|
||||
function notify(EventInterface $event);
|
||||
function removeEventListener($eventNames, $listener);
|
||||
|
||||
/**
|
||||
* Notifies all listeners of a given event until one processes the event.
|
||||
* Dispatches an event to all registered listeners.
|
||||
*
|
||||
* A listener tells the dispatcher that it has processed the event
|
||||
* by calling the setProcessed() method on it.
|
||||
*
|
||||
* It can then return a value that will be forwarded to the caller.
|
||||
*
|
||||
* @param EventInterface $event An EventInterface instance
|
||||
*
|
||||
* @return mixed The returned value of the listener that processed the 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.
|
||||
* @param Event $event The event to pass to the event handlers/listeners.
|
||||
* If not supplied, an empty Event instance is created.
|
||||
*/
|
||||
function notifyUntil(EventInterface $event);
|
||||
function dispatchEvent($eventName, Event $event = null);
|
||||
|
||||
/**
|
||||
* Filters a value by calling all listeners of a given event.
|
||||
* Gets the listeners of a specific event or all listeners.
|
||||
*
|
||||
* @param EventInterface $event An EventInterface instance
|
||||
* @param mixed $value The value to be filtered
|
||||
* @param string $eventName The name of the event.
|
||||
*
|
||||
* @return mixed The filtered value
|
||||
* @return array The event listeners for the specified event, or all event
|
||||
* listeners by event name.
|
||||
*/
|
||||
function filter(EventInterface $event, $value);
|
||||
function getListeners($eventName = null);
|
||||
|
||||
/**
|
||||
* Returns true if the given event name has some listeners.
|
||||
* Checks whether an event has any registered listeners.
|
||||
*
|
||||
* @param string $name The event name
|
||||
* @param string $eventName The name of the event.
|
||||
*
|
||||
* @return Boolean true if some listeners are connected, false otherwise
|
||||
* @return Boolean TRUE if the specified event has any listeners, FALSE
|
||||
* otherwise.
|
||||
*/
|
||||
function hasListeners($name);
|
||||
|
||||
/**
|
||||
* Returns all listeners associated with a given event name.
|
||||
*
|
||||
* @param string $name The event name
|
||||
*
|
||||
* @return array An array of listeners
|
||||
*/
|
||||
function getListeners($name);
|
||||
}
|
||||
function hasListeners($eventName);
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* EventInterface.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface EventInterface
|
||||
{
|
||||
/**
|
||||
* Returns the subject.
|
||||
*
|
||||
* @return mixed The subject
|
||||
*/
|
||||
function getSubject();
|
||||
|
||||
/**
|
||||
* Returns the event name.
|
||||
*
|
||||
* @return string The event name
|
||||
*/
|
||||
function getName();
|
||||
|
||||
/**
|
||||
* Sets the processed flag to true.
|
||||
*
|
||||
* This method must be called by listeners when
|
||||
* it has processed the event (it is only meaningful
|
||||
* when the event has been notified with the notifyUntil()
|
||||
* dispatcher method.
|
||||
*/
|
||||
function setProcessed();
|
||||
|
||||
/**
|
||||
* Returns whether the event has been processed by a listener or not.
|
||||
*
|
||||
* This method is only meaningful for events notified
|
||||
* with notifyUntil().
|
||||
*
|
||||
* @return Boolean true if the event has been processed, false otherwise
|
||||
*/
|
||||
function isProcessed();
|
||||
|
||||
/**
|
||||
* Returns the event parameters.
|
||||
*
|
||||
* @return array The event parameters
|
||||
*/
|
||||
function all();
|
||||
|
||||
/**
|
||||
* Returns true if the parameter exists.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return Boolean true if the parameter exists, false otherwise
|
||||
*/
|
||||
function has($name);
|
||||
|
||||
/**
|
||||
* Returns a parameter value.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
*
|
||||
* @return mixed The parameter value
|
||||
*
|
||||
* @throws \InvalidArgumentException When parameter doesn't exists for this event
|
||||
*/
|
||||
function get($name);
|
||||
|
||||
/**
|
||||
* Sets a parameter.
|
||||
*
|
||||
* @param string $name The parameter name
|
||||
* @param mixed $value The parameter value
|
||||
*/
|
||||
function set($name, $value);
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* $Id: EventListener.php 4653 2008-07-10 17:17:58Z romanb $
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.doctrine-project.org>.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\EventDispatcher;
|
||||
|
||||
/**
|
||||
* An EventSubscriber knows himself what events he is interested in.
|
||||
* If an EventSubscriber is added to an EventManager, the manager invokes
|
||||
* {@link getSubscribedEvents} and registers the subscriber as a listener for all
|
||||
* returned events.
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @author Jonathan Wage <jonwage@gmail.com>
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Bernhard Schussek <bschussek@gmail.com>
|
||||
*/
|
||||
interface EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* Returns an array of events this subscriber wants to listen to.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSubscribedEvents();
|
||||
}
|
@ -13,126 +13,187 @@ namespace Symfony\Tests\Component\EventDispatcher;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class EventDispatcherTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testConnectAndDisconnect()
|
||||
/* Some pseudo events */
|
||||
const preFoo = 'preFoo';
|
||||
const postFoo = 'postFoo';
|
||||
const preBar = 'preBar';
|
||||
const postBar = 'postBar';
|
||||
|
||||
private $dispatcher;
|
||||
|
||||
private $listener;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$dispatcher = new EventDispatcher();
|
||||
|
||||
$dispatcher->connect('bar', 'listenToBar');
|
||||
$this->assertEquals(array('listenToBar'), $dispatcher->getListeners('bar'), '->connect() connects a listener to an event name');
|
||||
$dispatcher->connect('bar', 'listenToBarBar');
|
||||
$this->assertEquals(array('listenToBar', 'listenToBarBar'), $dispatcher->getListeners('bar'), '->connect() can connect several listeners for the same event name');
|
||||
|
||||
$dispatcher->connect('barbar', 'listenToBarBar');
|
||||
|
||||
$dispatcher->disconnect('bar');
|
||||
$this->assertEquals(array(), $dispatcher->getListeners('bar'), '->disconnect() without a listener disconnects all listeners of for an event name');
|
||||
$this->assertEquals(array('listenToBarBar'), $dispatcher->getListeners('barbar'), '->disconnect() without a listener disconnects all listeners of for an event name');
|
||||
$this->dispatcher = new EventDispatcher();
|
||||
$this->listener = new TestEventListener();
|
||||
}
|
||||
|
||||
public function testGetHasListeners()
|
||||
public function testInitialState()
|
||||
{
|
||||
$dispatcher = new EventDispatcher();
|
||||
|
||||
$this->assertFalse($dispatcher->hasListeners('foo'), '->hasListeners() returns false if the event has no listener');
|
||||
$dispatcher->connect('foo', 'listenToFoo');
|
||||
$this->assertEquals(true, $dispatcher->hasListeners('foo'), '->hasListeners() returns true if the event has some listeners');
|
||||
$dispatcher->disconnect('foo', 'listenToFoo');
|
||||
$this->assertFalse($dispatcher->hasListeners('foo'), '->hasListeners() returns false if the event has no listener');
|
||||
|
||||
$dispatcher->connect('bar', 'listenToBar');
|
||||
$this->assertEquals(array('listenToBar'), $dispatcher->getListeners('bar'), '->getListeners() returns an array of listeners connected to the given event name');
|
||||
$this->assertEquals(array(), $dispatcher->getListeners('foobar'), '->getListeners() returns an empty array if no listener are connected to the given event name');
|
||||
$this->assertEquals(array(), $this->dispatcher->getListeners());
|
||||
$this->assertFalse($this->dispatcher->hasListeners(self::preFoo));
|
||||
$this->assertFalse($this->dispatcher->hasListeners(self::postFoo));
|
||||
}
|
||||
|
||||
public function testNotify()
|
||||
public function testAddEventListener()
|
||||
{
|
||||
$listener = new Listener();
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFoo'));
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFooBis'));
|
||||
$e = $dispatcher->notify($event = new Event(new \stdClass(), 'foo'));
|
||||
$this->assertEquals('listenToFoolistenToFooBis', $listener->getValue(), '->notify() notifies all registered listeners in order');
|
||||
|
||||
$listener->reset();
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFooBis'));
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFoo'));
|
||||
$dispatcher->notify(new Event(new \stdClass(), 'foo'));
|
||||
$this->assertEquals('listenToFooBislistenToFoo', $listener->getValue(), '->notify() notifies all registered listeners in order');
|
||||
$this->dispatcher->addEventListener(array('preFoo', 'postFoo'), $this->listener);
|
||||
$this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
|
||||
$this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
|
||||
$this->assertEquals(1, count($this->dispatcher->getListeners(self::preFoo)));
|
||||
$this->assertEquals(1, count($this->dispatcher->getListeners(self::postFoo)));
|
||||
$this->assertEquals(2, count($this->dispatcher->getListeners()));
|
||||
}
|
||||
|
||||
public function testNotifyUntil()
|
||||
public function testGetListenersSortsByPriority()
|
||||
{
|
||||
$listener = new Listener();
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFoo'));
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFooBis'));
|
||||
$dispatcher->notifyUntil($event = new Event(new \stdClass(), 'foo'));
|
||||
$this->assertEquals('listenToFoolistenToFooBis', $listener->getValue(), '->notifyUntil() notifies all registered listeners in order and stops when the event is processed');
|
||||
$listener1 = new TestEventListener();
|
||||
$listener2 = new TestEventListener();
|
||||
$listener3 = new TestEventListener();
|
||||
|
||||
$listener->reset();
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFooBis'));
|
||||
$dispatcher->connect('foo', array($listener, 'listenToFoo'));
|
||||
$dispatcher->notifyUntil($event = new Event(new \stdClass(), 'foo'));
|
||||
$this->assertEquals('listenToFooBis', $listener->getValue(), '->notifyUntil() notifies all registered listeners in order and stops when the event is processed');
|
||||
$this->dispatcher->addEventListener('preFoo', $listener1, -10);
|
||||
$this->dispatcher->addEventListener('preFoo', $listener2);
|
||||
$this->dispatcher->addEventListener('preFoo', $listener3, 10);
|
||||
|
||||
$expected = array(
|
||||
spl_object_hash($listener3) => $listener3,
|
||||
spl_object_hash($listener2) => $listener2,
|
||||
spl_object_hash($listener1) => $listener1,
|
||||
);
|
||||
|
||||
$this->assertSame($expected, $this->dispatcher->getListeners('preFoo'));
|
||||
}
|
||||
|
||||
public function testFilter()
|
||||
public function testGetAllListenersSortsByPriority()
|
||||
{
|
||||
$listener = new Listener();
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->connect('foo', array($listener, 'filterFoo'));
|
||||
$dispatcher->connect('foo', array($listener, 'filterFooBis'));
|
||||
$ret = $dispatcher->filter($event = new Event(new \stdClass(), 'foo'), 'foo');
|
||||
$this->assertEquals('-*foo*-', $ret, '->filter() returns the filtered value');
|
||||
$listener1 = new TestEventListener();
|
||||
$listener2 = new TestEventListener();
|
||||
$listener3 = new TestEventListener();
|
||||
$listener4 = new TestEventListener();
|
||||
$listener5 = new TestEventListener();
|
||||
$listener6 = new TestEventListener();
|
||||
|
||||
$listener->reset();
|
||||
$dispatcher = new EventDispatcher();
|
||||
$dispatcher->connect('foo', array($listener, 'filterFooBis'));
|
||||
$dispatcher->connect('foo', array($listener, 'filterFoo'));
|
||||
$ret = $dispatcher->filter($event = new Event(new \stdClass(), 'foo'), 'foo');
|
||||
$this->assertEquals('*-foo-*', $ret, '->filter() returns the filtered value');
|
||||
$this->dispatcher->addEventListener('preFoo', $listener1, -10);
|
||||
$this->dispatcher->addEventListener('preFoo', $listener2);
|
||||
$this->dispatcher->addEventListener('preFoo', $listener3, 10);
|
||||
$this->dispatcher->addEventListener('postFoo', $listener4, -10);
|
||||
$this->dispatcher->addEventListener('postFoo', $listener5);
|
||||
$this->dispatcher->addEventListener('postFoo', $listener6, 10);
|
||||
|
||||
$expected = array(
|
||||
'preFoo' => array(
|
||||
spl_object_hash($listener3) => $listener3,
|
||||
spl_object_hash($listener2) => $listener2,
|
||||
spl_object_hash($listener1) => $listener1,
|
||||
),
|
||||
'postFoo' => array(
|
||||
spl_object_hash($listener6) => $listener6,
|
||||
spl_object_hash($listener5) => $listener5,
|
||||
spl_object_hash($listener4) => $listener4,
|
||||
),
|
||||
);
|
||||
|
||||
$this->assertSame($expected, $this->dispatcher->getListeners());
|
||||
}
|
||||
|
||||
public function testDispatchEvent()
|
||||
{
|
||||
$this->dispatcher->addEventListener(array('preFoo', 'postFoo'), $this->listener);
|
||||
$this->dispatcher->dispatchEvent(self::preFoo);
|
||||
$this->assertTrue($this->listener->preFooInvoked);
|
||||
$this->assertFalse($this->listener->postFooInvoked);
|
||||
}
|
||||
|
||||
public function testDispatchEventForClosure()
|
||||
{
|
||||
$invoked = 0;
|
||||
$listener = function () use (&$invoked) {
|
||||
$invoked++;
|
||||
};
|
||||
$this->dispatcher->addEventListener(array('preFoo', 'postFoo'), $listener);
|
||||
$this->dispatcher->dispatchEvent(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->addEventListener('postFoo', $this->listener, 10);
|
||||
$this->dispatcher->addEventListener('postFoo', $otherListener);
|
||||
$this->dispatcher->dispatchEvent(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->addEventListener('preFoo', $listener1, -10);
|
||||
$this->dispatcher->addEventListener('preFoo', $listener2);
|
||||
$this->dispatcher->addEventListener('preFoo', $listener3, 10);
|
||||
$this->dispatcher->dispatchEvent(self::preFoo);
|
||||
$this->assertEquals(array('3', '2', '1'), $invoked);
|
||||
}
|
||||
|
||||
public function testRemoveEventListener()
|
||||
{
|
||||
$this->dispatcher->addEventListener(array('preBar'), $this->listener);
|
||||
$this->assertTrue($this->dispatcher->hasListeners(self::preBar));
|
||||
$this->dispatcher->removeEventListener(array('preBar'), $this->listener);
|
||||
$this->assertFalse($this->dispatcher->hasListeners(self::preBar));
|
||||
}
|
||||
|
||||
public function testAddEventSubscriber()
|
||||
{
|
||||
$eventSubscriber = new TestEventSubscriber();
|
||||
$this->dispatcher->addEventSubscriber($eventSubscriber);
|
||||
$this->assertTrue($this->dispatcher->hasListeners(self::preFoo));
|
||||
$this->assertTrue($this->dispatcher->hasListeners(self::postFoo));
|
||||
}
|
||||
}
|
||||
|
||||
class Listener
|
||||
class TestEventListener
|
||||
{
|
||||
protected
|
||||
$value = '';
|
||||
public $preFooInvoked = false;
|
||||
public $postFooInvoked = false;
|
||||
|
||||
function filterFoo(Event $event, $foo)
|
||||
/* Listener methods */
|
||||
|
||||
public function preFoo(Event $e)
|
||||
{
|
||||
return "*$foo*";
|
||||
$this->preFooInvoked = true;
|
||||
}
|
||||
|
||||
function filterFooBis(Event $event, $foo)
|
||||
public function postFoo(Event $e)
|
||||
{
|
||||
return "-$foo-";
|
||||
}
|
||||
$this->postFooInvoked = true;
|
||||
|
||||
function listenToFoo(Event $event)
|
||||
{
|
||||
$this->value .= 'listenToFoo';
|
||||
}
|
||||
|
||||
function listenToFooBis(Event $event)
|
||||
{
|
||||
$this->value .= 'listenToFooBis';
|
||||
|
||||
$event->setProcessed();
|
||||
}
|
||||
|
||||
function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
function reset()
|
||||
{
|
||||
$this->value = '';
|
||||
$e->stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
class TestEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array('preFoo', 'postFoo');
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
<?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\Tests\Component\EventDispatcher;
|
||||
|
||||
use Symfony\Component\EventDispatcher\Event;
|
||||
|
||||
class EventTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $subject;
|
||||
protected $parameters;
|
||||
|
||||
public function testGetSubject()
|
||||
{
|
||||
$event = $this->createEvent();
|
||||
$this->assertEquals($this->subject, $event->getSubject(), '->getSubject() returns the event subject');
|
||||
}
|
||||
|
||||
public function testGetName()
|
||||
{
|
||||
$this->assertEquals('name', $this->createEvent()->getName(), '->getName() returns the event name');
|
||||
}
|
||||
|
||||
public function testParameters()
|
||||
{
|
||||
$event = $this->createEvent();
|
||||
|
||||
$this->assertEquals($this->parameters, $event->all(), '->all() returns the event parameters');
|
||||
$this->assertEquals('bar', $event->get('foo'), '->get() returns the value of a parameter');
|
||||
$event->set('foo', 'foo');
|
||||
$this->assertEquals('foo', $event->get('foo'), '->set() changes the value of a parameter');
|
||||
$this->assertTrue($event->has('foo'), '->has() returns true if the parameter is defined');
|
||||
$this->assertFalse($event->has('oof'), '->has() returns false if the parameter is not defined');
|
||||
|
||||
try {
|
||||
$event->get('foobar');
|
||||
$this->fail('->get() throws an \InvalidArgumentException exception when the parameter does not exist');
|
||||
} catch (\Exception $e) {
|
||||
$this->assertInstanceOf('\InvalidArgumentException', $e, '->get() throws an \InvalidArgumentException exception when the parameter does not exist');
|
||||
$this->assertEquals('The event "name" has no "foobar" parameter.', $e->getMessage(), '->get() throws an \InvalidArgumentException exception when the parameter does not exist');
|
||||
}
|
||||
$event = new Event($this->subject, 'name', $this->parameters);
|
||||
}
|
||||
|
||||
public function testSetIsProcessed()
|
||||
{
|
||||
$event = $this->createEvent();
|
||||
$this->assertFalse($event->isProcessed(), '->isProcessed() returns false by default');
|
||||
$event->setProcessed();
|
||||
$this->assertTrue($event->isProcessed(), '->isProcessed() returns true if the event has been processed');
|
||||
}
|
||||
|
||||
protected function createEvent()
|
||||
{
|
||||
$this->subject = new \stdClass();
|
||||
$this->parameters = array('foo' => 'bar');
|
||||
|
||||
return new Event($this->subject, 'name', $this->parameters);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user