From 5e1e3fd18aebdd3d92956834700db902b35b5009 Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 1 Aug 2011 11:26:37 -0400 Subject: [PATCH] w --- framework/YiiBase.php | 75 +++++++++++++++++---------------- framework/base/ApplicationComponent.php | 53 +++++++++++++++++++++++ framework/base/Component.php | 35 +++++++++++++++ framework/base/Initable.php | 9 ++++ framework/base/Model.php | 12 ++++++ 5 files changed, 148 insertions(+), 36 deletions(-) create mode 100644 framework/base/ApplicationComponent.php diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 9e89b75..226efb4 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -154,7 +154,7 @@ class YiiBase } if ($alias[0] !== '@') { // a simple class name - if ($forceInclude && self::autoload($alias)) { + if ($forceInclude && static::autoload($alias)) { self::$_imported[$alias] = $alias; } return $alias; @@ -167,7 +167,7 @@ class YiiBase return self::$_imported[$alias] = $className; } - if (($path = self::getAlias(dirname($alias))) === false) { + if (($path = static::getAlias(dirname($alias))) === false) { throw new \yii\base\Exception('Invalid path alias: ' . $alias); } @@ -240,7 +240,7 @@ class YiiBase elseif ($path[0] !== '@') { self::$aliases[$alias] = rtrim($path, '\\/'); } - elseif (($p = self::getAlias($path)) !== false) { + elseif (($p = static::getAlias($path)) !== false) { self::$aliases[$alias] = $p; } else { @@ -277,7 +277,7 @@ class YiiBase if (strpos($className, '\\') !== false) { // convert namespace to path alias, e.g. yii\base\Component to @yii/base/Component $alias = '@' . str_replace('\\', '/', ltrim($className, '\\')); - if (($path = self::getAlias($alias)) !== false) { + if (($path = static::getAlias($alias)) !== false) { include($path . '.php'); return true; } @@ -288,7 +288,7 @@ class YiiBase if (($pos = strpos($className, '_')) !== false) { // convert class name to path alias, e.g. PHPUnit_Framework_TestCase to @PHPUnit/Framework/TestCase $alias = '@' . str_replace('_', '/', $className); - if (($path = self::getAlias($alias)) !== false) { + if (($path = static::getAlias($alias)) !== false) { include($path . '.php'); return true; } @@ -307,15 +307,16 @@ class YiiBase } /** - * Creates an object and initializes its properties based on the given configuration. + * Creates a new component instance using the given configuration. * * The specified configuration can be either a string or an array. - * If the former, the string is treated as the object type which can - * be either a class name or [[getAlias|path alias]]. - * If the latter, the array must contain a `class` element which refers - * to a class name or [[getAlias|path alias]]. The rest of the name-value - * pairs in the array will be used to initialize the corresponding object properties. - * For example, + * If the former, the string is treated as the object type; if the latter, + * the array must contain a `class` element specifying the object type, and + * the rest of the name-value pairs in the array will be used to initialize + * the corresponding object properties. + * + * The object type can be either a class name or [[getAlias|path alias]] of + * the class. For example, * * ~~~ * $component = Yii::createComponent('@app/components/GoogleMap'); @@ -330,63 +331,65 @@ class YiiBase * passed to the constructor of the object being created. * * If a component class implements the [[\yii\base\Initable]] interface, - * its [[\yii\base\Initable::init|init]] method will be invoked after - * its properties have been initialized. + * its [[\yii\base\Initable::preinit|preinit]] and [[\yii\base\Initable::init|init]] + * methods will be invoked BEFORE and AFTER the component properties are initialized, + * respectively. * * @param mixed $config the configuration. It can be either a string or an array. * @return mixed the created object - * @throws \yii\base\Exception if the configuration does not have a 'class' element. + * @throws \yii\base\Exception if the configuration is invalid. */ public static function createComponent($config) { if (is_string($config)) { - $type = $config; + $class = $config; $config = array(); } elseif (isset($config['class'])) { - $type = $config['class']; + $class = $config['class']; unset($config['class']); } else { throw new \yii\base\Exception('Object configuration must be an array containing a "class" element.'); } - if (!class_exists($type, false)) { - $type = Yii::import($type, true); + if (!class_exists($class, false)) { + $class = static::import($class, true); } if (($n = func_num_args()) > 1) { $args = func_get_args(); if ($n === 2) { - $object = new $type($args[1]); + $object = new $class($args[1]); } elseif ($n === 3) { - $object = new $type($args[1], $args[2]); + $object = new $class($args[1], $args[2]); } elseif ($n === 4) { - $object = new $type($args[1], $args[2], $args[3]); + $object = new $class($args[1], $args[2], $args[3]); } else { unset($args[0]); - $class = new ReflectionClass($type); - $object = $class->newInstanceArgs($args); + $r = new ReflectionClass($class); + $object = $r->newInstanceArgs($args); } } else { - $object = new $type; + $object = new $class; } - if ($object instanceof \yii\base\Component) { + if ($object instanceof Initable) { $object->preinit(); - } - - foreach ($config as $key => $value) { - $object->$key = $value; - } - - if ($object instanceof \yii\base\Initable) { + foreach ($config as $name => $value) { + $object->$name = $value; + } $object->init(); } + else { + foreach ($config as $name => $value) { + $object->$name = $value; + } + } return $object; } @@ -401,7 +404,7 @@ class YiiBase public static function trace($msg, $category = 'application') { if (YII_DEBUG) { - self::log($msg, CLogger::LEVEL_TRACE, $category); + static::log($msg, CLogger::LEVEL_TRACE, $category); } } @@ -459,7 +462,7 @@ class YiiBase */ public static function beginProfile($token, $category = 'application') { - self::log('begin:' . $token, CLogger::LEVEL_PROFILE, $category); + static::log('begin:' . $token, CLogger::LEVEL_PROFILE, $category); } /** @@ -471,7 +474,7 @@ class YiiBase */ public static function endProfile($token, $category = 'application') { - self::log('end:' . $token, CLogger::LEVEL_PROFILE, $category); + static::log('end:' . $token, CLogger::LEVEL_PROFILE, $category); } /** diff --git a/framework/base/ApplicationComponent.php b/framework/base/ApplicationComponent.php new file mode 100644 index 0000000..e38f7be --- /dev/null +++ b/framework/base/ApplicationComponent.php @@ -0,0 +1,53 @@ + + * @since 2.0 + */ +abstract class ApplicationComponent extends Component implements Initable +{ + /** + * @var array the behaviors that should be attached to this component. + * The behaviors will be attached to the component when [[init]] is called. + * Please refer to [[Model::behaviors]] on how to specify the value of this property. + */ + public $behaviors = array(); + + /** + * Pre-initializes this component. + * This method is required by the [[Initable]] interface. It is invoked by + * [[\Yii::createComponent]] after its creates the new component instance but + * BEFORE the component properties are initialized. + * + * You may override this method to do work such as setting property default values. + */ + public function preinit() + { + } + + /** + * Initializes the application component. + * This method is invoked after the component is created and its property values are + * initialized. The default implementation will call [[Component::attachBehaviors]] + * to attach behaviors declared in [[behaviors]]. + * If you override this method, make sure to call the parent implementation. + */ + public function init() + { + $this->attachBehaviors($this->behaviors); + } +} diff --git a/framework/base/Component.php b/framework/base/Component.php index 4b9640d..10a1fc7 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -304,6 +304,41 @@ class Component } /** + * Creates a new component instance. + * + * This method differs from the PHP `new` operator in that it does the following + * additional work after the component is created: + * + * - Call [[Initable::preinit|preinit]] if the class implements [[Initable]]; + * - Initialize the component properties using the name-value pairs given as the + * first parameter to this method; + * - Call [[Initable::init|init]] if the class implements [[Initable]]. + * + * Any additional parameters passed to this method will be + * passed to the constructor of the component being created. For example, + * + * @param array $config the name-value pairs that will be used to initialize component properties. + * @return object the created component + * @throws Exception if the configuration is invalid. + */ + public static function create($config = array()) + { + if (!is_array($config)) { + throw new Exception('The $config parameter must be an array.'); + } + + if (($n = func_num_args()) > 1) { + $args = func_get_args(); + $args[0]['class'] = '\\' . get_called_class(); + return call_user_func_array('\Yii::createComponent', $args); + } + else { + $config['class'] = '\\' . get_called_class(); + return \Yii::createComponent($config); + } + } + + /** * 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/Initable.php b/framework/base/Initable.php index 90bc769..02b397b 100644 --- a/framework/base/Initable.php +++ b/framework/base/Initable.php @@ -23,6 +23,15 @@ namespace yii\base; interface Initable { /** + * Pre-initializes this component. + * This method is invoked by [[\Yii::createComponent]] after its creates the new + * component instance, but BEFORE the component properties are initialized. + * + * You may implement this method to do work such as setting property default values. + */ + public function preinit(); + + /** * 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, diff --git a/framework/base/Model.php b/framework/base/Model.php index 918a9df..a21efed 100644 --- a/framework/base/Model.php +++ b/framework/base/Model.php @@ -50,6 +50,18 @@ class Model extends Component implements Initable, \IteratorAggregate, \ArrayAcc } /** + * Pre-initializes this model. + * This method is required by the [[Initable]] interface. It is invoked by + * [[\Yii::createComponent]] after its creates the new model instance but + * BEFORE the model properties are initialized. + * + * You may override this method to do work such as setting property default values. + */ + public function preinit() + { + } + + /** * Initializes this model. * * This method is required by the [[Initable]] interface. It is invoked by [[\Yii::createComponent]]