Commit 7a234327 by Qiang Xue

...

parent 7ff5f127
Component provides the *event* and *behavior* features, in addition to the *property* feature which is implemented in
its parent class [[Object]].
Event is a way to "inject" custom code into existing code at certain places. For example, a comment object can trigger
an "add" event when the user adds a comment. We can write custom code and attach it to this event so that when the event
is triggered, our custom code will be executed.
An event is identified by a name (unique within the class it is defined). Event names are *case-sensitive*.
An event can be attached with one or multiple PHP callbacks, called *event handlers*. One can call [[trigger()]] to
raise an event. When an event is raised, the attached event handlers will be invoked automatically in the order they are
attached to the event.
To attach an event handler to an event, call [[on()]]. For example,
~~~
$comment->on('add', function($event) {
// send email notification
});
~~~
In the above, we attach an anonymous function to the "add" event of the comment. Valid event handlers include:
- anonymous function: `function($event) { ... }`
- object method: `array($object, 'handleAdd')`
- static method: `array('Page', 'handleAdd')`
- global function: `'handleAdd'`
The signature of an event handler should be like the following:
~~~
function foo($event)
~~~
where `$event` is an [[Event]] object which includes parameters associated with the event.
One can also attach an event handler to an event when configuring a component with a configuration array. The syntax is
like the following:
~~~
array(
'on add' => function($event) { ... }
)
~~~
where `on add` stands for attaching an event to the `add` event.
One can call [[getEventHandlers()]] to retrieve all event handlers that are attached to a specified event. Because this
method returns a [[Vector]] object, we can manipulate this object to attach/detach event handlers, or adjust their
relative orders.
~~~
$handlers = $comment->getEventHandlers('add');
$handlers->insertAt(0, $callback); // attach a handler as the first one
$handlers[] = $callback; // attach a handler as the last one
unset($handlers[0]); // detach the first handler
~~~
A behavior is an instance of [[Behavior]] or its child class. A component can be attached with one or multiple
behaviors. When a behavior is attached to a component, its public properties and methods can be accessed via the
component directly, as if the component owns those properties and methods.
To attach a behavior to a component, declare it in [[behaviors()]], or explicitly call [[attachBehavior]]. Behaviors
declared in [[behaviors()]] are automatically attached to the corresponding component.
One can also attach a behavior to a component when configuring it with a configuration array. The syntax is like the
following:
~~~
array(
'as tree' => array(
'class' => 'Tree',
),
)
~~~
where `as tree` stands for attaching a behavior named `tree`, and the array will be passed to [[\Yii::createObject()]]
to create the behavior object.
\ No newline at end of file
A property is defined by a getter method (e.g. `getLabel`), and/or a setter method (e.g. `setLabel`). For example,
the following getter and setter methods define a property named `label`:
~~~
private $_label;
public function getLabel()
{
return $this->_label;
}
public function setLabel($value)
{
$this->_label = $value;
}
~~~
Property names are *case-insensitive*.
A property can be accessed like a member variable of an object. Reading or writing a property will cause the invocation
of the corresponding getter or setter method. For example,
~~~
// equivalent to $label = $object->getLabel();
$label = $object->label;
// equivalent to $object->setLabel('abc');
$object->label = 'abc';
~~~
If a property has only a getter method and has no setter method, it is considered as *read-only*. In this case, trying
to modify the property value will cause an exception.
One can call [[hasProperty]], [[canGetProperty]] and/or [[canSetProperty]] to check the existence of a property.
Besides the property feature, the Object class defines a static method [[create]] which provides a convenient
alternative way of creating a new object instance.
The Object class also defines the [[evaluateExpression]] method so that a PHP expression or callback can be dynamically
evaluated within the context of an object.
\ No newline at end of file
......@@ -12,7 +12,7 @@ namespace yii\base;
/**
* Behavior is the base class for all behavior classes.
*
* A behavior can be used to enhance the functionality of an existing component.
* A behavior can be used to enhance the functionality of an existing component without modifying its code.
* In particular, it can "inject" its own methods and properties into the component
* and make them directly accessible via the component.
*
......@@ -52,7 +52,7 @@ class Behavior extends \yii\base\Object
* )
* ~~~
*
* @return array events (keys) and the corresponding behavior method names (values).
* @return array events (array keys) and the corresponding event handler methods (array values).
*/
public function events()
{
......
......@@ -10,65 +10,9 @@
namespace yii\base;
/**
* Component is the base class for all component classes in Yii.
* Component is the base class that provides the *property*, *event* and *behavior* features.
*
* Component provides the *event* and *behavior* features, in addition to
* the *property* feature which is implemented in its parent class [[Object]].
*
* Event is a way to "inject" custom code into existing code at certain places.
* For example, a comment object can trigger an "add" event when the user adds
* a comment. We can write custom code and attach it to this event so that
* when the event is triggered, our custom code will be executed.
*
* An event is identified by a name (unique within the class it is defined).
* Event names are *case-sensitive*.
*
* An event can be attached with one or multiple PHP callbacks, called *event handlers*.
* One can call [[trigger()]] to raise an event. When an event is raised, the attached
* event handlers will be invoked automatically in the order they are attached to the event.
*
* To attach an event handler to an event, call [[on()]]. For example,
*
* ~~~
* $comment->on('add', function($event) {
* // send email notification
* });
* ~~~
*
* In the above, we attach an anonymous function to the "add" event of the comment.
* Valid event handlers include:
*
* - anonymous function: `function($event) { ... }`
* - object method: `array($object, 'handleAdd')`
* - static method: `array('Page', 'handleAdd')`
* - global function: `'handleAdd'`
*
* The signature of an event handler should be like the following:
* ~~~
* function foo($event)
* ~~~
*
* where `$event` is an [[Event]] object which includes parameters associated with the event.
*
* One can call [[getEventHandlers()]] to retrieve all event handlers that are attached
* to a specified event. Because this method returns a [[Vector]] object, we can manipulate
* this object to attach/detach event handlers, or adjust their relative orders.
*
* ~~~
* $handlers = $comment->getEventHandlers('add');
* $handlers->insertAt(0, $callback); // attach a handler as the first one
* $handlers[] = $callback; // attach a handler as the last one
* unset($handlers[0]); // detach the first handler
* ~~~
*
*
* A behavior is an instance of [[Behavior]] or its child class. A component can be attached
* with one or multiple behaviors. When a behavior is attached to a component, its public
* properties and methods can be accessed via the component directly, as if the component owns
* those properties and methods.
*
* To attach a behavior to a component, declare it in [[behaviors()]], or explicitly call [[attachBehavior]].
* Behaviors declared in [[behaviors()]] are automatically attached to the corresponding component.
* @include @yii/base/Component.md
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......@@ -134,13 +78,19 @@ class Component extends \yii\base\Object
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) { // write property
if (method_exists($this, $setter)) {
// set property
$this->$setter($value);
return;
} elseif (strncmp($name, 'on ', 3) === 0) { // on event
} elseif (strncmp($name, 'on ', 3) === 0) {
// on event: attach event handler
$name = trim(substr($name, 3));
$this->getEventHandlers($name)->add($value);
return;
} elseif (strncmp($name, 'as ', 3) === 0) {
// as behavior: attach behavior
$name = trim(substr($name, 3));
$this->attachBehavior($name, \Yii::createObject($value));
} else { // behavior property
$this->ensureBehaviors();
foreach ($this->_b as $behavior) {
......@@ -394,7 +344,7 @@ class Component extends \yii\base\Object
* @param string $behavior the behavior name
* @return Behavior the behavior object, or null if the behavior does not exist
*/
public function asa($behavior)
public function getBehavior($behavior)
{
$this->ensureBehaviors();
return isset($this->_b[$behavior]) ? $this->_b[$behavior] : null;
......@@ -493,6 +443,9 @@ class Component extends \yii\base\Object
if (!($behavior instanceof Behavior)) {
$behavior = \Yii::createObject($behavior);
}
if (isset($this->_b[$name])) {
$this->_b[$name]->detach($this);
}
$behavior->attach($this);
return $this->_b[$name] = $behavior;
}
......
......@@ -13,9 +13,9 @@ namespace yii\base;
* Dictionary implements a collection that stores key-value pairs.
*
* You can access, add or remove an item with a key by using
* [[itemAt]], [[add]], and [[remove]].
* [[itemAt()]], [[add()]], and [[remove()]].
*
* To get the number of the items in the dictionary, use [[getCount]].
* To get the number of the items in the dictionary, use [[getCount()]].
*
* Because Dictionary implements a set of SPL interfaces, it can be used
* like a regular PHP array as follows,
......@@ -28,6 +28,8 @@ namespace yii\base;
* $n = count($dictionary); // returns the number of items in the dictionary
* ~~~
*
* @property integer $count the number of items in the dictionary
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
......
......@@ -17,17 +17,16 @@ namespace yii\base;
* 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, an event may specify extra parameters via the [[params]] property.
* Additionally, an event may specify extra parameters via the [[data]] property.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class Event extends Object
class Event extends \yii\base\Object
{
/**
* @var string the event name. This property is set by [[Component::raiseEvent]].
* @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.
* The event name is in lower case.
*/
public $name;
/**
......@@ -41,19 +40,19 @@ class Event extends Object
*/
public $handled = false;
/**
* @var mixed extra parameters associated with the event.
* @var mixed extra data associated with the event.
*/
public $params;
public $data;
/**
* Constructor.
*
* @param mixed $sender sender of the event
* @param mixed $params parameters of the event
* @param mixed $data extra data associated with the event
*/
public function __construct($sender = null, $params = null)
public function __construct($sender = null, $data = null)
{
$this->sender = $sender;
$this->params = $params;
$this->data = $data;
}
}
......@@ -12,9 +12,9 @@ namespace yii\base;
/**
* Initable is an interface indicating a class needs initialization to work properly.
*
* Initable requires a class to implement the [[init]] method.
* When [[\Yii::createObject]] is being used to create a new component which implements
* Initable, it will call the [[init]] method after setting the initial values of the
* Initable requires a class to implement the [[init()]] method.
* When [[\Yii::createObject()]] is being used to create a new component which implements
* Initable, it will call the [[init()]] method after setting the initial values of the
* component properties.
*
* @author Qiang Xue <qiang.xue@gmail.com>
......
......@@ -222,6 +222,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess
*/
public function afterValidate()
{
$this->trigger('afterValidate');
if ($this->hasEventHandlers('onAfterValidate')) {
$this->onAfterValidate(new Event($this));
}
......
......@@ -21,7 +21,7 @@ namespace yii\base;
class ModelBehavior extends Behavior
{
/**
* Declares event handlers for owner's events.
* Declares event handlers for the owner's events.
* The default implementation returns the following event handlers:
*
* - `beforeValidate` event
......@@ -39,8 +39,8 @@ class ModelBehavior extends Behavior
}
/**
* Responds to [[Model::onBeforeValidate]] event.
* Override this method if you want to handle the corresponding event of the [[owner]].
* Responds to the owner's `beforeValidate` event.
* Override this method if you want to handle the `beforeValidate` event of the [[owner]].
* You may set the [[ModelEvent::isValid|isValid]] property of the event parameter
* to be false to cancel the validation process.
* @param ModelEvent $event event parameter
......@@ -50,8 +50,8 @@ class ModelBehavior extends Behavior
}
/**
* Responds to [[Model::onAfterValidate]] event.
* Override this method if you want to handle the corresponding event of the [[owner]].
* Responds to the owner's `afterValidate` event.
* Override this method if you want to handle the `beforeValidate` event of the [[owner]].
* @param Event $event event parameter
*/
public function afterValidate($event)
......
......@@ -21,7 +21,7 @@ class ModelEvent extends Event
{
/**
* @var boolean whether the model is in valid status. Defaults to true.
* A model is in valid status if it passes validation, or other checks.
* A model is in valid status if it passes validations or certain checks.
*/
public $isValid = true;
}
......@@ -10,52 +10,9 @@
namespace yii\base;
/**
* Object is the base class that implements the *property* feature.
* Object is the base class that provides the *property* feature.
*
* A property is defined by a getter method (e.g. `getLabel`),
* and/or a setter method (e.g. `setLabel`). For example, the following
* getter and setter methods define a property named `label`:
*
* ~~~
* private $_label;
*
* public function getLabel()
* {
* return $this->_label;
* }
*
* public function setLabel($value)
* {
* $this->_label = $value;
* }
* ~~~
*
* A property can be accessed like a member variable of an object.
* Reading or writing a property will cause the invocation of the corresponding
* getter or setter method. For example,
*
* ~~~
* // equivalent to $label = $object->getLabel();
* $label = $object->label;
* // equivalent to $object->setLabel('abc');
* $object->label = 'abc';
* ~~~
*
* If a property has only a getter method and has no setter method, it is
* considered as *read-only*. In this case, trying to modify the property value
* will cause an exception.
*
* Property names are *case-insensitive*.
*
* One can call [[hasProperty]], [[canGetProperty]] and/or [[canSetProperty]]
* to check the existence of a property.
*
* Besides the property feature, the Object class defines a static method
* [[create]] which provides a convenient alternative way of creating a new
* object instance.
*
* The Object class also defines the [[evaluateExpression]] method so that a PHP
* expression or callback can be dynamically evaluated within the context of an object.
* @include @yii/base/Object.md
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......
......@@ -13,10 +13,10 @@ namespace yii\base;
* Vector implements an integer-indexed collection class.
*
* You can access, append, insert, remove an item from the vector
* by calling methods such as [[itemAt]], [[add]], [[insertAt]],
* [[remove]] and [[removeAt]].
* by calling methods such as [[itemAt()]], [[add()]], [[insertAt()]],
* [[remove()]] and [[removeAt()]].
*
* To get the number of the items in the vector, use [[getCount]].
* To get the number of the items in the vector, use [[getCount()]].
*
* Because Vector implements a set of SPL interfaces, it can be used
* like a regular PHP array as follows,
......@@ -32,7 +32,9 @@ namespace yii\base;
*
* Note that if you plan to extend Vector by performing additional operations
* with each addition or removal of an item (e.g. performing type check),
* please make sure you override [[insertAt]] and [[removeAt]].
* please make sure you override [[insertAt()]] and [[removeAt()]].
*
* @property integer $count the number of items in the vector
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......
<?php
/**
* CActiveRecordBehavior class file.
* ActiveRecordBehavior class file.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright &copy; 2008-2011 Yii Software LLC
* @copyright Copyright &copy; 2008-2012 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db\ar;
use yii\base\ModelBehavior;
/**
* CActiveRecordBehavior is the base class for behaviors that can be attached to {@link CActiveRecord}.
* Compared with {@link CModelBehavior}, CActiveRecordBehavior attaches to more events
* that are only defined by {@link CActiveRecord}.
* ActiveRecordBehavior is the base class for behaviors that can be attached to [[ActiveRecord]].
*
* Compared to [[\yii\base\ModelBehavior]], ActiveRecordBehavior responds to more events
* that are specific to [[ActiveRecord]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
*/
class CActiveRecordBehavior extends CModelBehavior
class ActiveRecordBehavior extends ModelBehavior
{
/**
* Declares events and the corresponding event handler methods.
* If you override this method, make sure you merge the parent result to the return value.
* @return array events (array keys) and the corresponding event handler methods (array values).
* @see CBehavior::events
* @see \yii\base\Behavior::events()
*/
public function events()
{
return array_merge(parent::events(), array(
'onBeforeInsert' => 'beforeInsert',
'onAfterInsert' => 'afterInsert',
'onBeforeUpdate' => 'beforeUpdate',
'onAfterUpdate' => 'afterUpdate',
'onBeforeDelete' => 'beforeDelete',
'onAfterDelete' => 'afterDelete',
'onBeforeFind' => 'beforeFind',
'onAfterFind' => 'afterFind',
'beforeInsert' => 'beforeInsert',
'afterInsert' => 'afterInsert',
'beforeUpdate' => 'beforeUpdate',
'afterUpdate' => 'afterUpdate',
'beforeDelete' => 'beforeDelete',
'afterDelete' => 'afterDelete',
));
}
/**
* Responds to {@link CActiveRecord::onBeforeSave} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* You may set {@link CModelEvent::isValid} to be false to quit the saving process.
* @param CModelEvent $event event parameter
* Responds to the owner's `beforeInsert` event.
* Overrides this method if you want to handle the corresponding event of the owner.
* You may set the [[ModelEvent::isValid|isValid]] property of the event parameter
* to be false to quit the ActiveRecord inserting process.
* @param \yii\base\ModelEvent $event event parameter
*/
public function beforeInsert($event)
{
}
/**
* Responds to {@link CActiveRecord::onAfterSave} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CModelEvent $event event parameter
* Responds to the owner's `afterInsert` event.
* Overrides this method if you want to handle the corresponding event of the owner.
* @param \yii\base\ModelEvent $event event parameter
*/
public function afterInsert($event)
{
}
/**
* Responds to {@link CActiveRecord::onBeforeSave} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* You may set {@link CModelEvent::isValid} to be false to quit the saving process.
* @param CModelEvent $event event parameter
* Responds to the owner's `beforeUpdate` event.
* Overrides this method if you want to handle the corresponding event of the owner.
* You may set the [[ModelEvent::isValid|isValid]] property of the event parameter
* to be false to quit the ActiveRecord updating process.
* @param \yii\base\ModelEvent $event event parameter
*/
public function beforeUpdate($event)
{
}
/**
* Responds to {@link CActiveRecord::onAfterSave} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CModelEvent $event event parameter
* Responds to the owner's `afterUpdate` event.
* Overrides this method if you want to handle the corresponding event of the owner.
* @param \yii\base\ModelEvent $event event parameter
*/
public function afterUpdate($event)
{
}
/**
* Responds to {@link CActiveRecord::onBeforeDelete} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* You may set {@link CModelEvent::isValid} to be false to quit the deletion process.
* @param CEvent $event event parameter
* Responds to the owner's `beforeDelete` event.
* Overrides this method if you want to handle the corresponding event of the owner.
* You may set the [[ModelEvent::isValid|isValid]] property of the event parameter
* to be false to quit the ActiveRecord deleting process.
* @param \yii\base\ModelEvent $event event parameter
*/
public function beforeDelete($event)
{
}
/**
* Responds to {@link CActiveRecord::onAfterDelete} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CEvent $event event parameter
* Responds to the owner's `afterDelete` event.
* Overrides this method if you want to handle the corresponding event of the owner.
* @param \yii\base\ModelEvent $event event parameter
*/
public function afterDelete($event)
{
}
/**
* Responds to {@link CActiveRecord::onBeforeFind} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CEvent $event event parameter
*/
public function beforeFind($event)
{
}
/**
* Responds to {@link CActiveRecord::onAfterFind} event.
* Overrides this method if you want to handle the corresponding event of the {@link CBehavior::owner owner}.
* @param CEvent $event event parameter
*/
public function afterFind($event)
{
}
}
......@@ -222,7 +222,7 @@ class Command extends \yii\base\Component
}
\Yii::trace("Executing SQL: {$sql}{$paramLog}", __CLASS__);
echo $sql . "\n\n";
//echo $sql . "\n\n";
try {
if ($this->connection->enableProfiling) {
\Yii::beginProfile(__METHOD__ . "($sql)", __CLASS__);
......@@ -355,7 +355,7 @@ echo $sql . "\n\n";
}
\Yii::trace("Querying SQL: {$sql}{$paramLog}", __CLASS__);
echo $sql . "\n\n";
//echo $sql . "\n\n";
if ($db->queryCachingCount > 0 && $db->queryCachingDuration >= 0 && $method !== '') {
$cache = \Yii::$application->getComponent($db->queryCacheID);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment