Created
December 5, 2012 07:51
-
-
Save bashilbers/4213585 to your computer and use it in GitHub Desktop.
RHM code example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* The EventDispatcher is the central point of the event listener system, all classes which wish to send events must inherit from Event_Dispatcher. | |
*/ | |
class Mercurius_Event_Dispatcher | |
implements Mercurius_Event_Dispatcher_Interface | |
{ | |
/* | |
* Objects (handlers) listening for various events | |
* @var Array | |
*/ | |
protected $_listeners = array(); | |
protected $_prioritized = array(); | |
/** | |
* Dispatched events | |
* @var Array | |
*/ | |
private $_events = array(); | |
/** | |
* Target dispatcher registering event listeners | |
* @var Mercurius_Event_Dispatcher_Interface | |
*/ | |
private $_target; | |
/** | |
* Aggregates an instance of the Event_Dispatcher class. | |
* | |
* The Event_Dispatcher class is generally used as a base class, which means that most developers do not need to use this constructor function. | |
* However, advanced developers who are implementing the Event_Dispatcher_Interface interface need to use this constructor. | |
* | |
* If you are unable to extend the Event_Dispatcher class and must instead implement the Event_Dispatcher_Interface interface, | |
* use this constructor to aggregate an instance of the Event_Dispatcher class. | |
* | |
* @param null|Mercurius_Event_Dispatcher_Interface $target The target object for events dispatched to the Event_Dispatcher object. This parameter is used | |
* when the Event_Dispatcher instance is aggregated by a class that implements Event_Dispatcher_Interface; | |
* it is necessary so that the containing object can be the target for events. | |
* @return void | |
*/ | |
public function __construct($target = null) | |
{ | |
if ($target instanceof Mercurius_Event_Dispatcher_Interface) { | |
$this->_target = $target; | |
} | |
} | |
/** | |
* Registers an event listener object with an Event_Dispatcher object so that the listener receives notification of an event. | |
* | |
* After you successfully register an listener, you cannot change its priority through additional calls to addEventListener(). | |
* To change a listener's priority, you must first call removeEventListener(). Then you can register the listener again with the new priority level. | |
* | |
* Keep in mind that after the listener is registered, subsequent calls to addEventListener() with a different eventType result in the creation | |
* of a separate listener registration. | |
* | |
* @param Mercurius_Event_Listener $listener Class that contains a PHP callable; The listener function that processes the event | |
* @param null|Integer $priority The priority level of the listener. The priority is designated by a signed 32-bit integer. | |
* The higher the number, the higher the priority. All listeners with priority n are processed before listeners of priority n-1. | |
* If two or more listeners share the same priority, they are processed in the order in which they were added. | |
* @return void | |
*/ | |
public function addEventListener(Mercurius_Event_Listener $listener, $priority = 0) | |
{ | |
// check whether $listener was already binded to listener.eventType | |
if (in_array($listener, $this->getEventListeners($listener->getEventType()))) { | |
// @TODO: send out a log that $listener is already added. | |
return; | |
} | |
$type = $listener->getEventType(); | |
$this->_listeners[$type][$priority][spl_object_hash($listener)] = $listener; | |
unset($this->_prioritized[$type]); | |
} | |
/** | |
* Removes a listener from the Event_Dispatcher object. | |
* | |
* If there is no matching listener registered with the Event_Dispatcher object, a call to this method has no effect. | |
* | |
* @param Mercurius_Event_Listener $listener Class containing a PHP callable; The listener function that processes the event. | |
* @return mixed false if listener was not registered, null otherwise | |
*/ | |
public function removeEventListener(Mercurius_Event_Listener $listener) | |
{ | |
$type = $listener->getEventType(); | |
if (!isset($this->_listeners[$type])) { | |
return false; | |
} | |
// loop each registered handlers trying to remove $listener | |
foreach ($this->_listeners[$type] as $priority => $listeners) { | |
if (false !== ($key = array_search($listener, $listeners))) { | |
unset($this->_listeners[$type][$priority][$key], $this->_prioritized[$type]); | |
} | |
} | |
} | |
/** | |
* Dispatches an event into the event flow triggering all registered listeners | |
* | |
* @param Mercurius_Event $event The Event object that is dispatched into the event flow. | |
* @return boolean A value of true if the event was successfully dispatched. A value of false indicates failure or that stopPropagation() was called on the event. | |
*/ | |
public function dispatchEvent(Mercurius_Event $event) | |
{ | |
if (!isset($this->_listeners[(string) $event])) { | |
return; | |
} | |
// inject reference | |
if (null !== $this->_target) { | |
$event->setTarget($this->_target); | |
} | |
foreach ($this->getEventListeners($event) as $listener) { | |
if($event->isPropagationStopped()) { | |
return false; | |
} | |
if (null !== ($value = call_user_func($listener->getCallBack(), $event))) { | |
if ($value) { | |
$event->setReturnValue($value); | |
} | |
$event->setProcessed(true); | |
} | |
} | |
$this->_events[$event->getType()] = $event; | |
return true; | |
} | |
/** | |
* Filters a value by calling all listeners of a given event | |
* | |
* @param Mercurius_Event $event The given event object. | |
* @param mixed $value The value to be filtered. | |
* @return void | |
*/ | |
public function filter(Mercurius_Event $event, $value) | |
{ | |
foreach (array_values($this->getEventListeners($event)) as $listener) { | |
$value = call_user_func_array($listener, array($event, $value)); | |
} | |
$event->setReturnValue($value); | |
} | |
/** | |
* Checks whether the Event_Dispatcher object has any listeners registered for a specific type of event. | |
* | |
* @param string|Mercurius_event $event The event to check for registered listeners. | |
* @return boolean True if some listeners are attached, false otherwise. | |
*/ | |
public function hasEventListeners($event) | |
{ | |
return (boolean) count($this->getEventListeners($event)); | |
} | |
/** | |
* Returns all attached listeners for given event. | |
* | |
* @param null|String|Mercurius_Event $event The event to fetch listeners from. | |
* @return Array An array of listeners. | |
*/ | |
public function getEventListeners($type = null) | |
{ | |
// return prioritized listeners from $type | |
if ($type) { | |
if ($type instanceof Mercurius_Event) { | |
$type = $type->getType(); | |
} else if (!is_string($type)) { | |
throw new InvalidArgumentException('Listeners could not be retrieved due to invalid Event type argument given'); | |
} | |
if (!isset($this->_listeners[$type])) { | |
return array(); | |
} | |
if (!isset($this->_prioritized[$type])) { | |
$this->_prioritize($type); | |
} | |
return $this->_prioritized[$type]; | |
} | |
// return prioritized listeners from all events | |
foreach (array_keys($this->_listeners) as $eventname) { | |
if (!isset($this->_prioritized[$eventname])) { | |
$this->_prioritize($eventname); | |
} | |
} | |
return $this->_prioritized; | |
} | |
/** | |
* Sorts the internal list of listeners for the given event by priority. | |
* | |
* @param String|Mercurius_Event $type The event to sort on. | |
* @return void | |
*/ | |
protected function _prioritize($type) | |
{ | |
if ($type instanceof Mercurius_Event) { | |
$type = $event->getType(); | |
} else if (!is_string($type)) { | |
throw new InvalidArgumentException('Listeners could not be prioritized due to invalid Event type argument given'); | |
} | |
$this->_prioritized[$type] = array(); | |
if (isset($this->_listeners[$type])) { | |
krsort($this->_listeners[$type]); | |
$this->_prioritized[$type] = call_user_func_array('array_merge', $this->_listeners[$type]); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment