--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/lib/Zend/EventManager/EventManager.php Thu Mar 21 19:52:38 2013 +0100
@@ -0,0 +1,551 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category Zend
+ * @package Zend_EventManager
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+require_once 'Zend/EventManager/Event.php';
+require_once 'Zend/EventManager/EventCollection.php';
+require_once 'Zend/EventManager/ResponseCollection.php';
+require_once 'Zend/EventManager/SharedEventCollectionAware.php';
+require_once 'Zend/EventManager/StaticEventManager.php';
+require_once 'Zend/Stdlib/CallbackHandler.php';
+require_once 'Zend/Stdlib/PriorityQueue.php';
+
+/**
+ * Event manager: notification system
+ *
+ * Use the EventManager when you want to create a per-instance notification
+ * system for your objects.
+ *
+ * @category Zend
+ * @package Zend_EventManager
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+class Zend_EventManager_EventManager implements Zend_EventManager_EventCollection, Zend_EventManager_SharedEventCollectionAware
+{
+ /**
+ * Subscribed events and their listeners
+ * @var array Array of Zend_Stdlib_PriorityQueue objects
+ */
+ protected $events = array();
+
+ /**
+ * @var string Class representing the event being emitted
+ */
+ protected $eventClass = 'Zend_EventManager_Event';
+
+ /**
+ * Identifiers, used to pull static signals from StaticEventManager
+ * @var array
+ */
+ protected $identifiers = array();
+
+ /**
+ * Static collections
+ * @var false|null|Zend_EventManager_StaticEventCollection
+ */
+ protected $sharedCollections = null;
+
+ /**
+ * Constructor
+ *
+ * Allows optionally specifying identifier(s) to use to pull signals from a
+ * StaticEventManager.
+ *
+ * @param null|string|int|array|Traversable $identifiers
+ * @return void
+ */
+ public function __construct($identifiers = null)
+ {
+ $this->setIdentifiers($identifiers);
+ }
+
+ /**
+ * Set the event class to utilize
+ *
+ * @param string $class
+ * @return Zend_EventManager_EventManager
+ */
+ public function setEventClass($class)
+ {
+ $this->eventClass = $class;
+ return $this;
+ }
+
+ /**
+ * Set static collections container
+ *
+ * @param Zend_EventManager_StaticEventCollection $collections
+ * @return void
+ */
+ public function setSharedCollections(Zend_EventManager_SharedEventCollection $collections)
+ {
+ $this->sharedCollections = $collections;
+ return $this;
+ }
+
+ /**
+ * Remove any shared collections
+ *
+ * Sets {@link $sharedCollections} to boolean false to disable ability
+ * to lazy-load static event manager instance.
+ *
+ * @return void
+ */
+ public function unsetSharedCollections()
+ {
+ $this->sharedCollections = false;
+ }
+
+ /**
+ * Get static collections container
+ *
+ * @return false|Zend_EventManager_SharedEventCollection
+ */
+ public function getSharedCollections()
+ {
+ if (null === $this->sharedCollections) {
+ $this->setSharedCollections(Zend_EventManager_StaticEventManager::getInstance());
+ }
+ return $this->sharedCollections;
+ }
+
+ /**
+ * Get the identifier(s) for this Zend_EventManager_EventManager
+ *
+ * @return array
+ */
+ public function getIdentifiers()
+ {
+ return $this->identifiers;
+ }
+
+ /**
+ * Set the identifiers (overrides any currently set identifiers)
+ *
+ * @param string|int|array|Traversable $identifiers
+ * @return Zend_EventManager_EventManager
+ */
+ 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 Zend_EventManager_EventManager
+ */
+ public function addIdentifiers($identifiers)
+ {
+ if (is_array($identifiers) || $identifiers instanceof Traversable) {
+ $this->identifiers = array_unique($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|callback $callback
+ * @return Zend_EventManager_ResponseCollection All listener return values
+ */
+ public function trigger($event, $target = null, $argv = array(), $callback = null)
+ {
+ if ($event instanceof Zend_EventManager_EventDescription) {
+ $e = $event;
+ $event = $e->getName();
+ $callback = $target;
+ } elseif ($target instanceof Zend_EventManager_EventDescription) {
+ $e = $target;
+ $e->setName($event);
+ $callback = $argv;
+ } elseif ($argv instanceof Zend_EventManager_EventDescription) {
+ $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)) {
+ require_once 'Zend/Stdlib/Exception/InvalidCallbackException.php';
+ throw new Zend_Stdlib_Exception_InvalidCallbackException('Invalid callback provided');
+ }
+
+ 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
+ * @throws Zend_Stdlib_Exception_InvalidCallbackException if invalid callback provided
+ */
+ public function triggerUntil($event, $target, $argv = null, $callback = null)
+ {
+ if ($event instanceof Zend_EventManager_EventDescription) {
+ $e = $event;
+ $event = $e->getName();
+ $callback = $target;
+ } elseif ($target instanceof Zend_EventManager_EventDescription) {
+ $e = $target;
+ $e->setName($event);
+ $callback = $argv;
+ } elseif ($argv instanceof Zend_EventManager_EventDescription) {
+ $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)) {
+ require_once 'Zend/Stdlib/Exception/InvalidCallbackException.php';
+ throw new Zend_Stdlib_Exception_InvalidCallbackException('Invalid callback provided');
+ }
+
+ 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.
+ *
+ * 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
+ * integer value. Higher values have higher priority (i.e., execute first).
+ *
+ * You can specify "*" for the event name. In such cases, the listener will
+ * be triggered for every event.
+ *
+ * @param string|array|Zend_EventManager_ListenerAggregate $event An event or array of event names. If a ListenerAggregate, proxies to {@link attachAggregate()}.
+ * @param callback|int $callback If string $event provided, expects PHP callback; for a ListenerAggregate $event, this will be the priority
+ * @param int $priority If provided, the priority at which to register the callback
+ * @return Zend_Stdlib_CallbackHandler|mixed CallbackHandler if attaching callback (to allow later unsubscribe); mixed if attaching aggregate
+ */
+ public function attach($event, $callback = null, $priority = 1)
+ {
+ // Proxy ListenerAggregate arguments to attachAggregate()
+ if ($event instanceof Zend_EventManager_ListenerAggregate) {
+ return $this->attachAggregate($event, $callback);
+ }
+
+ // Null callback is invalid
+ if (null === $callback) {
+ require_once 'Zend/EventManager/Exception/InvalidArgumentException.php';
+ throw new Zend_EventManager_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 Zend_Stdlib_PriorityQueue();
+ }
+
+ // Create a callback handler, setting the event and priority in its metadata
+ $listener = new Zend_Stdlib_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 EventCollection instance, and call attach()
+ * one or more times, typically to attach to multiple events using local
+ * methods.
+ *
+ * @param Zend_EventManager_ListenerAggregate $aggregate
+ * @param int $priority If provided, a suggested priority for the aggregate to use
+ * @return mixed return value of {@link Zend_EventManager_ListenerAggregate::attach()}
+ */
+ public function attachAggregate(Zend_EventManager_ListenerAggregate $aggregate, $priority = 1)
+ {
+ return $aggregate->attach($this, $priority);
+ }
+
+ /**
+ * Unsubscribe a listener from an event
+ *
+ * @param Zend_Stdlib_CallbackHandler|Zend_EventManager_ListenerAggregate $listener
+ * @return bool Returns true if event and listener found, and unsubscribed; returns false if either event or listener not found
+ * @throws Zend_EventManager_Exception_InvalidArgumentException if invalid listener provided
+ */
+ public function detach($listener)
+ {
+ if ($listener instanceof Zend_EventManager_ListenerAggregate) {
+ return $this->detachAggregate($listener);
+ }
+
+ if (!$listener instanceof Zend_Stdlib_CallbackHandler) {
+ require_once 'Zend/EventManager/Exception/InvalidArgumentException.php';
+ throw new Zend_EventManager_Exception_InvalidArgumentException(sprintf(
+ '%s: expected a Zend_EventManager_ListenerAggregate or Zend_Stdlib_CallbackHandler; received "%s"',
+ __METHOD__,
+ (is_object($listener) ? get_class($listener) : gettype($listener))
+ ));
+ }
+
+ $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 EventCollection instance, and call detach()
+ * of all previously attached listeners.
+ *
+ * @param Zend_EventManager_ListenerAggregate $aggregate
+ * @return mixed return value of {@link Zend_EventManager_ListenerAggregate::detach()}
+ */
+ public function detachAggregate(Zend_EventManager_ListenerAggregate $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 Zend_Stdlib_PriorityQueue
+ */
+ public function getListeners($event)
+ {
+ if (!array_key_exists($event, $this->events)) {
+ return new Zend_Stdlib_PriorityQueue();
+ }
+ return $this->events[$event];
+ }
+
+ /**
+ * 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]);
+ }
+ }
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Trigger listeners
+ *
+ * Actual functionality for triggering listeners, to which both trigger() and triggerUntil()
+ * delegate.
+ *
+ * @param string $event Event name
+ * @param EventDescription $e
+ * @param null|callback $callback
+ * @return ResponseCollection
+ */
+ protected function triggerListeners($event, Zend_EventManager_EventDescription $e, $callback = null)
+ {
+ $responses = new Zend_EventManager_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 ($listeners->isEmpty()) {
+ return $responses;
+ }
+
+ foreach ($listeners as $listener) {
+ // Trigger the listener's callback, and push its result onto the
+ // response collection
+ $responses->push(call_user_func($listener->getCallback(), $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;
+ }
+
+ /**
+ * Get list of all listeners attached to the shared collection for
+ * identifiers registered by this instance
+ *
+ * @param string $event
+ * @return array
+ */
+ protected function getSharedListeners($event)
+ {
+ if (!$sharedCollections = $this->getSharedCollections()) {
+ return array();
+ }
+
+ $identifiers = $this->getIdentifiers();
+ $sharedListeners = array();
+
+ foreach ($identifiers as $id) {
+ if (!$listeners = $sharedCollections->getListeners($id, $event)) {
+ continue;
+ }
+
+ if (!is_array($listeners) && !($listeners instanceof Traversable)) {
+ continue;
+ }
+
+ foreach ($listeners as $listener) {
+ if (!$listener instanceof Zend_Stdlib_CallbackHandler) {
+ continue;
+ }
+ $sharedListeners[] = $listener;
+ }
+ }
+
+ return $sharedListeners;
+ }
+
+ /**
+ * Add listeners to the master queue of listeners
+ *
+ * Used to inject shared listeners and wildcard listeners.
+ *
+ * @param Zend_Stdlib_PriorityQueue $masterListeners
+ * @param Zend_Stdlib_PriorityQueue $listeners
+ * @return void
+ */
+ protected function insertListeners($masterListeners, $listeners)
+ {
+ if (!count($listeners)) {
+ return;
+ }
+
+ 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);
+ }
+ }
+}