diff --git a/benchmarks/ZendBenchmark/EventManager/AttachBenchmark.php b/benchmarks/ZendBenchmark/EventManager/AttachBenchmark.php new file mode 100644 index 00000000000..f11ee6f4153 --- /dev/null +++ b/benchmarks/ZendBenchmark/EventManager/AttachBenchmark.php @@ -0,0 +1,45 @@ +eventManager = new EventManager(); + } + + /** + * @iterations 50 + */ + public function attachOneThousandListeners() + { + for ($i = 0 ; $i != 1000 ; ++$i) { + $this->eventManager->attach('eventName', function() {;}); + } + } +} diff --git a/benchmarks/ZendBenchmark/EventManager/TriggerEvmBenchmark.php b/benchmarks/ZendBenchmark/EventManager/TriggerEvmBenchmark.php new file mode 100644 index 00000000000..a13f43a75bd --- /dev/null +++ b/benchmarks/ZendBenchmark/EventManager/TriggerEvmBenchmark.php @@ -0,0 +1,86 @@ +eventManager = new EventManager(); + + // Add one hundred listeners to two different events with random priorities + for ($i = 0 ; $i != 100 ; ++$i) { + $this->eventManager->attach('eventName1', function() {}, rand(0, 100)); + $this->eventManager->attach('eventName2', function() {}, rand(0, 100)); + } + + // Attach also fifty listeners to the wildcard + for ($i = 0 ; $i != 10 ; ++$i) { + $this->eventManager->attach('*', function() {}, rand(0, 100)); + } + } + + /** + * @iterations 50 + */ + public function triggerEventOneTimeWithoutSharedManager() + { + $this->eventManager->trigger('eventName1'); + } + + /** + * @iterations 50 + */ + public function triggerEventOneTimeWithEmptySharedManager() + { + $this->eventManager->setSharedManager(new SharedEventManager()); + $this->eventManager->trigger('eventName1'); + } + + /** + * @iterations 50 + */ + public function triggerEventTenTimesWithoutSharedManager() + { + for ($i = 0 ; $i !== 10 ; ++$i) { + $this->eventManager->trigger('eventName1'); + } + } + + /** + * @iterations 50 + */ + public function triggerEventTenTimesWithEmptySharedManager() + { + $this->eventManager->setSharedManager(new SharedEventManager()); + + for ($i = 0 ; $i !== 10 ; ++$i) { + $this->eventManager->trigger('eventName1'); + } + } +} diff --git a/benchmarks/ZendBenchmark/EventManager/TriggerEvmWithSemBenchmark.php b/benchmarks/ZendBenchmark/EventManager/TriggerEvmWithSemBenchmark.php new file mode 100644 index 00000000000..dd6ef9f7ec0 --- /dev/null +++ b/benchmarks/ZendBenchmark/EventManager/TriggerEvmWithSemBenchmark.php @@ -0,0 +1,81 @@ +eventManager = new EventManager(); + $this->sharedManager = new SharedEventManager(); + + $this->eventManager->setIdentifiers(['identifier1', 'identifier2']); + $this->eventManager->setSharedManager($this->sharedManager); + + // Add fifty listeners to two different events with random priorities in the EVM and SEM + for ($i = 0 ; $i != 50 ; ++$i) { + $this->eventManager->attach('eventName1', function() {}, rand(0, 100)); + $this->eventManager->attach('eventName2', function() {}, rand(0, 100)); + + $this->sharedManager->attach('identifier1', 'eventName1', function() {}, rand(0, 100)); + $this->sharedManager->attach('identifier2', 'eventName1', function() {}, rand(0, 100)); + $this->sharedManager->attach('identifier3', 'eventName1', function() {}, rand(0, 100)); + } + + // Attach also fifty listeners to the wildcard + for ($i = 0 ; $i != 10 ; ++$i) { + $this->eventManager->attach('*', function() {}, rand(0, 100)); + $this->sharedManager->attach('*', 'eventName1', function() {}, rand(0, 100)); + $this->sharedManager->attach('identifier1', '*', function() {}, rand(0, 100)); + $this->sharedManager->attach('*', '*', function() {}, rand(0, 100)); + } + } + + /** + * @iterations 50 + */ + public function triggerEventOneTime() + { + $this->eventManager->trigger('eventName1'); + } + + /** + * @iterations 50 + */ + public function triggerEventTenTimes() + { + for ($i = 0 ; $i !== 10 ; ++$i) { + $this->eventManager->trigger('eventName1'); + } + } +} diff --git a/composer.json b/composer.json index b165a6b9b04..099b525ef72 100644 --- a/composer.json +++ b/composer.json @@ -12,6 +12,7 @@ "php": ">=5.3.3" }, "require-dev": { + "athletic/athletic": "0.1.7", "doctrine/annotations": ">=1.0", "ircmaxell/random-lib": "dev-master", "ircmaxell/security-lib": "dev-master", @@ -29,6 +30,12 @@ "autoload": { "psr-0": { "Zend\\": "library/" + + } + }, + "autoload-dev": { + "psr-0": { + "ZendBenchmark\\": "benchmarks/" } }, "bin": [ diff --git a/demos/bench-evm.php b/demos/bench-evm.php new file mode 100644 index 00000000000..65a6c6858a0 --- /dev/null +++ b/demos/bench-evm.php @@ -0,0 +1,61 @@ +attach('event', 'emptyFunc', $i % 10); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d\n", $timeEnd - $timeStart, $memEnd - $memStart); + + +echo "Triggers {$numberOfTriggers} events: "; +$memStart = memory_get_usage(); +$timeStart = microtime(true); +for ($i = 0; $i < $numberOfListeners; ++$i) { + $eventManager->trigger('event'); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d\n", $timeEnd - $timeStart, $memEnd - $memStart); + + +$sharedManager = new \Zend\EventManager\SharedEventManager(); +$eventManager->setSharedManager($sharedManager); + +echo "Attach {$numberOfListeners} shared listeners: "; +$memStart = memory_get_usage(); +$timeStart = microtime(true); +for ($i = 0; $i < $numberOfListeners; ++$i) { + $sharedManager->attach('myid1', 'event', 'emptyFunc', $i % 10); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d\n", $timeEnd - $timeStart, $memEnd - $memStart); + + +echo "Triggers {$numberOfTriggers} events: "; +$memStart = memory_get_usage(); +$timeStart = microtime(true); +for ($i = 0; $i < $numberOfListeners; ++$i) { + $eventManager->trigger('event'); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d\n", $timeEnd - $timeStart, $memEnd - $memStart); + + +printf("\nTotal: time=%f, mem=%d\n", microtime(true) - $totalTimeStart, memory_get_peak_usage(true)); diff --git a/demos/index.php b/demos/index.php new file mode 100644 index 00000000000..b0d86479ccf --- /dev/null +++ b/demos/index.php @@ -0,0 +1,61 @@ +attach('event', 'emptyFunc', $i); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d
", $timeEnd - $timeStart, $memEnd - $memStart); + + +echo "Triggers {$numberOfTriggers} events: "; +$memStart = memory_get_usage(); +$timeStart = microtime(true); +for ($i = 0; $i < $numberOfListeners; ++$i) { + $eventManager->trigger('event'); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d
", $timeEnd - $timeStart, $memEnd - $memStart); + + +$sharedManager = new \Zend\EventManager\SharedEventManager(); +$eventManager->setSharedManager($sharedManager); + +echo "Attach {$numberOfListeners} shared listeners: "; +$memStart = memory_get_usage(); +$timeStart = microtime(true); +for ($i = 0; $i < $numberOfListeners; ++$i) { + $sharedManager->attach('myid', 'event', 'emptyFunc', $i); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d
", $timeEnd - $timeStart, $memEnd - $memStart); + + +echo "Triggers {$numberOfTriggers} events: "; +$memStart = memory_get_usage(); +$timeStart = microtime(true); +for ($i = 0; $i < $numberOfListeners; ++$i) { + $eventManager->trigger('event'); +} +$timeEnd = microtime(true); +$memEnd = memory_get_usage(true); +printf("time=%f, mem=%d
", $timeEnd - $timeStart, $memEnd - $memStart); + + +printf("
Total: time=%f, mem=%d\n", microtime(true) - $totalTimeStart, memory_get_peak_usage(true)); diff --git a/library/Zend/Db/TableGateway/Feature/EventFeature/TableGatewayEvent.php b/library/Zend/Db/TableGateway/Feature/EventFeature/TableGatewayEvent.php index af7531eeffd..2ff5a07512d 100644 --- a/library/Zend/Db/TableGateway/Feature/EventFeature/TableGatewayEvent.php +++ b/library/Zend/Db/TableGateway/Feature/EventFeature/TableGatewayEvent.php @@ -133,7 +133,7 @@ public function stopPropagation($flag = true) * * @return bool */ - public function propagationIsStopped() + public function isPropagationStopped() { return false; } diff --git a/library/Zend/EventManager/AbstractListenerAggregate.php b/library/Zend/EventManager/AbstractListenerAggregate.php index 4d4a443d0d8..491d88f088d 100644 --- a/library/Zend/EventManager/AbstractListenerAggregate.php +++ b/library/Zend/EventManager/AbstractListenerAggregate.php @@ -9,26 +9,7 @@ namespace Zend\EventManager; - -/** - * Abstract aggregate listener - */ abstract class AbstractListenerAggregate implements ListenerAggregateInterface { - /** - * @var \Zend\Stdlib\CallbackHandler[] - */ - protected $listeners = array(); - - /** - * {@inheritDoc} - */ - public function detach(EventManagerInterface $events) - { - foreach ($this->listeners as $index => $callback) { - if ($events->detach($callback)) { - unset($this->listeners[$index]); - } - } - } + use ListenerAggregateTrait; } diff --git a/library/Zend/EventManager/Event.php b/library/Zend/EventManager/Event.php index 31037b9f14f..a9f0eb9ca74 100644 --- a/library/Zend/EventManager/Event.php +++ b/library/Zend/EventManager/Event.php @@ -9,7 +9,7 @@ namespace Zend\EventManager; -use ArrayAccess; +use Traversable; /** * Representation of an event @@ -19,20 +19,15 @@ */ class Event implements EventInterface { - /** - * @var string Event name - */ - protected $name; - /** * @var string|object The event target */ protected $target; /** - * @var array|ArrayAccess|object The event parameters + * @var array The event parameters */ - protected $params = array(); + protected $params = []; /** * @var bool Whether or not to stop propagation @@ -44,19 +39,12 @@ class Event implements EventInterface * * Accept a target and its parameters. * - * @param string $name Event name - * @param string|object $target - * @param array|ArrayAccess $params + * @param string|object $target + * @param array|Traversable $params */ - public function __construct($name = null, $target = null, $params = null) + public function __construct($target = null, $params = null) { - if (null !== $name) { - $this->setName($name); - } - - if (null !== $target) { - $this->setTarget($target); - } + $this->setTarget($target); if (null !== $params) { $this->setParams($params); @@ -64,21 +52,17 @@ public function __construct($name = null, $target = null, $params = null) } /** - * Get event name - * - * @return string + * {@inheritDoc} */ - public function getName() + public function setTarget($target) { - return $this->name; + $this->target = $target; } /** - * Get the event target + * {@inheritDoc} * * This may be either an object, or the name of a static method. - * - * @return string|object */ public function getTarget() { @@ -86,111 +70,47 @@ public function getTarget() } /** - * Set parameters - * - * Overwrites parameters - * - * @param array|ArrayAccess|object $params - * @return Event - * @throws Exception\InvalidArgumentException + * {@inheritDoc} */ public function setParams($params) { - if (!is_array($params) && !is_object($params)) { - throw new Exception\InvalidArgumentException(sprintf( - 'Event parameters must be an array or object; received "%s"', gettype($params) - )); + if ($params instanceof Traversable) { + $params = iterator_to_array($params); } $this->params = $params; - return $this; } /** - * Get all parameters - * - * @return array|object|ArrayAccess - */ - public function getParams() - { - return $this->params; - } - - /** - * Get an individual parameter - * - * If the parameter does not exist, the $default value will be returned. - * - * @param string|int $name - * @param mixed $default - * @return mixed + * {@inheritDoc} */ - public function getParam($name, $default = null) - { - // Check in params that are arrays or implement array access - if (is_array($this->params) || $this->params instanceof ArrayAccess) { - if (!isset($this->params[$name])) { - return $default; - } - - return $this->params[$name]; - } - - // Check in normal objects - if (!isset($this->params->{$name})) { - return $default; - } - return $this->params->{$name}; - } - - /** - * Set the event name - * - * @param string $name - * @return Event - */ - public function setName($name) + public function setParam($name, $value) { - $this->name = (string) $name; - return $this; + $this->params[$name] = $value; } /** - * Set the event target/context - * - * @param null|string|object $target - * @return Event + * {@inheritDoc} */ - public function setTarget($target) + public function getParams() { - $this->target = $target; - return $this; + return $this->params; } /** - * Set an individual parameter to a value - * - * @param string|int $name - * @param mixed $value - * @return Event + * {@inheritDoc} */ - public function setParam($name, $value) + public function getParam($name, $default = null) { - if (is_array($this->params) || $this->params instanceof ArrayAccess) { - // Arrays or objects implementing array access - $this->params[$name] = $value; - } else { - // Objects - $this->params->{$name} = $value; + if (!isset($this->params[$name])) { + return $default; } - return $this; + + return $this->params[$name]; } /** - * Stop further event propagation - * - * @param bool $flag - * @return void + * {@inheritDoc} */ public function stopPropagation($flag = true) { @@ -198,11 +118,9 @@ public function stopPropagation($flag = true) } /** - * Is propagation stopped? - * - * @return bool + * {@inheritDoc} */ - public function propagationIsStopped() + public function isPropagationStopped() { return $this->stopPropagation; } diff --git a/library/Zend/EventManager/EventInterface.php b/library/Zend/EventManager/EventInterface.php index 7974f6e9ac8..518a8ae51d2 100644 --- a/library/Zend/EventManager/EventInterface.php +++ b/library/Zend/EventManager/EventInterface.php @@ -9,7 +9,7 @@ namespace Zend\EventManager; -use ArrayAccess; +use Traversable; /** * Representation of an event @@ -17,11 +17,12 @@ interface EventInterface { /** - * Get event name + * Set the event target/context * - * @return string + * @param null|string|object $target + * @return void */ - public function getName(); + public function setTarget($target); /** * Get target/context from which event was triggered @@ -31,53 +32,37 @@ public function getName(); public function getTarget(); /** - * Get parameters passed to the event - * - * @return array|ArrayAccess - */ - public function getParams(); - - /** - * Get a single parameter by name - * - * @param string $name - * @param mixed $default Default value to return if parameter does not exist - * @return mixed - */ - public function getParam($name, $default = null); - - /** - * Set the event name + * Set event parameters (overwrite parameters) * - * @param string $name + * @param array|Traversable $params * @return void */ - public function setName($name); + public function setParams($params); /** - * Set the event target/context + * Set a single parameter by key * - * @param null|string|object $target + * @param string $name + * @param mixed $value * @return void */ - public function setTarget($target); + public function setParam($name, $value); /** - * Set event parameters + * Get parameters passed to the event * - * @param string $params - * @return void + * @return array */ - public function setParams($params); + public function getParams(); /** - * Set a single parameter by key + * Get a single parameter by name * * @param string $name - * @param mixed $value - * @return void + * @param mixed $default Default value to return if parameter does not exist + * @return mixed */ - public function setParam($name, $value); + public function getParam($name, $default = null); /** * Indicate whether or not the parent EventManagerInterface should stop propagating events @@ -92,5 +77,5 @@ public function stopPropagation($flag = true); * * @return bool */ - public function propagationIsStopped(); + public function isPropagationStopped(); } diff --git a/library/Zend/EventManager/EventManager.php b/library/Zend/EventManager/EventManager.php index de51b1e96ad..0fbe4183bb0 100644 --- a/library/Zend/EventManager/EventManager.php +++ b/library/Zend/EventManager/EventManager.php @@ -9,11 +9,8 @@ namespace Zend\EventManager; -use ArrayAccess; use ArrayObject; use Traversable; -use Zend\Stdlib\CallbackHandler; -use Zend\Stdlib\PriorityQueue; /** * Event manager: notification system @@ -21,28 +18,19 @@ * Use the EventManager when you want to create a per-instance notification * system for your objects. */ -class EventManager implements EventManagerInterface +class EventManager extends FastEventManager implements SharedEventManagerAwareInterface { - /** - * Subscribed events and their listeners - * @var array Array of PriorityQueue objects - */ - protected $events = array(); - - /** - * @var string Class representing the event being emitted - */ - protected $eventClass = 'Zend\EventManager\Event'; - /** * Identifiers, used to pull shared signals from SharedEventManagerInterface instance + * * @var array */ - protected $identifiers = array(); + protected $identifiers = []; /** * Shared event manager - * @var false|null|SharedEventManagerInterface + * + * @var null|SharedEventManagerInterface */ protected $sharedManager = null; @@ -56,208 +44,37 @@ class EventManager implements EventManagerInterface */ public function __construct($identifiers = null) { - $this->setIdentifiers($identifiers); - } - - /** - * Set the event class to utilize - * - * @param string $class - * @return EventManager - */ - public function setEventClass($class) - { - $this->eventClass = $class; - return $this; + if ($identifiers) { + $this->setIdentifiers($identifiers); + } } /** * Set shared event manager * - * @param SharedEventManagerInterface $sharedEventManager - * @return EventManager + * @param SharedEventManagerInterface $sharedEventManager + * @return void */ public function setSharedManager(SharedEventManagerInterface $sharedEventManager) { $this->sharedManager = $sharedEventManager; - StaticEventManager::setInstance($sharedEventManager); - return $this; - } - - /** - * Remove any shared event manager currently attached - * - * @return void - */ - public function unsetSharedManager() - { - $this->sharedManager = false; } /** * Get shared event manager * - * If one is not defined, but we have a static instance in - * StaticEventManager, that one will be used and set in this instance. - * - * If none is available in the StaticEventManager, a boolean false is - * returned. - * - * @return false|SharedEventManagerInterface + * @return SharedEventManagerInterface|null */ public function getSharedManager() { - // "false" means "I do not want a shared manager; don't try and fetch one" - if (false === $this->sharedManager - || $this->sharedManager instanceof SharedEventManagerInterface - ) { - return $this->sharedManager; - } - - if (!StaticEventManager::hasInstance()) { - return false; - } - - $this->sharedManager = StaticEventManager::getInstance(); return $this->sharedManager; } - /** - * Get the identifier(s) for this EventManager - * - * @return array - */ - public function getIdentifiers() - { - return $this->identifiers; - } - - /** - * Set the identifiers (overrides any currently set identifiers) - * - * @param string|int|array|Traversable $identifiers - * @return EventManager Provides a fluent interface - */ - public function setIdentifiers($identifiers) - { - if (is_array($identifiers) || $identifiers instanceof Traversable) { - $this->identifiers = array_unique((array) $identifiers); - } elseif ($identifiers !== null) { - $this->identifiers = array($identifiers); - } - return $this; - } - - /** - * Add some identifier(s) (appends to any currently set identifiers) - * - * @param string|int|array|Traversable $identifiers - * @return EventManager Provides a fluent interface - */ - public function addIdentifiers($identifiers) - { - if (is_array($identifiers) || $identifiers instanceof Traversable) { - $this->identifiers = array_unique(array_merge($this->identifiers, (array) $identifiers)); - } elseif ($identifiers !== null) { - $this->identifiers = array_unique(array_merge($this->identifiers, array($identifiers))); - } - return $this; - } - - /** - * Trigger all listeners for a given event - * - * Can emulate triggerUntil() if the last argument provided is a callback. - * - * @param string $event - * @param string|object $target Object calling emit, or symbol describing target (such as static method name) - * @param array|ArrayAccess $argv Array of arguments; typically, should be associative - * @param null|callable $callback - * @return ResponseCollection All listener return values - * @throws Exception\InvalidCallbackException - */ - public function trigger($event, $target = null, $argv = array(), $callback = null) - { - if ($event instanceof EventInterface) { - $e = $event; - $event = $e->getName(); - $callback = $target; - } elseif ($target instanceof EventInterface) { - $e = $target; - $e->setName($event); - $callback = $argv; - } elseif ($argv instanceof EventInterface) { - $e = $argv; - $e->setName($event); - $e->setTarget($target); - } else { - $e = new $this->eventClass(); - $e->setName($event); - $e->setTarget($target); - $e->setParams($argv); - } - - if ($callback && !is_callable($callback)) { - throw new Exception\InvalidCallbackException('Invalid callback provided'); - } - - // Initial value of stop propagation flag should be false - $e->stopPropagation(false); - - return $this->triggerListeners($event, $e, $callback); - } - - /** - * Trigger listeners until return value of one causes a callback to - * evaluate to true - * - * Triggers listeners until the provided callback evaluates the return - * value of one as true, or until all listeners have been executed. - * - * @param string $event - * @param string|object $target Object calling emit, or symbol describing target (such as static method name) - * @param array|ArrayAccess $argv Array of arguments; typically, should be associative - * @param callable $callback - * @return ResponseCollection - * @throws Exception\InvalidCallbackException if invalid callable provided - */ - public function triggerUntil($event, $target, $argv = null, $callback = null) - { - if ($event instanceof EventInterface) { - $e = $event; - $event = $e->getName(); - $callback = $target; - } elseif ($target instanceof EventInterface) { - $e = $target; - $e->setName($event); - $callback = $argv; - } elseif ($argv instanceof EventInterface) { - $e = $argv; - $e->setName($event); - $e->setTarget($target); - } else { - $e = new $this->eventClass(); - $e->setName($event); - $e->setTarget($target); - $e->setParams($argv); - } - - if (!is_callable($callback)) { - throw new Exception\InvalidCallbackException('Invalid callback provided'); - } - - // Initial value of stop propagation flag should be false - $e->stopPropagation(false); - - return $this->triggerListeners($event, $e, $callback); - } - /** * Attach a listener to an event * * The first argument is the event, and the next argument describes a - * callback that will respond to that event. A CallbackHandler instance - * describing the event listener combination will be returned. + * callback that will respond to that event. * * The last argument indicates a priority at which the event should be * executed. By default, this value is 1; however, you may set it for any @@ -266,285 +83,72 @@ public function triggerUntil($event, $target, $argv = null, $callback = null) * You can specify "*" for the event name. In such cases, the listener will * be triggered for every event. * - * @param string|array|ListenerAggregateInterface $event An event or array of event names. If a ListenerAggregateInterface, proxies to {@link attachAggregate()}. - * @param callable|int $callback If string $event provided, expects PHP callback; for a ListenerAggregateInterface $event, this will be the priority - * @param int $priority If provided, the priority at which to register the callable - * @return CallbackHandler|mixed CallbackHandler if attaching callable (to allow later unsubscribe); mixed if attaching aggregate - * @throws Exception\InvalidArgumentException + * @param string $eventName An event or array of event names + * @param callable $listener + * @param int $priority If provided, the priority at which to register the callable + * @return callable if attaching callable (to allow later unsubscribe) */ - public function attach($event, $callback = null, $priority = 1) + public function attach($eventName, callable $listener, $priority = 1) { - // Proxy ListenerAggregateInterface arguments to attachAggregate() - if ($event instanceof ListenerAggregateInterface) { - return $this->attachAggregate($event, $callback); - } + // The '.0' is a hack that allows to circumvent the fact that array_merge remove + // any numeric key + $this->events[$eventName][(int) $priority . '.0'][] = $listener; - // Null callback is invalid - if (null === $callback) { - throw new Exception\InvalidArgumentException(sprintf( - '%s: expects a callback; none provided', - __METHOD__ - )); - } - - // Array of events should be registered individually, and return an array of all listeners - if (is_array($event)) { - $listeners = array(); - foreach ($event as $name) { - $listeners[] = $this->attach($name, $callback, $priority); - } - return $listeners; - } - - // If we don't have a priority queue for the event yet, create one - if (empty($this->events[$event])) { - $this->events[$event] = new PriorityQueue(); - } - - // Create a callback handler, setting the event and priority in its metadata - $listener = new CallbackHandler($callback, array('event' => $event, 'priority' => $priority)); - - // Inject the callback handler into the queue - $this->events[$event]->insert($listener, $priority); return $listener; } /** - * Attach a listener aggregate - * - * Listener aggregates accept an EventManagerInterface instance, and call attach() - * one or more times, typically to attach to multiple events using local - * methods. - * - * @param ListenerAggregateInterface $aggregate - * @param int $priority If provided, a suggested priority for the aggregate to use - * @return mixed return value of {@link ListenerAggregateInterface::attach()} - */ - public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1) - { - return $aggregate->attach($this, $priority); - } - - /** - * Unsubscribe a listener from an event - * - * @param CallbackHandler|ListenerAggregateInterface $listener - * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found - * @throws Exception\InvalidArgumentException if invalid listener provided + * {@inheritDoc} */ - public function detach($listener) + public function getListeners($eventName) { - if ($listener instanceof ListenerAggregateInterface) { - return $this->detachAggregate($listener); - } + // retrieve listeners + $listeners = isset($this->events[$eventName]) ? $this->events[$eventName] : []; - if (!$listener instanceof CallbackHandler) { - throw new Exception\InvalidArgumentException(sprintf( - '%s: expected a ListenerAggregateInterface or CallbackHandler; received "%s"', - __METHOD__, - (is_object($listener) ? get_class($listener) : gettype($listener)) - )); - } + // retrieve wildcard listeners + $wildcardListeners = isset($this->events['*']) ? $this->events['*'] : []; - $event = $listener->getMetadatum('event'); - if (!$event || empty($this->events[$event])) { - return false; - } - $return = $this->events[$event]->remove($listener); - if (!$return) { - return false; - } - if (!count($this->events[$event])) { - unset($this->events[$event]); - } - return true; - } - - /** - * Detach a listener aggregate - * - * Listener aggregates accept an EventManagerInterface instance, and call detach() - * of all previously attached listeners. - * - * @param ListenerAggregateInterface $aggregate - * @return mixed return value of {@link ListenerAggregateInterface::detach()} - */ - public function detachAggregate(ListenerAggregateInterface $aggregate) - { - return $aggregate->detach($this); - } - - /** - * Retrieve all registered events - * - * @return array - */ - public function getEvents() - { - return array_keys($this->events); - } - - /** - * Retrieve all listeners for a given event - * - * @param string $event - * @return PriorityQueue - */ - public function getListeners($event) - { - if (!array_key_exists($event, $this->events)) { - return new PriorityQueue(); - } - return $this->events[$event]; - } + // retrieve shared manager listeners + $sharedListeners = (null !== $this->sharedManager) + ? $this->sharedManager->getListeners($this->identifiers, $eventName) + : []; - /** - * Clear all listeners for a given event - * - * @param string $event - * @return void - */ - public function clearListeners($event) - { - if (!empty($this->events[$event])) { - unset($this->events[$event]); - } - } + // merge + $listeners = array_merge_recursive($listeners, $wildcardListeners, $sharedListeners); + krsort($listeners, SORT_NUMERIC); - /** - * Prepare arguments - * - * Use this method if you want to be able to modify arguments from within a - * listener. It returns an ArrayObject of the arguments, which may then be - * passed to trigger() or triggerUntil(). - * - * @param array $args - * @return ArrayObject - */ - public function prepareArgs(array $args) - { - return new ArrayObject($args); + return $listeners; } /** - * Trigger listeners - * - * Actual functionality for triggering listeners, to which both trigger() and triggerUntil() - * delegate. - * - * @param string $event Event name - * @param EventInterface $e - * @param null|callable $callback - * @return ResponseCollection + * {@inheritDoc} */ - protected function triggerListeners($event, EventInterface $e, $callback = null) + public function setIdentifiers($identifiers) { - $responses = new ResponseCollection; - $listeners = $this->getListeners($event); - - // Add shared/wildcard listeners to the list of listeners, - // but don't modify the listeners object - $sharedListeners = $this->getSharedListeners($event); - $sharedWildcardListeners = $this->getSharedListeners('*'); - $wildcardListeners = $this->getListeners('*'); - if (count($sharedListeners) || count($sharedWildcardListeners) || count($wildcardListeners)) { - $listeners = clone $listeners; - - // Shared listeners on this specific event - $this->insertListeners($listeners, $sharedListeners); - - // Shared wildcard listeners - $this->insertListeners($listeners, $sharedWildcardListeners); - - // Add wildcard listeners - $this->insertListeners($listeners, $wildcardListeners); + if ($identifiers instanceof Traversable) { + $identifiers = iterator_to_array($identifiers); } - foreach ($listeners as $listener) { - $listenerCallback = $listener->getCallback(); - - // Trigger the listener's callback, and push its result onto the - // response collection - $responses->push(call_user_func($listenerCallback, $e)); - - // If the event was asked to stop propagating, do so - if ($e->propagationIsStopped()) { - $responses->setStopped(true); - break; - } - - // If the result causes our validation callback to return true, - // stop propagation - if ($callback && call_user_func($callback, $responses->last())) { - $responses->setStopped(true); - break; - } - } - - return $responses; + $this->identifiers = (array) $identifiers; } /** - * Get list of all listeners attached to the shared event manager for - * identifiers registered by this instance - * - * @param string $event - * @return array + * {@inheritDoc} */ - protected function getSharedListeners($event) + public function addIdentifiers($identifiers) { - if (!$sharedManager = $this->getSharedManager()) { - return array(); + if ($identifiers instanceof Traversable) { + $identifiers = iterator_to_array($identifiers); } - $identifiers = $this->getIdentifiers(); - //Add wildcard id to the search, if not already added - if (!in_array('*', $identifiers)) { - $identifiers[] = '*'; - } - $sharedListeners = array(); - - foreach ($identifiers as $id) { - if (!$listeners = $sharedManager->getListeners($id, $event)) { - continue; - } - - if (!is_array($listeners) && !($listeners instanceof Traversable)) { - continue; - } - - foreach ($listeners as $listener) { - if (!$listener instanceof CallbackHandler) { - continue; - } - $sharedListeners[] = $listener; - } - } - - return $sharedListeners; + $this->identifiers = array_unique(array_merge($this->identifiers, $identifiers)); } /** - * Add listeners to the master queue of listeners - * - * Used to inject shared listeners and wildcard listeners. - * - * @param PriorityQueue $masterListeners - * @param PriorityQueue $listeners - * @return void + * {@inheritDoc} */ - protected function insertListeners($masterListeners, $listeners) + public function getIdentifiers() { - foreach ($listeners as $listener) { - $priority = $listener->getMetadatum('priority'); - if (null === $priority) { - $priority = 1; - } elseif (is_array($priority)) { - // If we have an array, likely using PriorityQueue. Grab first - // element of the array, as that's the actual priority. - $priority = array_shift($priority); - } - $masterListeners->insert($listener, $priority); - } + return $this->identifiers; } } diff --git a/library/Zend/EventManager/EventManagerAwareInterface.php b/library/Zend/EventManager/EventManagerAwareInterface.php index 16d8ba921be..720d36ac6ca 100644 --- a/library/Zend/EventManager/EventManagerAwareInterface.php +++ b/library/Zend/EventManager/EventManagerAwareInterface.php @@ -10,9 +10,9 @@ namespace Zend\EventManager; /** - * Interface to automate setter injection for an EventManager instance + * Interface for objects that are aware of an event manager */ -interface EventManagerAwareInterface extends EventsCapableInterface +interface EventManagerAwareInterface { /** * Inject an EventManager instance @@ -21,4 +21,13 @@ interface EventManagerAwareInterface extends EventsCapableInterface * @return void */ public function setEventManager(EventManagerInterface $eventManager); + + /** + * Retrieve the event manager + * + * Lazy-loads an EventManager instance if none registered. + * + * @return EventManagerInterface + */ + public function getEventManager(); } diff --git a/library/Zend/EventManager/EventManagerAwareTrait.php b/library/Zend/EventManager/EventManagerAwareTrait.php index 97012be8377..6928603164b 100644 --- a/library/Zend/EventManager/EventManagerAwareTrait.php +++ b/library/Zend/EventManager/EventManagerAwareTrait.php @@ -9,9 +9,45 @@ namespace Zend\EventManager; -use \Zend\EventManager\ProvidesEvents; - trait EventManagerAwareTrait { - use ProvidesEvents; + /** + * @var EventManagerInterface + */ + protected $eventManager; + + /** + * Set the event manager instance used by this context + * + * @param EventManagerInterface $eventManager + * @return void + */ + public function setEventManager(EventManagerInterface $eventManager) + { + if ($eventManager instanceof SharedEventManagerAwareInterface) { + $eventIdentifiers = isset($this->eventIdentifiers) ? (array) $this->eventIdentifiers : []; + + $eventManager->setIdentifiers( + array_unique(array_merge([__CLASS__, get_class($this)], $eventIdentifiers) + )); + } + + $this->eventManager = $eventManager; + } + + /** + * Retrieve the event manager + * + * Lazy-loads an EventManager instance if none registered. + * + * @return EventManagerInterface + */ + public function getEventManager() + { + if (null === $this->eventManager) { + $this->setEventManager(new EventManager()); + } + + return $this->eventManager; + } } diff --git a/library/Zend/EventManager/EventManagerInterface.php b/library/Zend/EventManager/EventManagerInterface.php index e17d21b0f04..e9da80e17ea 100644 --- a/library/Zend/EventManager/EventManagerInterface.php +++ b/library/Zend/EventManager/EventManagerInterface.php @@ -10,135 +10,81 @@ namespace Zend\EventManager; use Traversable; -use Zend\Stdlib\CallbackHandler; /** - * Interface for messengers + * Interface for event manager */ -interface EventManagerInterface extends SharedEventManagerAwareInterface +interface EventManagerInterface { /** - * Trigger an event - * - * Should allow handling the following scenarios: - * - Passing Event object only - * - Passing event name and Event object only - * - Passing event name, target, and Event object - * - Passing event name, target, and array|ArrayAccess of arguments - * - * Can emulate triggerUntil() if the last argument provided is a callback. - * - * @param string $event - * @param object|string $target - * @param array|object $argv - * @param null|callable $callback - * @return ResponseCollection - */ - public function trigger($event, $target = null, $argv = array(), $callback = null); - - /** - * Trigger an event until the given callback returns a boolean false - * - * Should allow handling the following scenarios: - * - Passing Event object and callback only - * - Passing event name, Event object, and callback only - * - Passing event name, target, Event object, and callback - * - Passing event name, target, array|ArrayAccess of arguments, and callback + * Attach a listener to an event * - * @param string $event - * @param object|string $target - * @param array|object $argv - * @param callable $callback - * @return ResponseCollection + * @param string $eventName + * @param callable $listener + * @param int $priority Priority at which to register listener + * @return callable */ - public function triggerUntil($event, $target, $argv = null, $callback = null); + public function attach($eventName, callable $listener, $priority = 1); /** - * Attach a listener to an event + * Attach a listener aggregate * - * @param string $event - * @param callable $callback - * @param int $priority Priority at which to register listener - * @return CallbackHandler + * @param ListenerAggregateInterface $aggregate + * @param int $priority If provided, a suggested priority for the aggregate to use + * @return mixed */ - public function attach($event, $callback = null, $priority = 1); + public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1); /** * Detach an event listener * - * @param CallbackHandler|ListenerAggregateInterface $listener + * @param callable $listener + * @param string $eventName optional to speed up process * @return bool */ - public function detach($listener); - - /** - * Get a list of events for which this collection has listeners - * - * @return array - */ - public function getEvents(); + public function detach(callable $listener, $eventName = ''); /** - * Retrieve a list of listeners registered to a given event + * Detach a listener aggregate * - * @param string $event - * @return array|object - */ - public function getListeners($event); - - /** - * Clear all listeners for a given event + * Listener aggregates accept an EventManagerInterface instance, and call detach() + * of all previously attached listeners * - * @param string $event - * @return void + * @param ListenerAggregateInterface $aggregate + * @return bool */ - public function clearListeners($event); + public function detachAggregate(ListenerAggregateInterface $aggregate); /** - * Set the event class to utilize + * Trigger an event (optionally until using a callback returns a boolean true) * - * @param string $class - * @return EventManagerInterface + * @param string $eventName + * @param EventInterface|null $event + * @param callable|null $callback + * @return ResponseCollection */ - public function setEventClass($class); + public function trigger($eventName, EventInterface $event = null, callable $callback = null); /** - * Get the identifier(s) for this EventManager + * Get a list of event names for which this collection has listeners * * @return array */ - public function getIdentifiers(); - - /** - * Set the identifiers (overrides any currently set identifiers) - * - * @param string|int|array|Traversable $identifiers - * @return EventManagerInterface - */ - public function setIdentifiers($identifiers); - - /** - * Add some identifier(s) (appends to any currently set identifiers) - * - * @param string|int|array|Traversable $identifiers - * @return EventManagerInterface - */ - public function addIdentifiers($identifiers); + public function getEventNames(); /** - * Attach a listener aggregate + * Retrieve a list of listeners registered to a given event * - * @param ListenerAggregateInterface $aggregate - * @param int $priority If provided, a suggested priority for the aggregate to use - * @return mixed return value of {@link ListenerAggregateInterface::attach()} + * @param string $eventName + * @return array */ - public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1); + public function getListeners($eventName); /** - * Detach a listener aggregate + * Clear all listeners for a given event * - * @param ListenerAggregateInterface $aggregate - * @return mixed return value of {@link ListenerAggregateInterface::detach()} + * @param string $eventName + * @return void */ - public function detachAggregate(ListenerAggregateInterface $aggregate); + public function clearListeners($eventName); } diff --git a/library/Zend/EventManager/EventsCapableInterface.php b/library/Zend/EventManager/EventsCapableInterface.php deleted file mode 100644 index 401744598ec..00000000000 --- a/library/Zend/EventManager/EventsCapableInterface.php +++ /dev/null @@ -1,25 +0,0 @@ -events[$eventName][(int) $priority][] = $listener; + $this->orderedByPriority[$eventName] = false; + + return $listener; + } + + /** + * {@inheritDoc} + */ + public function attachAggregate(ListenerAggregateInterface $aggregate, $priority = 1) + { + return $aggregate->attach($this, $priority); + } + + /** + * {@inheritDoc} + */ + public function detach(callable $listener, $eventName = '') + { + if ($eventName !== null && isset($this->events[$eventName])) { + foreach ($this->events[$eventName] as &$listeners) { + if (($key = array_search($listener, $listeners, true)) !== false) { + unset($listeners[$key]); + return true; + } + } + + return false; + } + + foreach ($this->events as &$event) { + foreach ($event as &$listeners) { + if (($key = array_search($listener, $listeners, true)) !== false) { + unset($listeners[$key]); + return true; + } + } + } + + return false; + } + + /** + * {@inheritDoc} + */ + public function detachAggregate(ListenerAggregateInterface $aggregate) + { + return $aggregate->detach($this); + } + + /** + * {@inheritDoc} + */ + public function trigger($eventName, EventInterface $event = null, callable $callback = null) + { + // Initial value of stop propagation flag should be false + $event = $event ?: new Event(); + $event->stopPropagation(false); + + $responses = []; + $listeners = $this->getListeners($eventName); + + foreach ($listeners as $listenersByPriority) { + foreach ($listenersByPriority as $listener) { + $lastResponse = $listener($event); + $responses[] = $lastResponse; + + if (($callback && $callback($lastResponse) || $event->isPropagationStopped())) { + $responseCollection = new ResponseCollection($responses); + $responseCollection->setStopped(true); + + return $responseCollection; + } + } + } + + return new ResponseCollection($responses); + } + + /** + * {@inheritDoc} + */ + public function getEventNames() + { + return array_keys($this->events); + } + + /** + * {@inheritDoc} + */ + public function getListeners($eventName) + { + if (!isset($this->events[$eventName])) { + return []; + } + + // Make sure to return listeners ordered by priority + // If `events[$eventName]` exists we are sure that `orderedByPriority[$eventName]` exists, too + if (!$this->orderedByPriority[$eventName]) { + krsort($this->events[$eventName], SORT_NUMERIC); + $this->orderedByPriority[$eventName] = true; + } + + return $this->events[$eventName]; + } + + /** + * {@inheritDoc} + */ + public function clearListeners($eventName) + { + unset($this->events[$eventName]); + } +} diff --git a/library/Zend/EventManager/Filter/FilterInterface.php b/library/Zend/EventManager/Filter/FilterInterface.php deleted file mode 100644 index 2e4b1c6a11c..00000000000 --- a/library/Zend/EventManager/Filter/FilterInterface.php +++ /dev/null @@ -1,65 +0,0 @@ -setExtractFlags(self::EXTR_BOTH); - - // Iterate and remove any matches - $removed = false; - $items = array(); - $this->rewind(); - while (!$this->isEmpty()) { - $item = $this->extract(); - if ($item['data'] === $datum) { - $removed = true; - continue; - } - $items[] = $item; - } - - // Repopulate - foreach ($items as $item) { - $this->insert($item['data'], $item['priority']); - } - - $this->setExtractFlags(self::EXTR_DATA); - return $removed; - } - - /** - * Iterate the next filter in the chain - * - * Iterates and calls the next filter in the chain. - * - * @param mixed $context - * @param array $params - * @param FilterIterator $chain - * @return mixed - */ - public function next($context = null, array $params = array(), $chain = null) - { - if (empty($context) || $chain->isEmpty()) { - return; - } - - $next = $this->extract(); - if (!$next instanceof CallbackHandler) { - return; - } - - $return = call_user_func($next->getCallback(), $context, $params, $chain); - return $return; - } -} diff --git a/library/Zend/EventManager/FilterChain.php b/library/Zend/EventManager/FilterChain.php deleted file mode 100644 index a2703602866..00000000000 --- a/library/Zend/EventManager/FilterChain.php +++ /dev/null @@ -1,120 +0,0 @@ -filters = new Filter\FilterIterator(); - } - - /** - * Apply the filters - * - * Begins iteration of the filters. - * - * @param mixed $context Object under observation - * @param mixed $argv Associative array of arguments - * @return mixed - */ - public function run($context, array $argv = array()) - { - $chain = clone $this->getFilters(); - - if ($chain->isEmpty()) { - return; - } - - $next = $chain->extract(); - if (!$next instanceof CallbackHandler) { - return; - } - - return call_user_func($next->getCallback(), $context, $argv, $chain); - } - - /** - * Connect a filter to the chain - * - * @param callable $callback PHP Callback - * @param int $priority Priority in the queue at which to execute; defaults to 1 (higher numbers == higher priority) - * @return CallbackHandler (to allow later unsubscribe) - * @throws Exception\InvalidCallbackException - */ - public function attach($callback, $priority = 1) - { - if (empty($callback)) { - throw new Exception\InvalidCallbackException('No callback provided'); - } - $filter = new CallbackHandler($callback, array('priority' => $priority)); - $this->filters->insert($filter, $priority); - return $filter; - } - - /** - * Detach a filter from the chain - * - * @param CallbackHandler $filter - * @return bool Returns true if filter found and unsubscribed; returns false otherwise - */ - public function detach(CallbackHandler $filter) - { - return $this->filters->remove($filter); - } - - /** - * Retrieve all filters - * - * @return Filter\FilterIterator - */ - public function getFilters() - { - return $this->filters; - } - - /** - * Clear all filters - * - * @return void - */ - public function clearFilters() - { - $this->filters = new Filter\FilterIterator(); - } - - /** - * Return current responses - * - * Only available while the chain is still being iterated. Returns the - * current ResponseCollection. - * - * @return null|ResponseCollection - */ - public function getResponses() - { - return null; - } -} diff --git a/library/Zend/EventManager/GlobalEventManager.php b/library/Zend/EventManager/GlobalEventManager.php deleted file mode 100644 index 047dd18cf42..00000000000 --- a/library/Zend/EventManager/GlobalEventManager.php +++ /dev/null @@ -1,135 +0,0 @@ -trigger($event, $context, $argv); - } - - /** - * Trigger listeners until return value of one causes a callback to evaluate - * to true. - * - * @param string $event - * @param string|object $context - * @param array|object $argv - * @param callable $callback - * @return ResponseCollection - */ - public static function triggerUntil($event, $context, $argv, $callback) - { - return static::getEventCollection()->triggerUntil($event, $context, $argv, $callback); - } - - /** - * Attach a listener to an event - * - * @param string $event - * @param callable $callback - * @param int $priority - * @return CallbackHandler - */ - public static function attach($event, $callback, $priority = 1) - { - return static::getEventCollection()->attach($event, $callback, $priority); - } - - /** - * Detach a callback from a listener - * - * @param CallbackHandler $listener - * @return bool - */ - public static function detach(CallbackHandler $listener) - { - return static::getEventCollection()->detach($listener); - } - - /** - * Retrieve list of events this object manages - * - * @return array - */ - public static function getEvents() - { - return static::getEventCollection()->getEvents(); - } - - /** - * Retrieve all listeners for a given event - * - * @param string $event - * @return PriorityQueue|array - */ - public static function getListeners($event) - { - return static::getEventCollection()->getListeners($event); - } - - /** - * Clear all listeners for a given event - * - * @param string $event - * @return void - */ - public static function clearListeners($event) - { - static::getEventCollection()->clearListeners($event); - } -} diff --git a/library/Zend/EventManager/ListenerAggregateInterface.php b/library/Zend/EventManager/ListenerAggregateInterface.php index 4d10e71da02..57af03ac514 100644 --- a/library/Zend/EventManager/ListenerAggregateInterface.php +++ b/library/Zend/EventManager/ListenerAggregateInterface.php @@ -26,8 +26,7 @@ interface ListenerAggregateInterface * implementation will pass this to the aggregate. * * @param EventManagerInterface $events - * - * @return void + * @return mixed */ public function attach(EventManagerInterface $events); @@ -35,8 +34,7 @@ public function attach(EventManagerInterface $events); * Detach all previously attached listeners * * @param EventManagerInterface $events - * - * @return void + * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found */ public function detach(EventManagerInterface $events); } diff --git a/library/Zend/EventManager/ListenerAggregateTrait.php b/library/Zend/EventManager/ListenerAggregateTrait.php index fabedc03cd8..b159c5a15d4 100644 --- a/library/Zend/EventManager/ListenerAggregateTrait.php +++ b/library/Zend/EventManager/ListenerAggregateTrait.php @@ -16,19 +16,24 @@ trait ListenerAggregateTrait { /** - * @var \Zend\Stdlib\CallbackHandler[] + * @var callable[] */ - protected $listeners = array(); + protected $listeners = []; /** * {@inheritDoc} */ public function detach(EventManagerInterface $events) { - foreach ($this->listeners as $index => $callback) { - if ($events->detach($callback)) { + $found = false; + + foreach ($this->listeners as $index => $listener) { + if ($events->detach($listener)) { unset($this->listeners[$index]); + $found = true; } } + + return $found; } } diff --git a/library/Zend/EventManager/ProvidesEvents.php b/library/Zend/EventManager/ProvidesEvents.php deleted file mode 100644 index ea46333a1f4..00000000000 --- a/library/Zend/EventManager/ProvidesEvents.php +++ /dev/null @@ -1,63 +0,0 @@ -eventIdentifier)) { - if ((is_string($this->eventIdentifier)) - || (is_array($this->eventIdentifier)) - || ($this->eventIdentifier instanceof Traversable) - ) { - $identifiers = array_unique(array_merge($identifiers, (array) $this->eventIdentifier)); - } elseif (is_object($this->eventIdentifier)) { - $identifiers[] = $this->eventIdentifier; - } - // silently ignore invalid eventIdentifier types - } - $events->setIdentifiers($identifiers); - $this->events = $events; - return $this; - } - - /** - * Retrieve the event manager - * - * Lazy-loads an EventManager instance if none registered. - * - * @return EventManagerInterface - */ - public function getEventManager() - { - if (!$this->events instanceof EventManagerInterface) { - $this->setEventManager(new EventManager()); - } - return $this->events; - } -} diff --git a/library/Zend/EventManager/README.md b/library/Zend/EventManager/README.md index 474b103d7be..49297cfd808 100644 --- a/library/Zend/EventManager/README.md +++ b/library/Zend/EventManager/README.md @@ -1,7 +1,7 @@ -EventManager Component from ZF2 +EventManager Component from ZF3 =============================== -This is the EventManager component for ZF2. +This is the EventManager component for ZF3. - File issues at https://github.com/zendframework/zf2/issues - Create pull requests against https://github.com/zendframework/zf2 diff --git a/library/Zend/EventManager/ResponseCollection.php b/library/Zend/EventManager/ResponseCollection.php index 5131d1d402a..364901b2f55 100644 --- a/library/Zend/EventManager/ResponseCollection.php +++ b/library/Zend/EventManager/ResponseCollection.php @@ -9,15 +9,36 @@ namespace Zend\EventManager; -use SplStack; +use ArrayIterator; +use Countable; +use IteratorAggregate; /** * Collection of signal handler return values + * + * We used to use a SplStack in Zend Framework 2, but using an array allows us some interesting + * optimizations */ -class ResponseCollection extends SplStack +class ResponseCollection implements Countable, IteratorAggregate { + /** + * @var array + */ + protected $responses = []; + + /** + * @var bool + */ protected $stopped = false; + /** + * @param array $responses + */ + public function __construct(array $responses = []) + { + $this->responses = $responses; + } + /** * Did the last response provided trigger a short circuit of the stack? * @@ -32,12 +53,11 @@ public function stopped() * Mark the collection as stopped (or its opposite) * * @param bool $flag - * @return ResponseCollection + * @return void */ public function setStopped($flag) { $this->stopped = (bool) $flag; - return $this; } /** @@ -47,7 +67,8 @@ public function setStopped($flag) */ public function first() { - return parent::bottom(); + reset($this->responses); + return current($this->responses); } /** @@ -60,10 +81,11 @@ public function first() */ public function last() { - if (count($this) === 0) { + if (empty($this->responses)) { return null; } - return parent::top(); + + return end($this->responses); } /** @@ -74,11 +96,22 @@ public function last() */ public function contains($value) { - foreach ($this as $response) { - if ($response === $value) { - return true; - } - } - return false; + return in_array($value, $this->responses, true); + } + + /** + * {@inheritDoc} + */ + public function count() + { + return count($this->responses); + } + + /** + * {@inheritDoc} + */ + public function getIterator() + { + return new ArrayIterator($this->responses); } } diff --git a/library/Zend/EventManager/SharedEventAggregateAwareInterface.php b/library/Zend/EventManager/SharedEventAggregateAwareInterface.php deleted file mode 100644 index 69b2b7915a4..00000000000 --- a/library/Zend/EventManager/SharedEventAggregateAwareInterface.php +++ /dev/null @@ -1,34 +0,0 @@ - - * $sharedEventManager = new SharedEventManager(); - * $sharedEventManager->attach( - * array('My\Resource\AbstractResource', 'My\Resource\EntityResource'), - * 'getAll', - * function ($e) use ($cache) { - * if (!$id = $e->getParam('id', false)) { - * return; - * } - * if (!$data = $cache->load(get_class($resource) . '::getOne::' . $id )) { - * return; - * } - * return $data; - * } - * ); - * + * identifying components * - * @param string|array $id Identifier(s) for event emitting component(s) - * @param string $event - * @param callable $callback PHP Callback - * @param int $priority Priority at which listener should execute - * @return CallbackHandler|array Either CallbackHandler or array of CallbackHandlers + * @param string|array $identifiers Identifier(s) for event emitting component(s) + * @param string $eventName + * @param callable $listener PHP Callback + * @param int $priority Priority at which listener should execute + * @return callable */ - public function attach($id, $event, $callback, $priority = 1) + public function attach($identifiers, $eventName, callable $listener, $priority = 1) { - $ids = (array) $id; - $listeners = array(); - foreach ($ids as $id) { - if (!array_key_exists($id, $this->identifiers)) { - $this->identifiers[$id] = new EventManager($id); - } - $listeners[] = $this->identifiers[$id]->attach($event, $callback, $priority); - } - if (count($listeners) > 1) { - return $listeners; + foreach ((array) $identifiers as $identifier) { + $this->identifiers[$identifier][$eventName][(int) $priority . '.0'][] = $listener; } - return $listeners[0]; + + return $listener; } /** @@ -84,7 +58,7 @@ public function attach($id, $event, $callback, $priority = 1) * * @param SharedListenerAggregateInterface $aggregate * @param int $priority If provided, a suggested priority for the aggregate to use - * @return mixed return value of {@link ListenerAggregateInterface::attachShared()} + * @return mixed return value of {@link SharedListenerAggregateInterface::attachShared()} */ public function attachAggregate(SharedListenerAggregateInterface $aggregate, $priority = 1) { @@ -94,16 +68,24 @@ public function attachAggregate(SharedListenerAggregateInterface $aggregate, $pr /** * Detach a listener from an event offered by a given resource * - * @param string|int $id - * @param CallbackHandler $listener + * @param string|int $identifier + * @param callable $listener * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found */ - public function detach($id, CallbackHandler $listener) + public function detach($identifier, callable $listener) { - if (!array_key_exists($id, $this->identifiers)) { - return false; + if (isset($this->identifiers[$identifier])) { + foreach ($this->identifiers[$identifier] as &$event) { + foreach ($event as &$listeners) { + if (($key = array_search($listener, $listeners, true)) !== false) { + unset($listeners[$key]); + return true; + } + } + } } - return $this->identifiers[$id]->detach($listener); + + return false; } /** @@ -121,56 +103,80 @@ public function detachAggregate(SharedListenerAggregateInterface $aggregate) } /** - * Retrieve all registered events for a given resource + * Retrieve all listeners for the given identifiers and for a specific event * - * @param string|int $id + * @param string[] $identifiers + * @param string $eventName * @return array */ - public function getEvents($id) + public function getListeners(array $identifiers, $eventName) { - if (!array_key_exists($id, $this->identifiers)) { - //Check if there are any id wildcards listeners - if ('*' != $id && array_key_exists('*', $this->identifiers)) { - return $this->identifiers['*']->getEvents(); + $listeners = []; + + // we detect if there is a wildcard identifier so that we can retrieve its listeners, and + // remove the conditional in the foreach + $wildcardIdentifierListeners = isset($identifiers['*']) ? $identifiers['*'] : null; + unset($identifiers['*']); + + foreach ($identifiers as $identifier) { + if (isset($this->identifiers[$identifier][$eventName]) && $eventName !== '*') { + $listeners = array_merge_recursive($listeners, $this->identifiers[$identifier][$eventName]); + } + + if (isset($this->identifiers[$identifier]['*'])) { + $listeners = array_merge_recursive($listeners, $this->identifiers[$identifier]['*']); + } + } + + // merge listeners attached to wildcard identifiers + if (null !== $wildcardIdentifierListeners) { + if (isset($wildcardIdentifierListeners[$eventName]) && $eventName !== '*') { + $listeners = array_merge_recursive($listeners, $wildcardIdentifierListeners[$eventName]); + } + + if (isset($wildcardIdentifierListeners['*'])) { + $listeners = array_merge_recursive($listeners, $wildcardIdentifierListeners['*']); } - return false; } - return $this->identifiers[$id]->getEvents(); + + return $listeners; } /** - * Retrieve all listeners for a given identifier and event + * Clear all listeners for the given identifiers and optionally for a specific event * - * @param string|int $id - * @param string|int $event - * @return false|PriorityQueue + * @param string[] $identifiers + * @param null|string $eventName + * @return void */ - public function getListeners($id, $event) + public function clearListeners(array $identifiers, $eventName = null) { - if (!array_key_exists($id, $this->identifiers)) { - return false; + foreach ($identifiers as $identifier) { + if (null === $eventName) { + unset($this->identifiers[$identifier]); + } else { + unset($this->identifiers[$identifier][$eventName]); + } } - return $this->identifiers[$id]->getListeners($event); } /** - * Clear all listeners for a given identifier, optionally for a specific event + * Retrieve all registered events for a given resource * - * @param string|int $id - * @param null|string $event - * @return bool + * @param string|int $identifier + * @return array */ - public function clearListeners($id, $event = null) + public function getEventNames($identifier) { - if (!array_key_exists($id, $this->identifiers)) { - return false; - } + if (!isset($this->identifiers[$identifier])) { + // Check if there are any id wildcards listeners + if ('*' !== $identifier && isset($this->identifiers['*'])) { + return array_keys($this->identifiers['*']); + } - if (null === $event) { - unset($this->identifiers[$id]); - return true; + return false; } - return $this->identifiers[$id]->clearListeners($event); + return array_keys($this->identifiers[$identifier]); } } diff --git a/library/Zend/EventManager/SharedEventManagerAwareInterface.php b/library/Zend/EventManager/SharedEventManagerAwareInterface.php index c982948a689..55d4d321ef8 100644 --- a/library/Zend/EventManager/SharedEventManagerAwareInterface.php +++ b/library/Zend/EventManager/SharedEventManagerAwareInterface.php @@ -9,6 +9,8 @@ namespace Zend\EventManager; +use Traversable; + /** * Interface to automate setter injection for a SharedEventManagerInterface instance */ @@ -30,9 +32,25 @@ public function setSharedManager(SharedEventManagerInterface $sharedEventManager public function getSharedManager(); /** - * Remove any shared collections + * Set the identifiers (overrides any currently set identifiers) + * + * @param array|Traversable $identifiers + * @return void + */ + public function setIdentifiers($identifiers); + + /** + * Add some identifier(s) (appends to any currently set identifiers) * + * @param array|Traversable $identifiers * @return void */ - public function unsetSharedManager(); + public function addIdentifiers($identifiers); + + /** + * Get the identifier(s) for this EventManager + * + * @return array + */ + public function getIdentifiers(); } diff --git a/library/Zend/EventManager/SharedEventManagerInterface.php b/library/Zend/EventManager/SharedEventManagerInterface.php index ee4e0fec902..d2bb559d3dc 100644 --- a/library/Zend/EventManager/SharedEventManagerInterface.php +++ b/library/Zend/EventManager/SharedEventManagerInterface.php @@ -9,57 +9,71 @@ namespace Zend\EventManager; -use Zend\Stdlib\CallbackHandler; -use Zend\Stdlib\PriorityQueue; - /** * Interface for shared event listener collections */ interface SharedEventManagerInterface { /** - * Retrieve all listeners for a given identifier and event + * Attach a listener to an event * - * @param string|int $id - * @param string|int $event - * @return false|PriorityQueue + * @param array $identifiers Identifier(s) for event emitting component(s) + * @param string $eventName + * @param callable $listener PHP Callback + * @param int $priority Priority at which listener should execute + * @return void */ - public function getListeners($id, $event); + public function attach($identifiers, $eventName, callable $listener, $priority = 1); /** - * Attach a listener to an event + * Attach a listener aggregate * - * @param string|array $id Identifier(s) for event emitting component(s) - * @param string $event - * @param callable $callback PHP Callback - * @param int $priority Priority at which listener should execute - * @return void + * @param SharedListenerAggregateInterface $aggregate + * @param int $priority If provided, a suggested priority for the aggregate to use + * @return mixed return value of {@link SharedListenerAggregateInterface::attachShared()} */ - public function attach($id, $event, $callback, $priority = 1); + public function attachAggregate(SharedListenerAggregateInterface $aggregate, $priority = 1); /** * Detach a listener from an event offered by a given resource * - * @param string|int $id - * @param CallbackHandler $listener + * @param string|int $identifier + * @param callable $listener * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found */ - public function detach($id, CallbackHandler $listener); + public function detach($identifier, callable $listener); /** - * Retrieve all registered events for a given resource + * Detach a listener aggregate * - * @param string|int $id + * @param SharedListenerAggregateInterface $aggregate + * @return mixed return value of {@link SharedListenerAggregateInterface::detachShared()} + */ + public function detachAggregate(SharedListenerAggregateInterface $aggregate); + + /** + * Retrieve all listeners for the given identifiers and event for a specific event + * + * @param string[] $identifiers + * @param string $eventName * @return array */ - public function getEvents($id); + public function getListeners(array $identifiers, $eventName); + + /** + * Clear all listeners for the given identifiers and optionally for a specific event + * + * @param string[] $identifiers + * @param null|string $eventName + * @return void + */ + public function clearListeners(array $identifiers, $eventName = null); /** - * Clear all listeners for a given identifier, optionally for a specific event + * Retrieve all registered events for a given resource * - * @param string|int $id - * @param null|string $event - * @return bool + * @param string|int $identifier + * @return array */ - public function clearListeners($id, $event = null); + public function getEventNames($identifier); } diff --git a/library/Zend/EventManager/SharedListenerAggregateInterface.php b/library/Zend/EventManager/SharedListenerAggregateInterface.php index 0fd127022bd..33b641f5c63 100644 --- a/library/Zend/EventManager/SharedListenerAggregateInterface.php +++ b/library/Zend/EventManager/SharedListenerAggregateInterface.php @@ -26,6 +26,7 @@ interface SharedListenerAggregateInterface * implementation will pass this to the aggregate. * * @param SharedEventManagerInterface $events + * @return mixed */ public function attachShared(SharedEventManagerInterface $events); @@ -33,6 +34,7 @@ public function attachShared(SharedEventManagerInterface $events); * Detach all previously attached listeners * * @param SharedEventManagerInterface $events + * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found */ public function detachShared(SharedEventManagerInterface $events); } diff --git a/library/Zend/EventManager/StaticEventManager.php b/library/Zend/EventManager/StaticEventManager.php deleted file mode 100644 index 4458efafb2f..00000000000 --- a/library/Zend/EventManager/StaticEventManager.php +++ /dev/null @@ -1,82 +0,0 @@ -=5.3.3", - "zendframework/zend-stdlib": "self.version" + "php": ">=5.4" }, "extra": { "branch-alias": { - "dev-master": "2.2-dev", - "dev-develop": "2.3-dev" + "dev-master": "3.0-dev", + "dev-develop": "3.1-dev" } } } diff --git a/library/Zend/Stdlib/CallbackHandler.php b/library/Zend/Stdlib/CallbackHandler.php index f1ac4a65b36..bdec2d95d30 100644 --- a/library/Zend/Stdlib/CallbackHandler.php +++ b/library/Zend/Stdlib/CallbackHandler.php @@ -32,35 +32,18 @@ class CallbackHandler */ protected $metadata; - /** - * PHP version is greater as 5.4rc1? - * @var bool - */ - protected static $isPhp54; - /** * Constructor * - * @param string|array|object|callable $callback PHP callback - * @param array $metadata Callback metadata + * @param Callable $callback PHP callback + * @param array $metadata Callback metadata */ - public function __construct($callback, array $metadata = array()) + public function __construct(Callable $callback, array $metadata = array()) { - $this->metadata = $metadata; - $this->registerCallback($callback); - } + $this->metadata = $metadata; - /** - * Registers the callback provided in the constructor - * - * @param callable $callback - * @throws Exception\InvalidCallbackException - * @return void - */ - protected function registerCallback($callback) - { - if (!is_callable($callback)) { - throw new Exception\InvalidCallbackException('Invalid callback provided; not callable'); + if (is_string($callback) && strpos($callback, '::') !== false) { + $callback = explode('::', $callback, 2); } $this->callback = $callback; @@ -69,7 +52,7 @@ protected function registerCallback($callback) /** * Retrieve registered callback * - * @return callable + * @return Callable */ public function getCallback() { @@ -85,53 +68,26 @@ public function getCallback() public function call(array $args = array()) { $callback = $this->getCallback(); - - // Minor performance tweak, if the callback gets called more than once - if (!isset(static::$isPhp54)) { - static::$isPhp54 = version_compare(PHP_VERSION, '5.4.0rc1', '>='); - } - $argCount = count($args); - if (static::$isPhp54 && is_string($callback)) { - $result = $this->validateStringCallbackFor54($callback); - - if ($result !== true && $argCount <= 3) { - $callback = $result; - // Minor performance tweak, if the callback gets called more - // than once - $this->callback = $result; - } - } - // Minor performance tweak; use call_user_func() until > 3 arguments // reached switch ($argCount) { case 0: - if (static::$isPhp54) { - return $callback(); - } - return call_user_func($callback); + return $callback(); case 1: - if (static::$isPhp54) { - return $callback(array_shift($args)); - } - return call_user_func($callback, array_shift($args)); + return $callback(array_shift($args)); case 2: $arg1 = array_shift($args); $arg2 = array_shift($args); - if (static::$isPhp54) { - return $callback($arg1, $arg2); - } - return call_user_func($callback, $arg1, $arg2); + + return $callback($arg1, $arg2); case 3: $arg1 = array_shift($args); $arg2 = array_shift($args); $arg3 = array_shift($args); - if (static::$isPhp54) { - return $callback($arg1, $arg2, $arg3); - } - return call_user_func($callback, $arg1, $arg2, $arg3); + + return $callback($arg1, $arg2, $arg3); default: return call_user_func_array($callback, $args); } @@ -165,54 +121,6 @@ public function getMetadata() */ public function getMetadatum($name) { - if (array_key_exists($name, $this->metadata)) { - return $this->metadata[$name]; - } - return null; - } - - /** - * Validate a static method call - * - * Validates that a static method call in PHP 5.4 will actually work - * - * @param string $callback - * @return true|array - * @throws Exception\InvalidCallbackException if invalid - */ - protected function validateStringCallbackFor54($callback) - { - if (!strstr($callback, '::')) { - return true; - } - - list($class, $method) = explode('::', $callback, 2); - - if (!class_exists($class)) { - throw new Exception\InvalidCallbackException(sprintf( - 'Static method call "%s" refers to a class that does not exist', - $callback - )); - } - - $r = new ReflectionClass($class); - if (!$r->hasMethod($method)) { - throw new Exception\InvalidCallbackException(sprintf( - 'Static method call "%s" refers to a method that does not exist', - $callback - )); - } - $m = $r->getMethod($method); - if (!$m->isStatic()) { - throw new Exception\InvalidCallbackException(sprintf( - 'Static method call "%s" refers to a method that is not static', - $callback - )); - } - - // returning a non boolean value may not be nice for a validate method, - // but that allows the usage of a static string callback without using - // the call_user_func function. - return array($class, $method); + return isset($this->metadata[$name]) ? $this->metadata[$name] : null; } } diff --git a/library/Zend/Stdlib/Exception/InvalidCallbackException.php b/library/Zend/Stdlib/Exception/InvalidCallbackException.php deleted file mode 100644 index 30e97e83bda..00000000000 --- a/library/Zend/Stdlib/Exception/InvalidCallbackException.php +++ /dev/null @@ -1,17 +0,0 @@ -listener = new MockAbstractListenerAggregate(); - } - - /** - * @covers \Zend\EventManager\AbstractListenerAggregate::detach - */ - public function testDetach() - { - $eventManager = $this->getMock('Zend\\EventManager\\EventManagerInterface'); - $unrelatedEventManager = $this->getMock('Zend\\EventManager\\EventManagerInterface'); - $callbackHandlers = array(); - $test = $this; - - $eventManager - ->expects($this->exactly(2)) - ->method('attach') - ->will($this->returnCallback(function () use (&$callbackHandlers, $test) { - return $callbackHandlers[] = $test->getMock('Zend\\Stdlib\\CallbackHandler', array(), array(), '', false); - })); - - $this->listener->attach($eventManager); - $this->assertSame($callbackHandlers, $this->listener->getCallbacks()); - - $this->listener->detach($unrelatedEventManager); - - $this->assertSame($callbackHandlers, $this->listener->getCallbacks()); - - $eventManager - ->expects($this->exactly(2)) - ->method('detach') - ->with($this->callback(function ($callbackHandler) use ($callbackHandlers) { - return in_array($callbackHandler, $callbackHandlers, true); - })) - ->will($this->returnValue(true)); - - $this->listener->detach($eventManager); - $this->assertEmpty($this->listener->getCallbacks()); - } -} diff --git a/tests/ZendTest/EventManager/Asset/EventManagerAwareObject.php b/tests/ZendTest/EventManager/Asset/EventManagerAwareObject.php new file mode 100644 index 00000000000..0bf434b3f55 --- /dev/null +++ b/tests/ZendTest/EventManager/Asset/EventManagerAwareObject.php @@ -0,0 +1,29 @@ +getObjectForTrait('\Zend\EventManager\EventManagerAwareTrait'); - - $this->assertAttributeEquals(null, 'events', $object); - - $eventManager = new EventManager; - - $object->setEventManager($eventManager); - - $this->assertAttributeEquals($eventManager, 'events', $object); - } - - public function testGetEventManager() - { - $object = $this->getObjectForTrait('\Zend\EventManager\EventManagerAwareTrait'); - - $this->assertInstanceOf('\Zend\EventManager\EventManagerInterface', $object->getEventManager()); - - $eventManager = new EventManager; + $eventManager = new EventManager(); + $object = new EventManagerAwareObject(); $object->setEventManager($eventManager); - $this->assertSame($eventManager, $object->getEventManager()); + $identifiers = $eventManager->getIdentifiers(); + $this->assertContains(get_class($object), $identifiers); + $this->assertContains('MyIdentifier', $identifiers, 'Assert class identifiers are merged'); } } diff --git a/tests/ZendTest/EventManager/EventManagerTest.php b/tests/ZendTest/EventManager/EventManagerTest.php index 380dc86355f..f0e7a72fbc4 100644 --- a/tests/ZendTest/EventManager/EventManagerTest.php +++ b/tests/ZendTest/EventManager/EventManagerTest.php @@ -10,668 +10,236 @@ namespace ZendTest\EventManager; -use ArrayIterator; -use stdClass; use Zend\EventManager\Event; use Zend\EventManager\EventInterface; use Zend\EventManager\EventManager; -use Zend\EventManager\ResponseCollection; use Zend\EventManager\SharedEventManager; -use Zend\EventManager\StaticEventManager; -use Zend\Stdlib\CallbackHandler; -/** - * @category Zend - * @package Zend_EventManager - * @subpackage UnitTests - * @group Zend_EventManager - */ class EventManagerTest extends \PHPUnit_Framework_TestCase { - public function setUp() + public function testEventManagerHasNoIdentifiersByDefault() { - StaticEventManager::resetInstance(); - - if (isset($this->message)) { - unset($this->message); - } - $this->events = new EventManager; - StaticEventManager::resetInstance(); + $eventManager = new EventManager(); + $this->assertEmpty($eventManager->getIdentifiers()); } - public function tearDown() + public function testCanSetIdentifiersThroughConstructor() { - StaticEventManager::resetInstance(); - } + $identifiers = ['identifier1', 'identifier2']; + $eventManager = new EventManager($identifiers); - public function testAttachShouldReturnCallbackHandler() - { - $listener = $this->events->attach('test', array($this, __METHOD__)); - $this->assertTrue($listener instanceof CallbackHandler); + $this->assertEquals($identifiers, $eventManager->getIdentifiers()); } - public function testAttachShouldAddListenerToEvent() + public function testSetIdentifiersReplace() { - $listener = $this->events->attach('test', array($this, __METHOD__)); - $listeners = $this->events->getListeners('test'); - $this->assertEquals(1, count($listeners)); - $this->assertContains($listener, $listeners); + $eventManager = new EventManager(['identifier1']); + $eventManager->setIdentifiers(['identifier2']); + + $this->assertEquals(['identifier2'], $eventManager->getIdentifiers()); } - public function testAttachShouldAddEventIfItDoesNotExist() + public function testAddIdentifiersAppend() { - $events = $this->events->getEvents(); - $this->assertTrue(empty($events), var_export($events, 1)); - $listener = $this->events->attach('test', array($this, __METHOD__)); - $events = $this->events->getEvents(); - $this->assertFalse(empty($events)); - $this->assertContains('test', $events); + $eventManager = new EventManager(['identifier1']); + $eventManager->addIdentifiers(['identifier2', 'identifier2']); + + $this->assertEquals(['identifier1', 'identifier2'], $eventManager->getIdentifiers()); } - public function testAllowsPassingArrayOfEventNamesWhenAttaching() + public function testEventManagerHasNoSharedEventManagerByDefault() { - $callback = function ($e) { - return $e->getName(); - }; - $this->events->attach(array('foo', 'bar'), $callback); - - foreach (array('foo', 'bar') as $event) { - $listeners = $this->events->getListeners($event); - $this->assertTrue(count($listeners) > 0); - foreach ($listeners as $listener) { - $this->assertSame($callback, $listener->getCallback()); - } - } + $eventManager = new EventManager(); + $this->assertNull($eventManager->getSharedManager()); } - public function testPassingArrayOfEventNamesWhenAttachingReturnsArrayOfCallbackHandlers() + public function testCanAttachListener() { - $callback = function ($e) { - return $e->getName(); - }; - $listeners = $this->events->attach(array('foo', 'bar'), $callback); + $eventManager = new EventManager(); + $count = 0; - $this->assertInternalType('array', $listeners); + $eventManager->attach('event', function() use (&$count) { $count++; }); + $eventManager->attach('event', function() use (&$count) { $count++; }); - foreach ($listeners as $listener) { - $this->assertInstanceOf('Zend\Stdlib\CallbackHandler', $listener); - $this->assertSame($callback, $listener->getCallback()); - } - } + $eventManager->trigger('unknownEvent'); + $this->assertEquals(0, $count); - public function testDetachShouldRemoveListenerFromEvent() - { - $listener = $this->events->attach('test', array($this, __METHOD__)); - $listeners = $this->events->getListeners('test'); - $this->assertContains($listener, $listeners); - $this->events->detach($listener); - $listeners = $this->events->getListeners('test'); - $this->assertNotContains($listener, $listeners); - } + $eventManager->trigger('event'); + $this->assertEquals(2, $count); - public function testDetachShouldReturnFalseIfEventDoesNotExist() - { - $listener = $this->events->attach('test', array($this, __METHOD__)); - $this->events->clearListeners('test'); - $this->assertFalse($this->events->detach($listener)); - } + // Test clearing listeners + $eventManager->clearListeners('unknownEvent'); + $eventManager->trigger('event'); + $this->assertEquals(4, $count); - public function testDetachShouldReturnFalseIfListenerDoesNotExist() - { - $listener1 = $this->events->attach('test', array($this, __METHOD__)); - $this->events->clearListeners('test'); - $listener2 = $this->events->attach('test', array($this, 'handleTestEvent')); - $this->assertFalse($this->events->detach($listener1)); + $eventManager->clearListeners('event'); + $eventManager->trigger('event'); + $this->assertEquals(4, $count); } - public function testRetrievingAttachedListenersShouldReturnEmptyArrayWhenEventDoesNotExist() + public function testCanAttachAggregate() { - $listeners = $this->events->getListeners('test'); - $this->assertEquals(0, count($listeners)); - } + $listenerAggregate = $this->getMock('Zend\EventManager\ListenerAggregateInterface'); + $eventManager = new EventManager(); - public function testTriggerShouldTriggerAttachedListeners() - { - $listener = $this->events->attach('test', array($this, 'handleTestEvent')); - $this->events->trigger('test', $this, array('message' => 'test message')); - $this->assertEquals('test message', $this->message); - } + $listenerAggregate->expects($this->once()) + ->method('attach') + ->with($eventManager, 1); - public function testTriggerShouldReturnAllListenerReturnValues() - { - $this->events->attach('string.transform', function ($e) { - $string = $e->getParam('string', '__NOT_FOUND__'); - return trim($string); - }); - $this->events->attach('string.transform', function ($e) { - $string = $e->getParam('string', '__NOT_FOUND__'); - return str_rot13($string); - }); - $responses = $this->events->trigger('string.transform', $this, array('string' => ' foo ')); - $this->assertTrue($responses instanceof ResponseCollection); - $this->assertEquals(2, $responses->count()); - $this->assertEquals('foo', $responses->first()); - $this->assertEquals(\str_rot13(' foo '), $responses->last()); + $eventManager->attachAggregate($listenerAggregate); } - public function testTriggerUntilShouldReturnAsSoonAsCallbackReturnsTrue() + public function testDetachUnknownListener() { - $this->events->attach('foo.bar', function ($e) { - $string = $e->getParam('string', ''); - $search = $e->getParam('search', '?'); - return strpos($string, $search); - }); - $this->events->attach('foo.bar', function ($e) { - $string = $e->getParam('string', ''); - $search = $e->getParam('search', '?'); - return strstr($string, $search); - }); - $responses = $this->events->triggerUntil( - 'foo.bar', - $this, - array('string' => 'foo', 'search' => 'f'), - array($this, 'evaluateStringCallback') - ); - $this->assertTrue($responses instanceof ResponseCollection); - $this->assertSame(0, $responses->last()); - } + $eventManager = new EventManager(); - public function testTriggerResponseCollectionContains() - { - $this->events->attach('string.transform', function ($e) { - $string = $e->getParam('string', ''); - return trim($string); - }); - $this->events->attach('string.transform', function ($e) { - $string = $e->getParam('string', ''); - return str_rot13($string); - }); - $responses = $this->events->trigger('string.transform', $this, array('string' => ' foo ')); - $this->assertTrue($responses->contains('foo')); - $this->assertTrue($responses->contains(\str_rot13(' foo '))); - $this->assertFalse($responses->contains(' foo ')); + $this->assertFalse($eventManager->detach(function() {})); + $this->assertFalse($eventManager->detach(function() {}, 'event')); } - public function handleTestEvent($e) + public function testCanDetachListenerWithoutEventName() { - $message = $e->getParam('message', '__NOT_FOUND__'); - $this->message = $message; - } + $eventManager = new EventManager(); + $count = 0; - public function evaluateStringCallback($value) - { - return (!$value); - } + $listener = $eventManager->attach('event', function() use (&$count) { $count++; }); + $this->assertTrue($eventManager->detach($listener)); - public function testTriggerUntilShouldMarkResponseCollectionStoppedWhenConditionMet() - { - $this->events->attach('foo.bar', function () { return 'bogus'; }, 4); - $this->events->attach('foo.bar', function () { return 'nada'; }, 3); - $this->events->attach('foo.bar', function () { return 'found'; }, 2); - $this->events->attach('foo.bar', function () { return 'zero'; }, 1); - $responses = $this->events->triggerUntil('foo.bar', $this, array(), function ($result) { - return ($result === 'found'); - }); - $this->assertTrue($responses instanceof ResponseCollection); - $this->assertTrue($responses->stopped()); - $result = $responses->last(); - $this->assertEquals('found', $result); - $this->assertFalse($responses->contains('zero')); - } + $eventManager->trigger('event'); - public function testTriggerUntilShouldMarkResponseCollectionStoppedWhenConditionMetByLastListener() - { - $this->events->attach('foo.bar', function () { return 'bogus'; }); - $this->events->attach('foo.bar', function () { return 'nada'; }); - $this->events->attach('foo.bar', function () { return 'zero'; }); - $this->events->attach('foo.bar', function () { return 'found'; }); - $responses = $this->events->triggerUntil('foo.bar', $this, array(), function ($result) { - return ($result === 'found'); - }); - $this->assertTrue($responses instanceof ResponseCollection); - $this->assertTrue($responses->stopped()); - $this->assertEquals('found', $responses->last()); + $this->assertEquals(0, $count); } - public function testResponseCollectionIsNotStoppedWhenNoCallbackMatchedByTriggerUntil() + public function testCanDetachListenerWithEventName() { - $this->events->attach('foo.bar', function () { return 'bogus'; }, 4); - $this->events->attach('foo.bar', function () { return 'nada'; }, 3); - $this->events->attach('foo.bar', function () { return 'found'; }, 2); - $this->events->attach('foo.bar', function () { return 'zero'; }, 1); - $responses = $this->events->triggerUntil('foo.bar', $this, array(), function ($result) { - return ($result === 'never found'); - }); - $this->assertTrue($responses instanceof ResponseCollection); - $this->assertFalse($responses->stopped()); - $this->assertEquals('zero', $responses->last()); - } + $eventManager = new EventManager(); + $count = 0; - public function testCanAttachListenerAggregate() - { - $aggregate = new TestAsset\MockAggregate(); - $this->events->attachAggregate($aggregate); - $events = $this->events->getEvents(); - foreach (array('foo.bar', 'foo.baz') as $event) { - $this->assertContains($event, $events); - } - } + $listener = $eventManager->attach('event', function() use (&$count) { $count++; }); + $this->assertTrue($eventManager->detach($listener), 'event'); - public function testCanAttachListenerAggregateViaAttach() - { - $aggregate = new TestAsset\MockAggregate(); - $this->events->attach($aggregate); - $events = $this->events->getEvents(); - foreach (array('foo.bar', 'foo.baz') as $event) { - $this->assertContains($event, $events); - } - } + $eventManager->trigger('event'); - public function testAttachAggregateReturnsAttachOfListenerAggregate() - { - $aggregate = new TestAsset\MockAggregate(); - $method = $this->events->attachAggregate($aggregate); - $this->assertSame('ZendTest\EventManager\TestAsset\MockAggregate::attach', $method); + $this->assertEquals(0, $count); } - public function testCanDetachListenerAggregates() + public function testCanDetachAggregate() { - // setup some other event listeners, to ensure appropriate items are detached - $listenerFooBar1 = $this->events->attach('foo.bar', function () { - return true; - }); - $listenerFooBar2 = $this->events->attach('foo.bar', function () { - return true; - }); - $listenerFooBaz1 = $this->events->attach('foo.baz', function () { - return true; - }); - $listenerOther = $this->events->attach('other', function () { - return true; - }); - - $aggregate = new TestAsset\MockAggregate(); - $this->events->attachAggregate($aggregate); - $this->events->detachAggregate($aggregate); - $events = $this->events->getEvents(); - foreach (array('foo.bar', 'foo.baz', 'other') as $event) { - $this->assertContains($event, $events); - } - - $listeners = $this->events->getListeners('foo.bar'); - $this->assertEquals(2, count($listeners)); - $this->assertContains($listenerFooBar1, $listeners); - $this->assertContains($listenerFooBar2, $listeners); - - $listeners = $this->events->getListeners('foo.baz'); - $this->assertEquals(1, count($listeners)); - $this->assertContains($listenerFooBaz1, $listeners); - - $listeners = $this->events->getListeners('other'); - $this->assertEquals(1, count($listeners)); - $this->assertContains($listenerOther, $listeners); - } + $listenerAggregate = $this->getMock('Zend\EventManager\ListenerAggregateInterface'); + $eventManager = new EventManager(); - public function testCanDetachListenerAggregatesViaDetach() - { - // setup some other event listeners, to ensure appropriate items are detached - $listenerFooBar1 = $this->events->attach('foo.bar', function () { - return true; - }); - $listenerFooBar2 = $this->events->attach('foo.bar', function () { - return true; - }); - $listenerFooBaz1 = $this->events->attach('foo.baz', function () { - return true; - }); - $listenerOther = $this->events->attach('other', function () { - return true; - }); - - $aggregate = new TestAsset\MockAggregate(); - $this->events->attach($aggregate); - $this->events->detach($aggregate); - $events = $this->events->getEvents(); - foreach (array('foo.bar', 'foo.baz', 'other') as $event) { - $this->assertContains($event, $events); - } - - $listeners = $this->events->getListeners('foo.bar'); - $this->assertEquals(2, count($listeners)); - $this->assertContains($listenerFooBar1, $listeners); - $this->assertContains($listenerFooBar2, $listeners); - - $listeners = $this->events->getListeners('foo.baz'); - $this->assertEquals(1, count($listeners)); - $this->assertContains($listenerFooBaz1, $listeners); - - $listeners = $this->events->getListeners('other'); - $this->assertEquals(1, count($listeners)); - $this->assertContains($listenerOther, $listeners); - } + $listenerAggregate->expects($this->once()) + ->method('detach') + ->with($eventManager); - public function testDetachAggregateReturnsDetachOfListenerAggregate() - { - $aggregate = new TestAsset\MockAggregate(); - $this->events->attachAggregate($aggregate); - $method = $this->events->detachAggregate($aggregate); - $this->assertSame('ZendTest\EventManager\TestAsset\MockAggregate::detach', $method); + $eventManager->detachAggregate($listenerAggregate); } - public function testAttachAggregateAcceptsOptionalPriorityValue() + public function testExtractEventNames() { - $aggregate = new TestAsset\MockAggregate(); - $this->events->attachAggregate($aggregate, 1); - $this->assertEquals(1, $aggregate->priority); - } + $eventManager = new EventManager(); - public function testAttachAggregateAcceptsOptionalPriorityValueViaAttachCallbackArgument() - { - $aggregate = new TestAsset\MockAggregate(); - $this->events->attach($aggregate, 1); - $this->assertEquals(1, $aggregate->priority); - } + $eventManager->attach('event1', function() {}); + $eventManager->attach('event2', function() {}); - public function testCallingEventsStopPropagationMethodHaltsEventEmission() - { - $this->events->attach('foo.bar', function ($e) { return 'bogus'; }, 4); - $this->events->attach('foo.bar', function ($e) { $e->stopPropagation(true); return 'nada'; }, 3); - $this->events->attach('foo.bar', function ($e) { return 'found'; }, 2); - $this->events->attach('foo.bar', function ($e) { return 'zero'; }, 1); - $responses = $this->events->trigger('foo.bar', $this, array()); - $this->assertTrue($responses instanceof ResponseCollection); - $this->assertTrue($responses->stopped()); - $this->assertEquals('nada', $responses->last()); - $this->assertTrue($responses->contains('bogus')); - $this->assertFalse($responses->contains('found')); - $this->assertFalse($responses->contains('zero')); + $this->assertEquals(['event1', 'event2'], $eventManager->getEventNames()); } - public function testCanAlterParametersWithinAEvent() + public function testCanTriggerListenersByPriority() { - $this->events->attach('foo.bar', function ($e) { $e->setParam('foo', 'bar'); }); - $this->events->attach('foo.bar', function ($e) { $e->setParam('bar', 'baz'); }); - $this->events->attach('foo.bar', function ($e) { - $foo = $e->getParam('foo', '__NO_FOO__'); - $bar = $e->getParam('bar', '__NO_BAR__'); - return $foo . ":" . $bar; - }); - $responses = $this->events->trigger('foo.bar', $this, array()); - $this->assertEquals('bar:baz', $responses->last()); - } + $eventManager = new EventManager(); - public function testParametersArePassedToEventByReference() - { - $params = array( 'foo' => 'bar', 'bar' => 'baz'); - $args = $this->events->prepareArgs($params); - $this->events->attach('foo.bar', function ($e) { $e->setParam('foo', 'FOO'); }); - $this->events->attach('foo.bar', function ($e) { $e->setParam('bar', 'BAR'); }); - $responses = $this->events->trigger('foo.bar', $this, $args); - $this->assertEquals('FOO', $args['foo']); - $this->assertEquals('BAR', $args['bar']); - } + // When using listeners with same priority, assert first one is executed first + $chain = ''; + $eventManager->attach('event', function() use (&$chain) { $chain .= '1'; }); + $eventManager->attach('event', function() use (&$chain) { $chain .= '2'; }); + $eventManager->trigger('event'); - public function testCanPassObjectForEventParameters() - { - $params = (object) array( 'foo' => 'bar', 'bar' => 'baz'); - $this->events->attach('foo.bar', function ($e) { $e->setParam('foo', 'FOO'); }); - $this->events->attach('foo.bar', function ($e) { $e->setParam('bar', 'BAR'); }); - $responses = $this->events->trigger('foo.bar', $this, $params); - $this->assertEquals('FOO', $params->foo); - $this->assertEquals('BAR', $params->bar); - } + $this->assertEquals('12', $chain); - public function testCanPassEventObjectAsSoleArgumentToTrigger() - { - $event = new Event(); - $event->setName(__FUNCTION__); - $event->setTarget($this); - $event->setParams(array('foo' => 'bar')); - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - $responses = $this->events->trigger($event); - $this->assertSame($event, $responses->last()); - } + // Assert priority is respected + $chain = ''; + $eventManager->clearListeners('event'); + $eventManager->attach('event', function() use (&$chain) { $chain .= '1'; }, 50); + $eventManager->attach('event', function() use (&$chain) { $chain .= '3'; }, -50); + $eventManager->attach('event', function() use (&$chain) { $chain .= '2'; }, 0); + $eventManager->trigger('event'); - public function testCanPassEventNameAndEventObjectAsSoleArgumentsToTrigger() - { - $event = new Event(); - $event->setTarget($this); - $event->setParams(array('foo' => 'bar')); - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - $responses = $this->events->trigger(__FUNCTION__, $event); - $this->assertSame($event, $responses->last()); - $this->assertEquals(__FUNCTION__, $event->getName()); - } + $this->assertEquals('123', $chain); - public function testCanPassEventObjectAsArgvToTrigger() - { - $event = new Event(); - $event->setParams(array('foo' => 'bar')); - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - $responses = $this->events->trigger(__FUNCTION__, $this, $event); - $this->assertSame($event, $responses->last()); - $this->assertEquals(__FUNCTION__, $event->getName()); - $this->assertSame($this, $event->getTarget()); - } + // Assert wildcard is always executed, and respect priority + $chain = ''; + $eventManager->clearListeners('event'); + $eventManager->attach('*', function() use (&$chain) { $chain .= '2'; }, -500); + $eventManager->attach('event', function() use (&$chain) { $chain .= '1'; }, -50); + $eventManager->trigger('event'); - public function testCanPassEventObjectAndCallbackAsSoleArgumentsToTriggerUntil() - { - $event = new Event(); - $event->setName(__FUNCTION__); - $event->setTarget($this); - $event->setParams(array('foo' => 'bar')); - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - $responses = $this->events->triggerUntil($event, function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); - $this->assertSame($event, $responses->last()); + $this->assertEquals('12', $chain); } - public function testCanPassEventNameAndEventObjectAndCallbackAsSoleArgumentsToTriggerUntil() + public function testCanTriggerListenersWithSharedManager() { - $event = new Event(); - $event->setTarget($this); - $event->setParams(array('foo' => 'bar')); - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - $responses = $this->events->triggerUntil(__FUNCTION__, $event, function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); - $this->assertSame($event, $responses->last()); - $this->assertEquals(__FUNCTION__, $event->getName()); - } + $eventManager = new EventManager(['identifier']); + $sharedEventManager = new SharedEventManager(); - public function testCanPassEventObjectAsArgvToTriggerUntil() - { - $event = new Event(); - $event->setParams(array('foo' => 'bar')); - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - $responses = $this->events->triggerUntil(__FUNCTION__, $this, $event, function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); - $this->assertSame($event, $responses->last()); - $this->assertEquals(__FUNCTION__, $event->getName()); - $this->assertSame($this, $event->getTarget()); - } + $eventManager->setSharedManager($sharedEventManager); - public function testTriggerCanTakeAnOptionalCallbackArgumentToEmulateTriggerUntil() - { - $this->events->attach(__FUNCTION__, function ($e) { - return $e; - }); - - // Four scenarios: - // First: normal signature: - $responses = $this->events->trigger(__FUNCTION__, $this, array(), function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); - - // Second: Event as $argv parameter: - $event = new Event(); - $responses = $this->events->trigger(__FUNCTION__, $this, $event, function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); - - // Third: Event as $target parameter: - $event = new Event(); - $event->setTarget($this); - $responses = $this->events->trigger(__FUNCTION__, $event, function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); - - // Fourth: Event as $event parameter: - $event = new Event(); - $event->setTarget($this); - $event->setName(__FUNCTION__); - $responses = $this->events->trigger($event, function ($r) { - return ($r instanceof EventInterface); - }); - $this->assertTrue($responses->stopped()); + // } - public function testDuplicateIdentifiersAreNotRegistered() + /** + * This test assert that if an event manager contains listeners with same priority for event name, + * wildcard and shared manager, those listeners are executed in an expected order (first event, then + * wildcard, then shared manager) + */ + public function testAssertOrder() { - $events = new EventManager(array(__CLASS__, get_class($this))); - $identifiers = $events->getIdentifiers(); - $this->assertSame(count($identifiers), 1); - $this->assertSame($identifiers[0], __CLASS__); - $events->addIdentifiers(__CLASS__); - $this->assertSame(count($identifiers), 1); - $this->assertSame($identifiers[0], __CLASS__); - } + $eventManager = new EventManager(['identifier']); + $sharedEventManager = new SharedEventManager(); + $chain = ''; - public function testIdentifierGetterSettersWorkWithStrings() - { - $identifier1 = 'foo'; - $identifiers = array($identifier1); - $this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->setIdentifiers($identifier1)); - $this->assertSame($this->events->getIdentifiers(), $identifiers); - $identifier2 = 'baz'; - $identifiers = array($identifier1, $identifier2); - $this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->addIdentifiers($identifier2)); - $this->assertSame($this->events->getIdentifiers(), $identifiers); - } + $eventManager->setSharedManager($sharedEventManager); - public function testIdentifierGetterSettersWorkWithArrays() - { - $identifiers = array('foo', 'bar'); - $this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->setIdentifiers($identifiers)); - $this->assertSame($this->events->getIdentifiers(), $identifiers); - $identifiers[] = 'baz'; - $this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->addIdentifiers($identifiers)); - - // This is done because the keys doesn't matter, just the values - $expectedIdentifiers = $this->events->getIdentifiers(); - sort($expectedIdentifiers); - sort($identifiers); - $this->assertSame($expectedIdentifiers, $identifiers); - } + $eventManager->attach('*', function() use (&$chain) { $chain .= '2'; }); + $eventManager->attach('event', function() use (&$chain) { $chain .= '1'; }); + $sharedEventManager->attach('identifier', 'event', function() use (&$chain) { $chain .= '3'; }); - public function testIdentifierGetterSettersWorkWithTraversables() - { - $identifiers = new ArrayIterator(array('foo', 'bar')); - $this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->setIdentifiers($identifiers)); - $this->assertSame($this->events->getIdentifiers(), (array) $identifiers); - $identifiers = new ArrayIterator(array('foo', 'bar', 'baz')); - $this->assertInstanceOf('Zend\EventManager\EventManager', $this->events->addIdentifiers($identifiers)); - - // This is done because the keys doesn't matter, just the values - $expectedIdentifiers = $this->events->getIdentifiers(); - sort($expectedIdentifiers); - $identifiers = (array) $identifiers; - sort($identifiers); - $this->assertSame($expectedIdentifiers, $identifiers); - } + $eventManager->trigger('event'); - public function testListenersAttachedWithWildcardAreTriggeredForAllEvents() - { - $test = new stdClass; - $test->events = array(); - $callback = function ($e) use ($test) { - $test->events[] = $e->getName(); - }; - - $this->events->attach('*', $callback); - foreach (array('foo', 'bar', 'baz') as $event) { - $this->events->trigger($event); - $this->assertContains($event, $test->events); - } + $this->assertEquals('123', $chain); } - public function testSettingSharedEventManagerSetsStaticEventManagerInstance() + public function testCanStopPropagationUsingEventObject() { - $shared = new SharedEventManager(); - $this->events->setSharedManager($shared); - $this->assertSame($shared, $this->events->getSharedManager()); - $this->assertSame($shared, StaticEventManager::getInstance()); - } + $event = new Event(); + $eventManager = new EventManager(); + $chain = ''; - public function testSharedEventManagerAttachReturnsCallbackHandler() - { - $shared = new SharedEventManager; - $callbackHandler = $shared->attach( - 'foo', - 'bar', - function ($e) { - return true; - } - ); - $this->assertTrue($callbackHandler instanceof CallbackHandler); - } + $eventManager->attach('event', function(EventInterface $event) use (&$chain) { + $chain .= '1'; + $event->stopPropagation(true); + }, 50); + $eventManager->attach('event', function() use (&$chain) { $chain .= '2'; }); - public function testDoesNotCreateStaticInstanceIfNonePresent() - { - StaticEventManager::resetInstance(); - $this->assertFalse($this->events->getSharedManager()); + $response = $eventManager->trigger('event', $event); + + $this->assertTrue($event->isPropagationStopped()); + $this->assertTrue($response->stopped()); + $this->assertEquals('1', $chain); } - public function testTriggerSetsStopPropagationFlagToFalse() + public function testCanStopPropagationUsingCallback() { - $marker = (object) array('propagationIsStopped' => true); - $this->events->attach('foo', function ($e) use ($marker) { - $marker->propagationIsStopped = $e->propagationIsStopped(); - }); + $event = new Event(); + $eventManager = new EventManager(); + $chain = ''; - $event = new Event(); - $event->stopPropagation(true); - $this->events->trigger('foo', $event); + $eventManager->attach('event', function() use (&$chain) { $chain .= '1'; }); + $eventManager->attach('event', function() use (&$chain) { $chain .= '2'; }); - $this->assertFalse($marker->propagationIsStopped); - $this->assertFalse($event->propagationIsStopped()); - } + $response = $eventManager->trigger('event', $event, function() { return true; }); - public function testTriggerUntilSetsStopPropagationFlagToFalse() - { - $marker = (object) array('propagationIsStopped' => true); - $this->events->attach('foo', function ($e) use ($marker) { - $marker->propagationIsStopped = $e->propagationIsStopped(); - }); - - $criteria = function ($r) { - return false; - }; - $event = new Event(); - $event->stopPropagation(true); - $this->events->triggerUntil('foo', $event, $criteria); - - $this->assertFalse($marker->propagationIsStopped); - $this->assertFalse($event->propagationIsStopped()); + $this->assertTrue($response->stopped()); + $this->assertEquals('1', $chain); } } diff --git a/tests/ZendTest/EventManager/EventTest.php b/tests/ZendTest/EventManager/EventTest.php new file mode 100644 index 00000000000..d328ceb0bf9 --- /dev/null +++ b/tests/ZendTest/EventManager/EventTest.php @@ -0,0 +1,77 @@ +assertSame($target, $event->getTarget()); + $this->assertEquals($params, $event->getParams()); + } + + public function paramsProvider() + { + return array( + array( + 'foo' => 'bar', + 'baz' => 'cat' + ), + array( + new \ArrayIterator(array( + 'foo' => 'bar', + 'baz' => 'cat' + )) + ) + ); + } + + /** + * @dataProvider paramsProvider + */ + public function testSetParams($params) + { + $event = new Event(); + $event->setParams($params); + + if ($params instanceof Traversable) { + $params = iterator_to_array($params); + } + + $this->assertEquals($params, $event->getParams()); + } + + public function testCanGetDefaultParam() + { + $event = new Event(); + + $event->setParam('foo', 'bar'); + $this->assertEquals('bar', $event->getParam('foo')); + + $this->assertEquals('default', $event->getParam('baz', 'default')); + } + + public function testAssertPropagationIsStoppedByDefault() + { + $event = new Event(); + $this->assertFalse($event->isPropagationStopped()); + + $event->stopPropagation(true); + $this->assertTrue($event->isPropagationStopped()); + } +} diff --git a/tests/ZendTest/EventManager/FilterChainTest.php b/tests/ZendTest/EventManager/FilterChainTest.php deleted file mode 100644 index b0cb741d0b3..00000000000 --- a/tests/ZendTest/EventManager/FilterChainTest.php +++ /dev/null @@ -1,146 +0,0 @@ -message)) { - unset($this->message); - } - $this->filterchain = new FilterChain; - } - - public function testSubscribeShouldReturnCallbackHandler() - { - $handle = $this->filterchain->attach(array( $this, __METHOD__ )); - $this->assertTrue($handle instanceof CallbackHandler); - } - - public function testSubscribeShouldAddCallbackHandlerToFilters() - { - $handler = $this->filterchain->attach(array($this, __METHOD__)); - $handlers = $this->filterchain->getFilters(); - $this->assertEquals(1, count($handlers)); - $this->assertTrue($handlers->contains($handler)); - } - - public function testDetachShouldRemoveCallbackHandlerFromFilters() - { - $handle = $this->filterchain->attach(array( $this, __METHOD__ )); - $handles = $this->filterchain->getFilters(); - $this->assertTrue($handles->contains($handle)); - $this->filterchain->detach($handle); - $handles = $this->filterchain->getFilters(); - $this->assertFalse($handles->contains($handle)); - } - - public function testDetachShouldReturnFalseIfCallbackHandlerDoesNotExist() - { - $handle1 = $this->filterchain->attach(array( $this, __METHOD__ )); - $this->filterchain->clearFilters(); - $handle2 = $this->filterchain->attach(array( $this, 'handleTestTopic' )); - $this->assertFalse($this->filterchain->detach($handle1)); - } - - public function testRetrievingAttachedFiltersShouldReturnEmptyArrayWhenNoFiltersExist() - { - $handles = $this->filterchain->getFilters(); - $this->assertEquals(0, count($handles)); - } - - public function testFilterChainShouldReturnLastResponse() - { - $this->filterchain->attach(function ($context, $params, $chain) { - if (isset($params['string'])) { - $params['string'] = trim($params['string']); - } - $return = $chain->next($context, $params, $chain); - return $return; - }); - $this->filterchain->attach(function ($context, array $params) { - $string = isset($params['string']) ? $params['string'] : ''; - return str_rot13($string); - }); - $value = $this->filterchain->run($this, array('string' => ' foo ')); - $this->assertEquals(str_rot13(trim(' foo ')), $value); - } - - public function testFilterIsPassedContextAndArguments() - { - $this->filterchain->attach(array( $this, 'filterTestCallback1' )); - $obj = (object) array('foo' => 'bar', 'bar' => 'baz'); - $value = $this->filterchain->run($this, array('object' => $obj)); - $this->assertEquals('filtered', $value); - $this->assertEquals('filterTestCallback1', $this->message); - $this->assertEquals('foobarbaz', $obj->foo); - } - - public function testInterceptingFilterShouldReceiveChain() - { - $this->filterchain->attach(array($this, 'filterReceivalCallback')); - $this->filterchain->run($this); - } - - public function testFilteringStopsAsSoonAsAFilterFailsToCallNext() - { - $this->filterchain->attach(function ($context, $params, $chain) { - if (isset($params['string'])) { - $params['string'] = trim($params['string']); - } - return $chain->next($context, $params, $chain); - }, 10000); - $this->filterchain->attach(function ($context, array $params) { - $string = isset($params['string']) ? $params['string'] : ''; - return str_rot13($string); - }, 1000); - $this->filterchain->attach(function ($context, $params, $chain) { - $string = isset($params['string']) ? $params['string'] : ''; - return hash('md5', $string); - }, 100); - $value = $this->filterchain->run($this, array('string' => ' foo ')); - $this->assertEquals(str_rot13(trim(' foo ')), $value); - } - - public function handleTestTopic($message) - { - $this->message = $message; - } - - public function filterTestCallback1($context, array $params) - { - $context->message = __FUNCTION__; - if (isset($params['object']) && is_object($params['object'])) { - $params['object']->foo = 'foobarbaz'; - } - return 'filtered'; - } - - public function filterReceivalCallback($context, array $params, $chain) - { - $this->assertInstanceOf('Zend\EventManager\Filter\FilterIterator', $chain); - } -} diff --git a/tests/ZendTest/EventManager/GlobalEventManagerTest.php b/tests/ZendTest/EventManager/GlobalEventManagerTest.php deleted file mode 100644 index 27f627a2edf..00000000000 --- a/tests/ZendTest/EventManager/GlobalEventManagerTest.php +++ /dev/null @@ -1,90 +0,0 @@ -assertInstanceOf('Zend\EventManager\EventManager', $events); - } - - public function testPassingNullValueForEventCollectionResetsInstance() - { - $events = GlobalEventManager::getEventCollection(); - $this->assertInstanceOf('Zend\EventManager\EventManager', $events); - GlobalEventManager::setEventCollection(null); - $events2 = GlobalEventManager::getEventCollection(); - $this->assertInstanceOf('Zend\EventManager\EventManager', $events2); - $this->assertNotSame($events, $events2); - } - - public function testProxiesAllStaticOperationsToEventCollectionInstance() - { - $test = new \stdClass(); - $listener = GlobalEventManager::attach('foo.bar', function ($e) use ($test) { - $test->event = $e->getName(); - $test->target = $e->getTarget(); - $test->params = $e->getParams(); - return $test->params; - }); - $this->assertInstanceOf('Zend\Stdlib\CallbackHandler', $listener); - - GlobalEventManager::trigger('foo.bar', $this, array('foo' => 'bar')); - $this->assertSame($this, $test->target); - $this->assertEquals('foo.bar', $test->event); - $this->assertEquals(array('foo' => 'bar'), $test->params); - - $results = GlobalEventManager::triggerUntil('foo.bar', $this, array('baz' => 'bat'), function ($r) { - return is_array($r); - }); - $this->assertTrue($results->stopped()); - $this->assertEquals(array('baz' => 'bat'), $test->params); - $this->assertEquals(array('baz' => 'bat'), $results->last()); - - $events = GlobalEventManager::getEvents(); - $this->assertEquals(array('foo.bar'), $events); - - $listeners = GlobalEventManager::getListeners('foo.bar'); - $this->assertEquals(1, count($listeners)); - $this->assertTrue($listeners->contains($listener)); - - GlobalEventManager::detach($listener); - $events = GlobalEventManager::getEvents(); - $this->assertEquals(array(), $events); - - $listener = GlobalEventManager::attach('foo.bar', function ($e) use ($test) { - $test->event = $e->getEvent(); - $test->target = $e->getTarget(); - $test->params = $e->getParams(); - }); - $events = GlobalEventManager::getEvents(); - $this->assertEquals(array('foo.bar'), $events); - GlobalEventManager::clearListeners('foo.bar'); - $events = GlobalEventManager::getEvents(); - $this->assertEquals(array(), $events); - } -} diff --git a/tests/ZendTest/EventManager/ListenerAggregateTraitTest.php b/tests/ZendTest/EventManager/ListenerAggregateTraitTest.php deleted file mode 100644 index b2be00f2e44..00000000000 --- a/tests/ZendTest/EventManager/ListenerAggregateTraitTest.php +++ /dev/null @@ -1,56 +0,0 @@ -getMock('Zend\\EventManager\\EventManagerInterface'); - $unrelatedEventManager = $this->getMock('Zend\\EventManager\\EventManagerInterface'); - $callbackHandlers = array(); - $test = $this; - - $eventManager - ->expects($this->exactly(2)) - ->method('attach') - ->will($this->returnCallback(function () use (&$callbackHandlers, $test) { - return $callbackHandlers[] = $test->getMock('Zend\\Stdlib\\CallbackHandler', array(), array(), '', false); - })); - - $listener->attach($eventManager); - $this->assertSame($callbackHandlers, $listener->getCallbacks()); - - $listener->detach($unrelatedEventManager); - - $this->assertSame($callbackHandlers, $listener->getCallbacks()); - - $eventManager - ->expects($this->exactly(2)) - ->method('detach') - ->with($this->callback(function ($callbackHandler) use ($callbackHandlers) { - return in_array($callbackHandler, $callbackHandlers, true); - })) - ->will($this->returnValue(true)); - - $listener->detach($eventManager); - $this->assertEmpty($listener->getCallbacks()); - } -} diff --git a/tests/ZendTest/EventManager/ResponseCollectionTest.php b/tests/ZendTest/EventManager/ResponseCollectionTest.php new file mode 100644 index 00000000000..79792ae7b78 --- /dev/null +++ b/tests/ZendTest/EventManager/ResponseCollectionTest.php @@ -0,0 +1,43 @@ +assertFalse($responseCollection->stopped()); + $this->assertEquals('value3', $responseCollection->last()); + $this->assertEquals('value1', $responseCollection->first()); + + $responseCollection->setStopped(true); + $this->assertTrue($responseCollection->stopped()); + $this->assertTrue($responseCollection->contains('value1')); + $this->assertFalse($responseCollection->contains('value4')); + } + + public function testResponseCollectionIsIterableAndCountable() + { + $responseCollection = new ResponseCollection(array('value1', 'value2', 'value3')); + $i = 1; + + foreach ($responseCollection as $response) { + $this->assertEquals("value$i", $response); + ++$i; + } + + $this->assertCount(3, $responseCollection); + } +} diff --git a/tests/ZendTest/EventManager/SharedEventManagerTest.php b/tests/ZendTest/EventManager/SharedEventManagerTest.php new file mode 100644 index 00000000000..247c0bba605 --- /dev/null +++ b/tests/ZendTest/EventManager/SharedEventManagerTest.php @@ -0,0 +1,40 @@ +getMock('Zend\EventManager\SharedListenerAggregateInterface'); + $sharedEventManager = new SharedEventManager(); + + $listenerAggregate->expects($this->once()) + ->method('attachShared') + ->with($sharedEventManager, 1); + + $sharedEventManager->attachAggregate($listenerAggregate); + } + + public function testCanDetachAggregate() + { + $listenerAggregate = $this->getMock('Zend\EventManager\SharedListenerAggregateInterface'); + $sharedEventManager = new SharedEventManager(); + + $listenerAggregate->expects($this->once()) + ->method('detachShared') + ->with($sharedEventManager); + + $sharedEventManager->detachAggregate($listenerAggregate); + } +} diff --git a/tests/ZendTest/EventManager/StaticEventManagerTest.php b/tests/ZendTest/EventManager/StaticEventManagerTest.php deleted file mode 100644 index c4818e86f0c..00000000000 --- a/tests/ZendTest/EventManager/StaticEventManagerTest.php +++ /dev/null @@ -1,334 +0,0 @@ -assertSame($expected, $test); - } - - public function testCanResetInstance() - { - $original = StaticEventManager::getInstance(); - StaticEventManager::resetInstance(); - $test = StaticEventManager::getInstance(); - $this->assertNotSame($original, $test); - } - - public function testSingletonInstanceIsInstanceOfClass() - { - $this->assertInstanceOf('Zend\EventManager\StaticEventManager', StaticEventManager::getInstance()); - } - - public function testCanAttachCallbackToEvent() - { - $events = StaticEventManager::getInstance(); - $events->attach('foo', 'bar', array($this, __FUNCTION__)); - $this->assertContains('bar', $events->getEvents('foo')); - $expected = array($this, __FUNCTION__); - $found = false; - $listeners = $events->getListeners('foo', 'bar'); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $listeners); - $this->assertTrue(0 < count($listeners), 'Empty listeners!'); - foreach ($listeners as $listener) { - if ($expected === $listener->getCallback()) { - $found = true; - break; - } - } - $this->assertTrue($found, 'Did not find listener!'); - } - - public function testCanAttachCallbackToMultipleEventsAtOnce() - { - $events = StaticEventManager::getInstance(); - $events->attach('bar', array('foo', 'test'), array($this, __FUNCTION__)); - $this->assertContains('foo', $events->getEvents('bar')); - $this->assertContains('test', $events->getEvents('bar')); - $expected = array($this, __FUNCTION__); - foreach (array('foo', 'test') as $event) { - $found = false; - $listeners = $events->getListeners('bar', $event); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $listeners); - $this->assertTrue(0 < count($listeners), 'Empty listeners!'); - foreach ($listeners as $listener) { - if ($expected === $listener->getCallback()) { - $found = true; - break; - } - } - $this->assertTrue($found, 'Did not find listener!'); - } - } - - public function testCanAttachSameEventToMultipleResourcesAtOnce() - { - $events = StaticEventManager::getInstance(); - $events->attach(array('foo', 'test'), 'bar', array($this, __FUNCTION__)); - $this->assertContains('bar', $events->getEvents('foo')); - $this->assertContains('bar', $events->getEvents('test')); - $expected = array($this, __FUNCTION__); - foreach (array('foo', 'test') as $id) { - $found = false; - $listeners = $events->getListeners($id, 'bar'); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $listeners); - $this->assertTrue(0 < count($listeners), 'Empty listeners!'); - foreach ($listeners as $listener) { - if ($expected === $listener->getCallback()) { - $found = true; - break; - } - } - $this->assertTrue($found, 'Did not find listener!'); - } - } - - public function testCanAttachCallbackToMultipleEventsOnMultipleResourcesAtOnce() - { - $events = StaticEventManager::getInstance(); - $events->attach(array('bar', 'baz'), array('foo', 'test'), array($this, __FUNCTION__)); - $this->assertContains('foo', $events->getEvents('bar')); - $this->assertContains('test', $events->getEvents('bar')); - $expected = array($this, __FUNCTION__); - foreach (array('bar', 'baz') as $resource) { - foreach (array('foo', 'test') as $event) { - $found = false; - $listeners = $events->getListeners($resource, $event); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $listeners); - $this->assertTrue(0 < count($listeners), 'Empty listeners!'); - foreach ($listeners as $listener) { - if ($expected === $listener->getCallback()) { - $found = true; - break; - } - } - $this->assertTrue($found, 'Did not find listener!'); - } - } - } - - public function testListenersAttachedUsingWildcardEventWillBeTriggeredByResource() - { - $test = new stdClass; - $test->events = array(); - $callback = function ($e) use ($test) { - $test->events[] = $e->getName(); - }; - - $staticEvents = StaticEventManager::getInstance(); - $staticEvents->attach('bar', '*', $callback); - - $events = new EventManager('bar'); - $events->setSharedManager($staticEvents); - - foreach (array('foo', 'bar', 'baz') as $event) { - $events->trigger($event); - $this->assertContains($event, $test->events); - } - } - - public function testCanDetachListenerFromResource() - { - $events = StaticEventManager::getInstance(); - $events->attach('foo', 'bar', array($this, __FUNCTION__)); - foreach ($events->getListeners('foo', 'bar') as $listener) { - // only one; retrieving it so we can detach - } - $events->detach('foo', $listener); - $listeners = $events->getListeners('foo', 'bar'); - $this->assertEquals(0, count($listeners)); - } - - public function testCanGetEventsByResource() - { - $events = StaticEventManager::getInstance(); - $events->attach('foo', 'bar', array($this, __FUNCTION__)); - $this->assertEquals(array('bar'), $events->getEvents('foo')); - } - - public function testCanGetEventsByWildcard() - { - $events = StaticEventManager::getInstance(); - $events->attach('*', 'bar', array($this, __FUNCTION__)); - $this->assertEquals(array('bar'), $events->getEvents('foo')); - } - - public function testCanGetListenersByResourceAndEvent() - { - $events = StaticEventManager::getInstance(); - $events->attach('foo', 'bar', array($this, __FUNCTION__)); - $listeners = $events->getListeners('foo', 'bar'); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $listeners); - $this->assertEquals(1, count($listeners)); - } - - public function testCanNotGetListenersByResourceAndEventWithWildcard() - { - $events = StaticEventManager::getInstance(); - $events->attach('*', 'bar', array($this, __FUNCTION__)); - $listeners = $events->getListeners('foo', 'bar'); - $this->assertFalse($listeners); - } - - public function testCanGetListenersByWildcardAndEvent() - { - $events = StaticEventManager::getInstance(); - $events->attach('*', 'bar', array($this, __FUNCTION__)); - $listeners = $events->getListeners('*', 'bar'); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $listeners); - $this->assertEquals(1, count($listeners)); - } - - public function testCanClearListenersByResource() - { - $events = StaticEventManager::getInstance(); - $events->attach('foo', 'bar', array($this, __FUNCTION__)); - $events->attach('foo', 'baz', array($this, __FUNCTION__)); - $events->clearListeners('foo'); - $this->assertFalse($events->getListeners('foo', 'bar')); - $this->assertFalse($events->getListeners('foo', 'baz')); - } - - public function testCanClearListenersByResourceAndEvent() - { - $events = StaticEventManager::getInstance(); - $events->attach('foo', 'bar', array($this, __FUNCTION__)); - $events->attach('foo', 'baz', array($this, __FUNCTION__)); - $events->attach('foo', 'bat', array($this, __FUNCTION__)); - $events->clearListeners('foo', 'baz'); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $events->getListeners('foo', 'baz')); - $this->assertEquals(0, count($events->getListeners('foo', 'baz'))); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $events->getListeners('foo', 'bar')); - $this->assertEquals(1, count($events->getListeners('foo', 'bar'))); - $this->assertInstanceOf('Zend\Stdlib\PriorityQueue', $events->getListeners('foo', 'bat')); - $this->assertEquals(1, count($events->getListeners('foo', 'bat'))); - } - - public function testCanPassArrayOfIdentifiersToConstructor() - { - $identifiers = array('foo', 'bar'); - $manager = new EventManager($identifiers); - } - - public function testListenersAttachedToAnyIdentifierProvidedToEventManagerWillBeTriggered() - { - $identifiers = array('foo', 'bar'); - $events = StaticEventManager::getInstance(); - $manager = new EventManager($identifiers); - $manager->setSharedManager($events); - - $test = new \stdClass; - $test->triggered = 0; - $events->attach('foo', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - $events->attach('bar', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - $manager->trigger('bar', $this, array()); - $this->assertEquals(2, $test->triggered); - } - - public function testListenersAttachedToWildcardsWillBeTriggered() - { - $identifiers = array('foo', 'bar'); - $events = StaticEventManager::getInstance(); - $manager = new EventManager($identifiers); - $manager->setSharedManager($events); - - $test = new \stdClass; - $test->triggered = 0; - $events->attach('*', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - //Tests one can have multiple wildcards attached - $events->attach('*', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - $manager->trigger('bar', $this, array()); - $this->assertEquals(2, $test->triggered); - } - - public function testListenersAttachedToAnyIdentifierProvidedToEventManagerOrWildcardsWillBeTriggered() - { - $identifiers = array('foo', 'bar'); - $events = StaticEventManager::getInstance(); - $manager = new EventManager($identifiers); - $manager->setSharedManager($events); - - $test = new \stdClass; - $test->triggered = 0; - $events->attach('foo', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - $events->attach('bar', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - $events->attach('*', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - //Tests one can have multiple wildcards attached - $events->attach('*', 'bar', function ($e) use ($test) { - $test->triggered++; - }); - $manager->trigger('bar', $this, array()); - $this->assertEquals(4, $test->triggered); - } - - public function testCanAttachListenerAggregate() - { - $staticManager = StaticEventManager::getInstance(); - $aggregate = new TestAsset\SharedMockAggregate('bazinga'); - $staticManager->attachAggregate($aggregate); - - $events = $staticManager->getEvents('bazinga'); - $this->assertCount(2, $events); - } - - public function testCanDetachListenerAggregate() - { - $staticManager = StaticEventManager::getInstance(); - $aggregate = new TestAsset\SharedMockAggregate('bazinga'); - - $staticManager->attachAggregate($aggregate); - $events = $staticManager->getEvents('bazinga'); - $this->assertCount(2, $events); - - $staticManager->detachAggregate($aggregate); - $events = $staticManager->getEvents('bazinga'); - $this->assertCount(0, $events); - } -} diff --git a/tests/ZendTest/EventManager/StaticIntegrationTest.php b/tests/ZendTest/EventManager/StaticIntegrationTest.php deleted file mode 100644 index 2a82fcae7cc..00000000000 --- a/tests/ZendTest/EventManager/StaticIntegrationTest.php +++ /dev/null @@ -1,148 +0,0 @@ - 0); - $events = StaticEventManager::getInstance(); - $events->attach( - 'ZendTest\EventManager\TestAsset\ClassWithEvents', - 'foo', - function ($e) use ($counter) { - $counter->count++; - } - ); - $class = new TestAsset\ClassWithEvents(); - $class->getEventManager()->setSharedManager($events); - $class->foo(); - $this->assertEquals(1, $counter->count); - } - - public function testLocalHandlersAreExecutedPriorToStaticHandlersWhenSetWithSamePriority() - { - $test = (object) array('results' => array()); - $events = StaticEventManager::getInstance(); - $events->attach( - 'ZendTest\EventManager\TestAsset\ClassWithEvents', - 'foo', - function ($e) use ($test) { - $test->results[] = 'static'; - } - ); - $class = new TestAsset\ClassWithEvents(); - $class->getEventManager()->attach('foo', function ($e) use ($test) { - $test->results[] = 'local'; - }); - $class->getEventManager()->setSharedManager($events); - $class->foo(); - $this->assertEquals(array('local', 'static'), $test->results); - } - - public function testLocalHandlersAreExecutedInPriorityOrderRegardlessOfStaticOrLocalRegistration() - { - $test = (object) array('results' => array()); - $events = StaticEventManager::getInstance(); - $events->attach( - 'ZendTest\EventManager\TestAsset\ClassWithEvents', - 'foo', - function ($e) use ($test) { - $test->results[] = 'static'; - }, - 10000 // high priority - ); - $class = new TestAsset\ClassWithEvents(); - $class->getEventManager()->attach('foo', function ($e) use ($test) { - $test->results[] = 'local'; - }, 1); // low priority - $class->getEventManager()->attach('foo', function ($e) use ($test) { - $test->results[] = 'local2'; - }, 1000); // medium priority - $class->getEventManager()->attach('foo', function ($e) use ($test) { - $test->results[] = 'local3'; - }, 15000); // highest priority - $class->getEventManager()->setSharedManager($events); - $class->foo(); - $this->assertEquals(array('local3', 'static', 'local2', 'local'), $test->results); - } - - public function testCallingUnsetSharedManagerDisablesStaticManager() - { - $counter = (object) array('count' => 0); - StaticEventManager::getInstance()->attach( - 'ZendTest\EventManager\TestAsset\ClassWithEvents', - 'foo', - function ($e) use ($counter) { - $counter->count++; - } - ); - $class = new TestAsset\ClassWithEvents(); - $class->getEventManager()->unsetSharedManager(); - $class->foo(); - $this->assertEquals(0, $counter->count); - } - - public function testCanPassAlternateStaticConnectionsHolder() - { - $counter = (object) array('count' => 0); - StaticEventManager::getInstance()->attach( - 'ZendTest\EventManager\TestAsset\ClassWithEvents', - 'foo', - function ($e) use ($counter) { - $counter->count++; - } - ); - $mockStaticEvents = new TestAsset\StaticEventsMock(); - $class = new TestAsset\ClassWithEvents(); - $class->getEventManager()->setSharedManager($mockStaticEvents); - $this->assertSame($mockStaticEvents, $class->getEventManager()->getSharedManager()); - $class->foo(); - $this->assertEquals(0, $counter->count); - } - - public function testTriggerMergesPrioritiesOfStaticAndInstanceListeners() - { - $test = (object) array('results' => array()); - $events = StaticEventManager::getInstance(); - $events->attach( - 'ZendTest\EventManager\TestAsset\ClassWithEvents', - 'foo', - function ($e) use ($test) { - $test->results[] = 'static'; - }, - 100 - ); - $class = new TestAsset\ClassWithEvents(); - $class->getEventManager()->attach('foo', function ($e) use ($test) { - $test->results[] = 'local'; - }, -100); - $class->getEventManager()->setSharedManager($events); - $class->foo(); - $this->assertEquals(array('static', 'local'), $test->results); - } -} diff --git a/tests/ZendTest/EventManager/TestAsset/ClassWithEvents.php b/tests/ZendTest/EventManager/TestAsset/ClassWithEvents.php deleted file mode 100644 index c752d2ba15d..00000000000 --- a/tests/ZendTest/EventManager/TestAsset/ClassWithEvents.php +++ /dev/null @@ -1,41 +0,0 @@ -events = $events; - } - if (null === $this->events) { - $this->events = new EventManager(__CLASS__); - } - return $this->events; - } - - public function foo() - { - $this->getEventManager()->trigger(__FUNCTION__, $this, array()); - } -} diff --git a/tests/ZendTest/EventManager/TestAsset/Functor.php b/tests/ZendTest/EventManager/TestAsset/Functor.php deleted file mode 100644 index be696480c16..00000000000 --- a/tests/ZendTest/EventManager/TestAsset/Functor.php +++ /dev/null @@ -1,19 +0,0 @@ -listeners[] = $events->attach('foo.bar', array($this, 'doFoo')); - $this->listeners[] = $events->attach('foo.baz', array($this, 'doFoo')); - } - - public function getCallbacks() - { - return $this->listeners; - } - - public function doFoo() - { - } -} diff --git a/tests/ZendTest/EventManager/TestAsset/MockAggregate.php b/tests/ZendTest/EventManager/TestAsset/MockAggregate.php deleted file mode 100644 index 6d962d57283..00000000000 --- a/tests/ZendTest/EventManager/TestAsset/MockAggregate.php +++ /dev/null @@ -1,59 +0,0 @@ -priority = $priority; - - $listeners = array(); - $listeners[] = $events->attach('foo.bar', array( $this, 'fooBar' )); - $listeners[] = $events->attach('foo.baz', array( $this, 'fooBaz' )); - - $this->listeners[ \spl_object_hash($events) ] = $listeners; - - return __METHOD__; - } - - public function detach(EventManagerInterface $events) - { - foreach ($this->listeners[ \spl_object_hash($events) ] as $listener) { - $events->detach($listener); - } - - return __METHOD__; - } - - public function fooBar() - { - return __METHOD__; - } - - public function fooBaz() - { - return __METHOD__; - } -} diff --git a/tests/ZendTest/EventManager/TestAsset/MockListenerAggregateTrait.php b/tests/ZendTest/EventManager/TestAsset/MockListenerAggregateTrait.php deleted file mode 100644 index 13d02e2f15f..00000000000 --- a/tests/ZendTest/EventManager/TestAsset/MockListenerAggregateTrait.php +++ /dev/null @@ -1,40 +0,0 @@ -listeners[] = $events->attach('foo.bar', array($this, 'doFoo')); - $this->listeners[] = $events->attach('foo.baz', array($this, 'doFoo')); - } - - public function getCallbacks() - { - return $this->listeners; - } - - public function doFoo() - { - } -} diff --git a/tests/ZendTest/EventManager/TestAsset/SharedMockAggregate.php b/tests/ZendTest/EventManager/TestAsset/SharedMockAggregate.php deleted file mode 100644 index 8750fd0cea9..00000000000 --- a/tests/ZendTest/EventManager/TestAsset/SharedMockAggregate.php +++ /dev/null @@ -1,66 +0,0 @@ -identity = $identity; - } - - protected $listeners = array(); - public $priority; - - public function attachShared(SharedEventManagerInterface $events, $priority = null) - { - $this->priority = $priority; - - $listeners = array(); - $listeners[] = $events->attach($this->identity, 'foo.bar', array( $this, 'fooBar' )); - $listeners[] = $events->attach($this->identity, 'foo.baz', array( $this, 'fooBaz' )); - - $this->listeners[ \spl_object_hash($events) ] = $listeners; - - return __METHOD__; - } - - public function detachShared(SharedEventManagerInterface $events) - { - foreach ($this->listeners[ \spl_object_hash($events) ] as $listener) { - $events->detach($this->identity, $listener); - } - - return __METHOD__; - } - - public function fooBar() - { - return __METHOD__; - } - - public function fooBaz() - { - return __METHOD__; - } -} diff --git a/tests/ZendTest/EventManager/TestAsset/StaticEventsMock.php b/tests/ZendTest/EventManager/TestAsset/StaticEventsMock.php deleted file mode 100644 index 4fdb7eada88..00000000000 --- a/tests/ZendTest/EventManager/TestAsset/StaticEventsMock.php +++ /dev/null @@ -1,79 +0,0 @@ -setExpectedException('Zend\Stdlib\Exception\InvalidCallbackException'); + $this->setExpectedException('Exception'); $handler = new CallbackHandler('boguscallback'); } @@ -72,53 +72,39 @@ public function testCallShouldReturnTheReturnValueOfTheCallback() public function testStringCallbackResolvingToClassDefiningInvokeNameShouldRaiseException() { - $this->setExpectedException('Zend\Stdlib\Exception\InvalidCallbackException'); + $this->setExpectedException('Exception'); $handler = new CallbackHandler('ZendTest\\Stdlib\\SignalHandlers\\Invokable'); } public function testStringCallbackReferringToClassWithoutDefinedInvokeShouldRaiseException() { - $this->setExpectedException('Zend\Stdlib\Exception\InvalidCallbackException'); + $this->setExpectedException('Exception'); $class = new SignalHandlers\InstanceMethod(); $handler = new CallbackHandler($class); } public function testCallbackConsistingOfStringContextWithNonStaticMethodShouldNotRaiseExceptionButWillRaiseEStrict() { - $handler = new CallbackHandler(array('ZendTest\\Stdlib\\SignalHandlers\\InstanceMethod', 'handler')); $error = false; set_error_handler(function ($errno, $errstr) use (&$error) { $error = true; }, E_STRICT); - $handler->call(); + + $handler = new CallbackHandler(array('ZendTest\\Stdlib\\SignalHandlers\\InstanceMethod', 'handler')); + restore_error_handler(); + $this->assertTrue($error); } public function testStringCallbackConsistingOfNonStaticMethodShouldRaiseException() { + $this->setExpectedException('Exception'); $handler = new CallbackHandler('ZendTest\\Stdlib\\SignalHandlers\\InstanceMethod::handler'); - - if (version_compare(PHP_VERSION, '5.4.0rc1', '>=')) { - $this->setExpectedException('Zend\Stdlib\Exception\InvalidCallbackException'); - $handler->call(); - } else { - $error = false; - set_error_handler(function ($errno, $errstr) use (&$error) { - $error = true; - }, E_STRICT); - $handler->call(); - restore_error_handler(); - $this->assertTrue($error); - } } public function testStringStaticCallbackForPhp54() { - if (version_compare(PHP_VERSION, '5.4.0rc1', '<=')) { - $this->markTestSkipped('Requires PHP 5.4'); - } - $handler = new CallbackHandler('ZendTest\\Stdlib\\SignalHandlers\\InstanceMethod::staticHandler'); $error = false; set_error_handler(function ($errno, $errstr) use (&$error) { @@ -132,10 +118,6 @@ public function testStringStaticCallbackForPhp54() public function testStringStaticCallbackForPhp54WithMoreThan3Args() { - if (version_compare(PHP_VERSION, '5.4.0rc1', '<=')) { - $this->markTestSkipped('Requires PHP 5.4'); - } - $handler = new CallbackHandler('ZendTest\\Stdlib\\SignalHandlers\\InstanceMethod::staticHandler'); $error = false; set_error_handler(function ($errno, $errstr) use (&$error) { @@ -147,9 +129,9 @@ public function testStringStaticCallbackForPhp54WithMoreThan3Args() $this->assertSame('staticHandler', $result); } - public function testCallbackToClassImplementingOverloadingButNotInvocableShouldRaiseException() + public function testCallbackToClassImplementingOverloadingButNotInvokableShouldRaiseException() { - $this->setExpectedException('Zend\Stdlib\Exception\InvalidCallbackException'); + $this->setExpectedException('Exception'); $handler = new CallbackHandler('foo', array( 'ZendTest\\Stdlib\\SignalHandlers\\Overloadable', 'foo' )); }