diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 5767e1f..e6f5a00 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -372,10 +372,18 @@ class YiiBase $object = new $type; } + if ($object instanceof \yii\base\Component) { + $object->preinit(); + } + foreach ($config as $key => $value) { $object->$key = $value; } + if ($object instanceof \yii\base\Component) { + $object->init(); + } + return $object; } diff --git a/framework/base/Component.php b/framework/base/Component.php index dc1ef53..5beb094 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -101,6 +101,8 @@ namespace yii\base; * [[disableBehavior]], respectively. When disabled, the behavior's public properties and methods * cannot be accessed via the component. * + * Components created via [[\Yii::createComponent]] have life cycles. In particular, + * * @author Qiang Xue * @since 2.0 */ @@ -170,17 +172,17 @@ class Component public function __set($name, $value) { $setter = 'set' . $name; - if (method_exists($this, $setter)) { + if (method_exists($this, $setter)) { // write property return $this->$setter($value); } - elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { + elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event $name = strtolower($name); if (!isset($this->_e[$name])) { $this->_e[$name] = new Vector; } return $this->_e[$name]->add($value); } - elseif (is_array($this->_b)) { + elseif (is_array($this->_b)) { // behavior foreach ($this->_b as $object) { if ($object->getEnabled() && (property_exists($object, $name) || $object->canSetProperty($name))) { return $object->$name = $value; @@ -247,16 +249,16 @@ class Component public function __unset($name) { $setter = 'set' . $name; - if (method_exists($this, $setter)) { + if (method_exists($this, $setter)) { // write property $this->$setter(null); } - elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { + elseif (method_exists($this, $name) && strncasecmp($name, 'on', 2) === 0) { // event unset($this->_e[strtolower($name)]); } - elseif (isset($this->_b[$name])) { + elseif (isset($this->_b[$name])) { // behavior $this->detachBehavior($name); } - elseif (is_array($this->_b)) { + elseif (is_array($this->_b)) { // behavior property foreach ($this->_b as $object) { if ($object->getEnabled()) { if (property_exists($object, $name)) { @@ -308,6 +310,46 @@ class Component } /** + * Initializes this component. + * This method is invoked by [[\Yii::createComponent]] after its creates the new + * component instance and initializes the component properties. In other words, + * at this stage, the component has been fully configured. + * + * The default implementation calls [[behaviors]] and registers any available behaviors. + * You may override this method with additional initialization logic (e.g. establish DB connection). + * Make sure you call the parent implementation. + */ + public function init() + { + $this->attachBehaviors($this->behaviors()); + } + + /** + * Returns a list of behaviors that this component should behave as. + * The return value should be an array of behavior configurations indexed by + * behavior names. Each behavior configuration can be either a string specifying + * the behavior class or an array of the following structure: + * + * ~~~ + * 'behaviorName' => array( + * 'class' => 'BehaviorClass', + * 'property1' => 'value1', + * 'property2' => 'value2', + * ) + * ~~~ + * + * Note that the behavior classes must extend from [[Behavior]]. Behaviors declared + * in this method will be attached to the model when [[init]] is invoked. + * + * @return array the behavior configurations. + * @see init + */ + public function behaviors() + { + return array(); + } + + /** * Returns a value indicating whether a property is defined. * A property is defined if there is a getter or setter method * defined in the class. Note, property names are case-insensitive. diff --git a/framework/base/Event.php b/framework/base/Event.php index abb46ec..3ae3818 100644 --- a/framework/base/Event.php +++ b/framework/base/Event.php @@ -42,8 +42,9 @@ class Event extends Component * Constructor. * @param mixed $sender sender of the event */ - public function __construct($sender=null) + public function __construct($sender=null, $params=null) { $this->sender = $sender; + $this->params = $params; } } diff --git a/framework/base/Model.php b/framework/base/Model.php index 43fc3c8..429efb5 100644 --- a/framework/base/Model.php +++ b/framework/base/Model.php @@ -31,22 +31,10 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess public function __construct($scenario='') { $this->_scenario = $scenario; - $this->init(); - $this->attachBehaviors($this->behaviors()); $this->afterConstruct(); } /** - * Initializes this model. - * This method is invoked in the constructor right after [[scenario]] is set. - * You may override this method to provide code that is needed to initialize the model (e.g. setting - * initial property values.) - */ - public function init() - { - } - - /** * Returns the list of attribute names. * By default, this method returns all public non-static properties of the class. * You may override this method to change the default. @@ -73,7 +61,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess /** * Returns the validation rules for attributes. * - * Validation rules are used by [[validate()]] to check if attribute values are valid. + * Validation rules are used by [[validate]] to check if attribute values are valid. * Child classes may override this method to declare different validation rules. * * Each rule is an array with the following structure: @@ -131,32 +119,6 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess } /** - * Returns a list of behaviors that this model should behave as. - * The return value should be an array of behavior configurations indexed by - * behavior names. Each behavior configuration can be either a string specifying - * the behavior class or an array of the following structure: - * - * ~~~ - * 'behaviorName' => array( - * 'class' => 'BehaviorClass', - * 'property1' => 'value1', - * 'property2' => 'value2', - * ) - * ~~~ - * - * Note, the behavior classes must extend from [[Behavior]]. Behaviors declared - * in this method will be attached to the model when it is instantiated. - * - * For more details about behaviors, see [[Component]]. - * - * @return array the behavior configurations. - */ - public function behaviors() - { - return array(); - } - - /** * Returns the attribute labels. * * Attribute labels are mainly used for display purpose. For example, given an attribute @@ -215,8 +177,8 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess } /** - * This method is invoked after a model instance is created by new operator. - * The default implementation raises the {@link onAfterConstruct} event. + * This method is invoked at the end of model constructor. + * The default implementation raises the [[onAfterConstruct]] event. * You may override this method to do postprocessing after model creation. * Make sure you call the parent implementation so that the event is raised properly. */ @@ -229,7 +191,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess /** * This method is invoked before validation starts. - * The default implementation calls {@link onBeforeValidate} to raise an event. + * The default implementation raises the [[onBeforeValidate]] event. * You may override this method to do preliminary checks before validation. * Make sure the parent implementation is invoked so that the event can be raised. * @return boolean whether validation should be executed. Defaults to true. @@ -247,7 +209,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess /** * This method is invoked after validation ends. - * The default implementation calls {@link onAfterValidate} to raise an event. + * The default implementation raises the [[onAfterValidate]] event. * You may override this method to do postprocessing after validation. * Make sure the parent implementation is invoked so that the event can be raised. */ @@ -353,7 +315,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess * Returns a value indicating whether the attribute is required. * This is determined by checking if the attribute is associated with a * [[\yii\validators\RequiredValidator|required]] validation rule in the - * current {@link scenario}. + * current [[scenario]]. * @param string $attribute attribute name * @return boolean whether the attribute is required */ @@ -601,7 +563,7 @@ class Model extends Component implements \IteratorAggregate, \ArrayAccess /** * Returns the attribute names that are safe to be massively assigned. - * A safe attribute is one that is associated with a validation rule in the current {@link scenario}. + * A safe attribute is one that is associated with a validation rule in the current [[scenario]]. * @return array safe attribute names */ public function getSafeAttributeNames() diff --git a/todo.txt b/todo.txt index 7cbe208..8b85adf 100644 --- a/todo.txt +++ b/todo.txt @@ -1,3 +1,4 @@ +- add more doc to Model - CompareValidator::clientValidateAttribute(): search for "CHtml::activeId" - FileValidator, UniqueValidator, ExistValidator, DateValidator: TBD - Can consider merging UniqueValidator and ExistValidator and using a NOT property. @@ -8,4 +9,6 @@ * initialize properties * init * ... - * destruct \ No newline at end of file + * destruct +- get/setFlash() should be moved to session component +- support optional parameter in URL patterns \ No newline at end of file