You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.7 KiB
180 lines
5.7 KiB
<?php |
|
/** |
|
* @link http://www.yiiframework.com/ |
|
* @copyright Copyright (c) 2008 Yii Software LLC |
|
* @license http://www.yiiframework.com/license/ |
|
*/ |
|
|
|
namespace yii\base; |
|
|
|
/** |
|
* Event is the base class for all event classes. |
|
* |
|
* It encapsulates the parameters associated with an event. |
|
* The [[sender]] property describes who raises the event. |
|
* And the [[handled]] property indicates if the event is handled. |
|
* If an event handler sets [[handled]] to be true, the rest of the |
|
* uninvoked handlers will no longer be called to handle the event. |
|
* |
|
* Additionally, when attaching an event handler, extra data may be passed |
|
* and be available via the [[data]] property when the event handler is invoked. |
|
* |
|
* @author Qiang Xue <qiang.xue@gmail.com> |
|
* @since 2.0 |
|
*/ |
|
class Event extends Object |
|
{ |
|
/** |
|
* @var string the event name. This property is set by [[Component::trigger()]]. |
|
* Event handlers may use this property to check what event it is handling. |
|
*/ |
|
public $name; |
|
/** |
|
* @var object the sender of this event. If not set, this property will be |
|
* set as the object whose "trigger()" method is called. |
|
*/ |
|
public $sender; |
|
/** |
|
* @var boolean whether the event is handled. Defaults to false. |
|
* When a handler sets this to be true, the event processing will stop and |
|
* ignore the rest of the uninvoked event handlers. |
|
*/ |
|
public $handled = false; |
|
/** |
|
* @var mixed the data that is passed to [[Component::on()]] when attaching an event handler. |
|
* Note that this varies according to which event handler is currently executing. |
|
*/ |
|
public $data; |
|
|
|
private static $_events = []; |
|
|
|
/** |
|
* Attaches an event handler to a class-level event. |
|
* |
|
* When a class-level event is triggered, event handlers attached |
|
* to that class and all parent classes will be invoked. |
|
* |
|
* For example, the following code attaches an event handler to `ActiveRecord`'s |
|
* `afterInsert` event: |
|
* |
|
* ~~~ |
|
* Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { |
|
* Yii::trace(get_class($event->sender) . ' is inserted.'); |
|
* }); |
|
* ~~~ |
|
* |
|
* The handler will be invoked for EVERY successful ActiveRecord insertion. |
|
* |
|
* For more details about how to declare an event handler, please refer to [[Component::on()]]. |
|
* |
|
* @param string $class the fully qualified class name to which the event handler needs to attach |
|
* @param string $name the event name |
|
* @param callback $handler the event handler |
|
* @param mixed $data the data to be passed to the event handler when the event is triggered. |
|
* When the event handler is invoked, this data can be accessed via [[Event::data]]. |
|
* @see off() |
|
*/ |
|
public static function on($class, $name, $handler, $data = null) |
|
{ |
|
self::$_events[$name][ltrim($class, '\\')][] = [$handler, $data]; |
|
} |
|
|
|
/** |
|
* Detaches an event handler from a class-level event. |
|
* |
|
* This method is the opposite of [[on()]]. |
|
* |
|
* @param string $class the fully qualified class name from which the event handler needs to be detached |
|
* @param string $name the event name |
|
* @param callback $handler the event handler to be removed. |
|
* If it is null, all handlers attached to the named event will be removed. |
|
* @return boolean if a handler is found and detached |
|
* @see on() |
|
*/ |
|
public static function off($class, $name, $handler = null) |
|
{ |
|
$class = ltrim($class, '\\'); |
|
if (empty(self::$_events[$name][$class])) { |
|
return false; |
|
} |
|
if ($handler === null) { |
|
unset(self::$_events[$name][$class]); |
|
return true; |
|
} else { |
|
$removed = false; |
|
foreach (self::$_events[$name][$class] as $i => $event) { |
|
if ($event[0] === $handler) { |
|
unset(self::$_events[$name][$class][$i]); |
|
$removed = true; |
|
} |
|
} |
|
if ($removed) { |
|
self::$_events[$name][$class] = array_values(self::$_events[$name][$class]); |
|
} |
|
return $removed; |
|
} |
|
} |
|
|
|
/** |
|
* Returns a value indicating whether there is any handler attached to the specified class-level event. |
|
* Note that this method will also check all parent classes to see if there is any handler attached |
|
* to the named event. |
|
* @param string|object $class the object or the fully qualified class name specifying the class-level event |
|
* @param string $name the event name |
|
* @return boolean whether there is any handler attached to the event. |
|
*/ |
|
public static function hasHandlers($class, $name) |
|
{ |
|
if (empty(self::$_events[$name])) { |
|
return false; |
|
} |
|
if (is_object($class)) { |
|
$class = get_class($class); |
|
} else { |
|
$class = ltrim($class, '\\'); |
|
} |
|
do { |
|
if (!empty(self::$_events[$name][$class])) { |
|
return true; |
|
} |
|
} while (($class = get_parent_class($class)) !== false); |
|
return false; |
|
} |
|
|
|
/** |
|
* Triggers a class-level event. |
|
* This method will cause invocation of event handlers that are attached to the named event |
|
* for the specified class and all its parent classes. |
|
* @param string|object $class the object or the fully qualified class name specifying the class-level event |
|
* @param string $name the event name |
|
* @param Event $event the event parameter. If not set, a default [[Event]] object will be created. |
|
*/ |
|
public static function trigger($class, $name, $event = null) |
|
{ |
|
if (empty(self::$_events[$name])) { |
|
return; |
|
} |
|
if ($event === null) { |
|
$event = new self; |
|
} |
|
$event->handled = false; |
|
$event->name = $name; |
|
|
|
if (is_object($class)) { |
|
$class = get_class($class); |
|
} else { |
|
$class = ltrim($class, '\\'); |
|
} |
|
do { |
|
if (!empty(self::$_events[$name][$class])) { |
|
foreach (self::$_events[$name][$class] as $handler) { |
|
$event->data = $handler[1]; |
|
call_user_func($handler[0], $event); |
|
if ($event instanceof Event && $event->handled) { |
|
return; |
|
} |
|
} |
|
} |
|
} while (($class = get_parent_class($class)) !== false); |
|
} |
|
}
|
|
|