Skip to content

Instantly share code, notes, and snippets.

@bashilbers
Created December 5, 2012 07:51
Show Gist options
  • Save bashilbers/4213585 to your computer and use it in GitHub Desktop.
Save bashilbers/4213585 to your computer and use it in GitHub Desktop.
RHM code example
<?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