From 7a2343276e89f83108614032eb5eb45f0997a908 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Fri, 30 Mar 2012 23:11:07 -0400 Subject: [PATCH] ... --- docs/api/framework/base/Component.md | 79 ++++++++++++++++++++++++++ docs/api/framework/base/Object.md | 39 +++++++++++++ framework/base/Behavior.php | 4 +- framework/base/Component.php | 75 +++++------------------- framework/base/Dictionary.php | 6 +- framework/base/Event.php | 17 +++--- framework/base/Initable.php | 6 +- framework/base/Model.php | 1 + framework/base/ModelBehavior.php | 10 ++-- framework/base/ModelEvent.php | 2 +- framework/base/Object.php | 47 +--------------- framework/base/Vector.php | 10 ++-- framework/db/ar/ActiveRecordBehavior.php | 97 ++++++++++++++------------------ framework/db/dao/Command.php | 4 +- 14 files changed, 208 insertions(+), 189 deletions(-) create mode 100644 docs/api/framework/base/Component.md create mode 100644 docs/api/framework/base/Object.md diff --git a/docs/api/framework/base/Component.md b/docs/api/framework/base/Component.md new file mode 100644 index 0000000..3dbf2cb --- /dev/null +++ b/docs/api/framework/base/Component.md @@ -0,0 +1,79 @@ +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 diff --git a/docs/api/framework/base/Object.md b/docs/api/framework/base/Object.md new file mode 100644 index 0000000..d61486d --- /dev/null +++ b/docs/api/framework/base/Object.md @@ -0,0 +1,39 @@ +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 diff --git a/framework/base/Behavior.php b/framework/base/Behavior.php index dde95b4..db9388a 100644 --- a/framework/base/Behavior.php +++ b/framework/base/Behavior.php @@ -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() { diff --git a/framework/base/Component.php b/framework/base/Component.php index f2bbd45..f2c4835 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -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 * @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; } diff --git a/framework/base/Dictionary.php b/framework/base/Dictionary.php index d655f77..928db95 100644 --- a/framework/base/Dictionary.php +++ b/framework/base/Dictionary.php @@ -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 * @since 2.0 */ diff --git a/framework/base/Event.php b/framework/base/Event.php index 737f9b7..44b3254 100644 --- a/framework/base/Event.php +++ b/framework/base/Event.php @@ -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 * @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; } } diff --git a/framework/base/Initable.php b/framework/base/Initable.php index 298f6ca..eb2d3bd 100644 --- a/framework/base/Initable.php +++ b/framework/base/Initable.php @@ -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 diff --git a/framework/base/Model.php b/framework/base/Model.php index aa361b1..a92a2ec 100644 --- a/framework/base/Model.php +++ b/framework/base/Model.php @@ -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)); } diff --git a/framework/base/ModelBehavior.php b/framework/base/ModelBehavior.php index fc2d71d..06ae29a 100644 --- a/framework/base/ModelBehavior.php +++ b/framework/base/ModelBehavior.php @@ -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) diff --git a/framework/base/ModelEvent.php b/framework/base/ModelEvent.php index d09795e..8f078e8 100644 --- a/framework/base/ModelEvent.php +++ b/framework/base/ModelEvent.php @@ -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; } diff --git a/framework/base/Object.php b/framework/base/Object.php index 96fe825..08d736d 100644 --- a/framework/base/Object.php +++ b/framework/base/Object.php @@ -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 * @since 2.0 diff --git a/framework/base/Vector.php b/framework/base/Vector.php index 7c6dadd..dbb7335 100644 --- a/framework/base/Vector.php +++ b/framework/base/Vector.php @@ -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 * @since 2.0 diff --git a/framework/db/ar/ActiveRecordBehavior.php b/framework/db/ar/ActiveRecordBehavior.php index 9556701..b5d9305 100644 --- a/framework/db/ar/ActiveRecordBehavior.php +++ b/framework/db/ar/ActiveRecordBehavior.php @@ -1,115 +1,102 @@ * @link http://www.yiiframework.com/ - * @copyright Copyright © 2008-2011 Yii Software LLC + * @copyright Copyright © 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 * @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) - { - } } diff --git a/framework/db/dao/Command.php b/framework/db/dao/Command.php index 6df40a9..ef3c4d4 100644 --- a/framework/db/dao/Command.php +++ b/framework/db/dao/Command.php @@ -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); }