<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[
Zend_Event is AS3'like powerful event system.Zend Framework: Zend_Event Component Proposal
Proposed Component Name
Zend_Event
Developer Notes
http://framework.zend.com/wiki/display/ZFDEV/Zend_Event
Proposers
Alvar Vilu
Zend Liaison
TBD
Revision
1.0 - 2 December 2009: Initial Draft. (wiki revision: 15)
Table of Contents
1. Overview
2. References
3. Component Requirements, Constraints, and Acceptance Criteria
- Any event dispatchable component must extend Zend_Event_Dispatcher or implement Zend_Event_Dispatcher_Interface.
4. Dependencies on Other Framework Components
- Zend_Exception
5. Theory of Operation
This component can handle event listeners per obj or via stack trace.
6. Milestones / Tasks
Describe some intermediate state of this component in terms of design notes, additional material added to this page, and / code. Note any significant dependencies here, such as, "Milestone #3 can not be completed until feature Foo has been added to ZF component XYZ." Milestones will be required for acceptance of future proposals. They are not hard, and many times you will only need to think of the first three below.
- Milestone 1: design notes will be published here
- Milestone 2: Working prototype checked into the incubator supporting use cases #1, #2, ...
- Milestone 3: Working prototype checked into the incubator supporting use cases #3 and #4.
- Milestone 4: Unit tests exist, work, and are checked into SVN.
- Milestone 5: Initial documentation exists.
If a milestone is already done, begin the description with "[DONE]", like this:
- Milestone #: [DONE] Unit tests ...
7. Class Index
- Zend_Magic_Exception
- Zend_Magic (factory class)
- Zend_Magic_MindProbe
- Zend_Magic_MindProbe_Intent
- Zend_Magic_Action
- Zend_Magic_CodeGen
8. Use Cases
| UC-01 |
|---|
| UC-02 |
|---|
9. Class Skeletons
/**
- @see Zend_Exception
*/
require_once 'AVlib/Exception.php';
/**
- @author Alvar Vilu <alvar.vilu@msn.com>
*
*/
class Zend_Event_Exception extends Zend_Exception
{}
/**
- @see Zend_Event_Dispatcher_Interface
*/
require_once 'AVlib/Event/Dispatcher/Interface.php';
/**
- @see Zend_Event_Phase
*/
require_once 'AVlib/Event/Phase.php';
/**
- @see Zend_Event
*/
require_once 'AVlib/Event.php';
/**
- @author Alvar Vilu <alvar.vilu@msn.com>
*
*/
class Zend_Event_Dispatcher implements Zend_Event_Dispatcher_Interface
{
/**
- An array that holds all listeners that have been created.
- [eventType][objID][useCapture] = array(listener, listener, ...)
- listener = array (0 => priority, 1 => callback func
- @var array
*/
private static $_listeners = array ();
/**
- A object that's used to dispatch events,
- can be $this on obj that interface Zend_Event_Dispatcher_Interface.
- @var Zend_Event_Dispatcher
*/
private $dispatchObj = null;
public function __construct ( $dispatchObj = null )
final private function _getDispatchObj ( )
/**
- Add new event listener to spesific type.
- If use capture is enabled then event will flow from (main) to target
- The higher the priority number - event will sorted to first.
- If two or more same priority level events added then first one will be dispatched.
- @param string $type
- @param string|array $listener
- @param bool $useCapture
- @param int $priority
- @param bool $useWeakReference UNIMPLEMENTED!
- @return Zend_Event_Dispatcher Event dispatchable object
*/
final public function addEventListener ( $type, $listener, $useCapture = false, $priority = 0, $useWeakReference = false ) {
$objHash = spl_object_hash ( $this->_getDispatchObj ( ) );
$useCapture = ( bool ) $useCapture;
$priority = ( int ) $priority;
$useWeakReference = ( bool ) $useWeakReference;
//Prepare self::$_listeners array indexes.
if ( ! isset ( self::$_listeners[ $type ][ $objHash ][ $useCapture ] ) ) {
if ( ! isset ( self::$_listeners[ $type ][ $objHash ] ) ) {
if ( ! isset ( self::$_listeners[ $type ] ) )
self::$_listeners[ $type ][ $objHash ] = array ();
}
self::$_listeners[ $type ][ $objHash ][ $useCapture ] = array ();
}
//If ve have that same listner, don't add it twice.
foreach ( self::$_listeners[ $type ][ $objHash ][ $useCapture ] as $l ) {
if ( $l[ 1 ] === $listener )
}
//Finally add the listener.
self::$_listeners[ $type ][ $objHash ][ $useCapture ][ ] = array (
0 => $priority,
1 => $listener
);
//Now rearrange listeners by priority
rsort ( self::$_listeners[ $type ][ $objHash ][ $useCapture ] );
return $this;
}
/**
- @param string $type
- @param string|array $listener
- @param bool $useCapture
- @return Zend_Event_Dispatcher
*/
final public function removeEventListener ( $type, $listener, $useCapture = false ) {
$objHash = spl_object_hash ( $this->_getDispatchObj ( ) );
$useCapture = ( bool ) $useCapture;
if ( ! isset ( self::$_listeners[ $type ][ $objHash ][ $useCapture ] ) )
return $this;
foreach ( self::$_listeners[ $type ][ $objHash ][ $useCapture ] as $k => $l ) {
if ( $l[ 1 ] === $listener )
}
return $this;
}
/**
- @param string|array|null $type If null, all listeners will be removed.
- @return Zend_Event_Dispatcher
*/
final public function removeEventListeners ( $type = null ) {
$objHash = spl_object_hash ( $this->_getDispatchObj ( ) );
if ( null === $type )
elseif ( is_array ( $type ) )
else
foreach ( $types as $type ) {
if ( isset ( self::$_listeners[ $type ][ $objHash ] ) )
}
return $this;
}
/**
- @param Zend_Event $event Instance of Zend_Event to dispatch.
- @throws Zend_Event_Dispatcher_Exception If listener function returned with a exception.
- @return bool True if event dispatched successfully.
*/
final public function dispatchEvent ( Zend_Event $event ) {
$last = null;
$dispatchTree = array ();
//Put 'at target' phase to dispatchTree.
$objHash = spl_object_hash ( $this->_getDispatchObj ( ) );
if ( isset ( self::$_listeners[ $event->type ][ $objHash ][ false ] ) )
//Prepare dispatch trees for capture and if needed, bubble phase.
foreach ( debug_backtrace ( ) as $branch ) {
if ( ! isset ( $branch[ 'object' ] ) or ! $branch[ 'object' ] instanceof Zend_Event_Dispatcher_Interface )
break;
if ( $branch[ 'object' ] === $this or $branch[ 'object' ] === $this->_getDispatchObj ( ) )
continue;
if ( $last !== $branch[ 'object' ] ) {
$last = $branch[ 'object' ];
$objHash = spl_object_hash ( $last );
if ( isset ( self::$_listeners[ $event->type ][ $objHash ][ true ] ) )
if ( $event->bubbles and isset ( self::$_listeners[ $event->type ][ $objHash ][ false ] ) )
}
}
//Start dispatching.
$stopPropagation = false;
try {
foreach ( $dispatchTree as $dispatcher ) {
//$dispatcher = array (0 => $obj, 1 => phase, 2 => array(listener, ...))
foreach ( $dispatcher[ 2 ] as $listener ) {
$evt = $event->cloneEvent ( $dispatcher[ 1 ], $this->_getDispatchObj ( ), $dispatcher[ 0 ] );
if ( false === call_user_func ( $listener[ 1 ], $evt ) )
if ( true === $evt->stopPropagation )
if ( true === $evt->stopImmediatePropagation )
}
if ( true === $stopPropagation )
}
} catch ( Exception $e )
return true;
}
/**
- @param string $type
- @return bool
*/
final public function hasEventListener ( $type )Unknown macro: { return isset ( self}
/**
- @param string $type Event type
- @return bool
*/
final public function willEventTrigger ( $type ) {
//No events at all for this type
if ( ! isset ( self::$_listeners[ $type ] ) )
return false;
foreach ( debug_backtrace ( ) as $branch )
return false;
}
}
/**
- @see Zend_Event_Exception
*/
require_once 'AVlib/Event/Exception.php';
/**
- @author Alvar Vilu <alvar.vilu@msn.com>
*
*/
class Zend_Event_Dispatcher_Exception extends Zend_Event_Exception
{}
interface Zend_Event_Dispatcher_Interface
/**
- @author Alvar Vilu <alvar.vilu@msn.com>
*
*/
class Zend_Event_PhaseUnknown macro: { /** * main -> target * * @var int */ const CAPTURING = 1; /** * at target * * @var int */ const AT_TARGET = 2; /** * target -> main * * @var int */ const BUBBLING = 3; }