diff --git a/framework/YiiBase.php b/framework/YiiBase.php index 7d1ab98..b962c19 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -76,16 +76,16 @@ class YiiBase /** * @var array initial property values that will be applied to objects newly created via [[createObject]]. * The array keys are fully qualified namespaced class names, and the array values are the corresponding - * name-value pairs for initializing the created class instances. Make sure the class names do NOT have - * the leading backslashes. For example, + * name-value pairs for initializing the created class instances. Please make sure class names are starting + * with a backslash. For example, * * ~~~ * array( - * 'mycompany\foo\Bar' => array( + * '\Bar' => array( * 'prop1' => 'value1', * 'prop2' => 'value2', * ), - * 'mycompany\foo\Car' => array( + * '\mycompany\foo\Car' => array( * 'prop1' => 'value1', * 'prop2' => 'value2', * ), @@ -301,6 +301,9 @@ class YiiBase /** * Creates a new object using the given configuration. * + * The class of the object can be any class. It does not have to + * extend from [[Object]] or [[Component]]. + * * The configuration can be either a string or an array. * If a string, it is treated as the *object type*; if an array, * it must contain a `class` element specifying the *object type*, and @@ -310,7 +313,7 @@ class YiiBase * The object type can be either a class name or the [[getAlias|alias]] of * the class. For example, * - * - `\app\components\GoogleMap`: namespaced class + * - `\app\components\GoogleMap`: full qualified namespaced class. * - `@app/components/GoogleMap`: an alias * * This method does the following steps to create an object: @@ -319,7 +322,7 @@ class YiiBase * - if [[objectConfig]] contains the configuration for the object class, * it will be merged with the configuration passed to this method; * - initialize the object properties using the configuration passed to this method; - * - call the `init` method of the object if it implements the [[yii\base\Initable]] interface. + * - call the `init` method of the object if it implements the [[\yii\base\Initable]] interface. * * Below are some usage examples: * @@ -337,6 +340,7 @@ class YiiBase * @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 is invalid. + * @see \yii\base\Object::newInstance() */ public static function createObject($config) { @@ -372,9 +376,9 @@ class YiiBase $object = $r->newInstanceArgs($args); } - $c = get_class($object); - if (isset(\Yii::$objectConfig[$c])) { - $config = array_merge(\Yii::$objectConfig[$c], $config); + $class = '\\' . get_class($object); + if (isset(\Yii::$objectConfig[$class])) { + $config = array_merge(\Yii::$objectConfig[$class], $config); } foreach ($config as $name => $value) { diff --git a/framework/base/Component.php b/framework/base/Component.php index 1705904..8f1f660 100644 --- a/framework/base/Component.php +++ b/framework/base/Component.php @@ -461,11 +461,8 @@ class Component extends Object */ public function attachBehavior($name, $behavior) { - if (!($behavior instanceof Behavior)) { - $behavior = \Yii::createObject($behavior); - } - $behavior->attach($this); - return $this->_b[$name] = $behavior; + $this->ensureBehaviors(); + return $this->attachBehaviorInternal($name, $behavior); } /** @@ -478,8 +475,9 @@ class Component extends Object */ public function attachBehaviors($behaviors) { + $this->ensureBehaviors(); foreach ($behaviors as $name => $behavior) { - $this->attachBehavior($name, $behavior); + $this->attachBehaviorInternal($name, $behavior); } } @@ -523,8 +521,23 @@ class Component extends Object if ($this->_b === null) { $this->_b = array(); foreach ($this->behaviors() as $name => $behavior) { - $this->attachBehavior($name, $behavior); + $this->attachBehaviorInternal($name, $behavior); } } } + + /** + * Attaches a behavior to this component. + * @param string $name the name of the behavior. + * @param string|array|Behavior $behavior the behavior to be attached + * @return Behavior the attached behavior. + */ + private function attachBehaviorInternal($name, $behavior) + { + if (!($behavior instanceof Behavior)) { + $behavior = \Yii::createObject($behavior); + } + $behavior->attach($this); + return $this->_b[$name] = $behavior; + } } diff --git a/framework/base/Object.php b/framework/base/Object.php index 5d4103b..af72f2a 100644 --- a/framework/base/Object.php +++ b/framework/base/Object.php @@ -300,8 +300,7 @@ class Object */ public static function newInstance($config = array()) { - $c = get_called_class(); - $class = '\\' . $c; + $class = '\\' . get_called_class(); if (($n = func_num_args()-1) > 0) { $args = func_get_args(); @@ -321,8 +320,8 @@ class Object $object = $r->newInstanceArgs($args); } - if (isset(\Yii::$objectConfig[$c])) { - $config = array_merge(\Yii::$objectConfig[$c], $config); + if (isset(\Yii::$objectConfig[$class])) { + $config = array_merge(\Yii::$objectConfig[$class], $config); } foreach ($config as $name => $value) { diff --git a/framework/db/ar/ActiveQuery.php b/framework/db/ar/ActiveQuery.php index 8d7caca..b1f0872 100644 --- a/framework/db/ar/ActiveQuery.php +++ b/framework/db/ar/ActiveQuery.php @@ -10,6 +10,9 @@ namespace yii\db\ar; +use yii\db\dao\BaseQuery; +use yii\base\VectorIterator; + /** * ActiveFinder.php is ... * todo: add SQL monitor @@ -17,86 +20,72 @@ namespace yii\db\ar; * @author Qiang Xue * @since 2.0 */ -class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ArrayAccess, \Countable +class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, \Countable { public $modelClass; public $with; public $alias; - public $index; + public $indexBy; + public $asArray; - private $_count; - private $_sql; - private $_countSql; - private $_asArray; - private $_records; + public $records; + public $sql; - public function all() + public function all($refresh = false) { - return $this->performQuery(); + if ($this->records === null || $refresh) { + $this->records = $this->performQuery(); + } + return $this->records; } - public function one() + public function one($refresh = false) { - $this->limit = 1; - $records = $this->performQuery(); - if (isset($records[0])) { - $this->_count = 1; - return $records[0]; + if ($this->records === null || $refresh) { + $this->limit = 1; + $this->records = $this->performQuery(); + } + if (isset($this->records[0])) { + return $this->records[0]; } else { - $this->_count = 0; return null; } } public function asArray($value = true) { - $this->_asArray = $value; - } - - protected function performQuery() - { - $class = $this->modelClass; - $db = $class::getDbConnection(); - $this->_sql = $this->getSql($db); - $command = $db->createCommand($this->_sql); - $command->bindValues($this->params); - $rows = $command->queryAll(); - if ($this->_asArray) { - $records = $rows; - } else { - $records = array(); - foreach ($rows as $row) { - $records[] = $class::populateRecord($row); - } - } - $this->_count = count($records); - return $records; + $this->asArray = $value; + return $this; } public function with() { - + $this->with = func_get_args(); + return $this; } -// -// public function getSql($connection = null) -// { -// -// } - public function setSql($value) + public function indexBy($column) { - $this->_sql = $value; + $this->indexBy = $column; + return $this; } - public function getCountSql() + public function alias($tableAlias) { - + $this->alias = $tableAlias; + return $this; } - public function getOneSql() + /** + * Returns the database connection used by this query. + * This method returns the connection used by the [[modelClass]]. + * @return \yii\db\dao\Connection the database connection used by this query + */ + public function getDbConnection() { - + $class = $this->modelClass; + return $class::getDbConnection(); } /** @@ -105,23 +94,7 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function getCount() { - if ($this->_count !== null) { - return $this->_count; - } else { - return $this->_count = $this->performCountQuery(); - } - } - - protected function performCountQuery() - { - $select = $this->select; - $this->select = 'COUNT(*)'; - $class = $this->modelClass; - $command = $this->createCommand($class::getDbConnection()); - $this->_countSql = $command->getSql(); - $count = $command->queryScalar(); - $this->select = $select; - return $count; + return $this->count(); } /** @@ -137,7 +110,7 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function cache($duration, $dependency = null, $queryCount = 1) { - $this->connection->cache($duration, $dependency, $queryCount); + $this->getDbConnection()->cache($duration, $dependency, $queryCount); return $this; } @@ -149,19 +122,30 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function getIterator() { - $records = $this->performQuery(); - return new \yii\base\VectorIterator($records); + if ($this->records === null) { + $this->records = $this->performQuery(); + } + return new VectorIterator($this->records); } /** * Returns the number of items in the vector. * This method is required by the SPL `Countable` interface. * It will be implicitly called when you use `count($vector)`. + * @param boolean $bySql whether to get the count by performing a SQL COUNT query. + * If this is false, it will count the number of records brought back by this query. * @return integer number of items in the vector. */ - public function count() + public function count($bySql = false) { - return $this->getCount(); + if ($bySql) { + return $this->performCountQuery(); + } else { + if ($this->records === null) { + $this->records = $this->performQuery(); + } + return count($this->records); + } } /** @@ -173,10 +157,10 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function offsetExists($offset) { - if ($this->_records === null) { - $this->_records = $this->performQuery(); + if ($this->records === null) { + $this->records = $this->performQuery(); } - return isset($this->_records[$offset]); + return isset($this->records[$offset]); } /** @@ -190,10 +174,10 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function offsetGet($offset) { - if ($this->_records === null) { - $this->_records = $this->performQuery(); + if ($this->records === null) { + $this->records = $this->performQuery(); } - return isset($this->_records[$offset]) ? $this->_records[$offset] : null; + return isset($this->records[$offset]) ? $this->records[$offset] : null; } /** @@ -209,10 +193,10 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function offsetSet($offset, $item) { - if ($this->_records === null) { - $this->_records = $this->performQuery(); + if ($this->records === null) { + $this->records = $this->performQuery(); } - $this->_records[$offset] = $item; + $this->records[$offset] = $item; } /** @@ -225,9 +209,38 @@ class ActiveQuery extends \yii\db\dao\BaseQuery implements \IteratorAggregate, \ */ public function offsetUnset($offset) { - if ($this->_records === null) { - $this->_records = $this->performQuery(); + if ($this->records === null) { + $this->records = $this->performQuery(); + } + unset($this->records[$offset]); + } + + protected function performQuery() + { + $db = $this->getDbConnection(); + $this->sql = $this->getSql($db); + $command = $db->createCommand($this->sql); + $command->bindValues($this->params); + $rows = $command->queryAll(); + if ($this->asArray) { + $records = $rows; + } else { + $records = array(); + $class = $this->modelClass; + foreach ($rows as $row) { + $records[] = $class::populateData($row); + } } - unset($this->_records[$offset]); + return $records; + } + + protected function performCountQuery() + { + $this->select = 'COUNT(*)'; + $class = $this->modelClass; + $command = $this->createCommand($class::getDbConnection()); + $this->sql = $command->getSql(); + $count = $command->queryScalar(); + return $count; } } diff --git a/framework/db/ar/ActiveRecord.php b/framework/db/ar/ActiveRecord.php index e13a9c6..19f20ac 100644 --- a/framework/db/ar/ActiveRecord.php +++ b/framework/db/ar/ActiveRecord.php @@ -308,7 +308,7 @@ abstract class ActiveRecord extends \yii\base\Model */ public function __construct($scenario = 'insert') { - if ($scenario === null) // internally used by populateRecord() and model() + if ($scenario === null) // internally used by populateData() and model() { return; } @@ -1186,7 +1186,7 @@ abstract class ActiveRecord extends \yii\base\Model * @return ActiveRecord the newly created active record. The class of the object is the same as the model class. * Null is returned if the input data is false. */ - public static function populateRecord($row) + public static function populateData($row) { $record = static::instantiate($row); $record->setScenario('update'); @@ -1204,7 +1204,7 @@ abstract class ActiveRecord extends \yii\base\Model /** * Creates an active record instance. - * This method is called by {@link populateRecord} and {@link populateRecords}. + * This method is called by {@link populateData}. * You may override this method if the instance being created * depends the attributes that are to be populated to the record. * For example, by creating a record based on the value of a column, diff --git a/framework/db/dao/BaseQuery.php b/framework/db/dao/BaseQuery.php index 82a2431..d9b1520 100644 --- a/framework/db/dao/BaseQuery.php +++ b/framework/db/dao/BaseQuery.php @@ -11,12 +11,12 @@ namespace yii\db\dao; /** - * Query represents a SQL statement in a way that is independent of DBMS. + * BaseQuery represents a SQL statement in a way that is independent of DBMS. * - * Query not only can represent a SELECT statement, it can also represent INSERT, UPDATE, DELETE, + * BaseQuery not only can represent a SELECT statement, it can also represent INSERT, UPDATE, DELETE, * and other commonly used DDL statements, such as CREATE TABLE, CREATE INDEX, etc. * - * Query provides a set of methods to facilitate the specification of different clauses. + * BaseQuery provides a set of methods to facilitate the specification of different clauses. * These methods can be chained together. For example, * * ~~~ @@ -120,27 +120,36 @@ class BaseQuery extends \yii\base\Object * Columns can contain table prefixes (e.g. "tbl_user.id") and/or column aliases (e.g. "tbl_user.id AS user_id"). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). - * @param boolean $distinct whether to use 'SELECT DISTINCT'. * @param string $option additional option that should be appended to the 'SELECT' keyword. For example, * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used. - * @return Query the query object itself + * @return BaseQuery the query object itself */ - public function select($columns = '*', $distinct = false, $option = '') + public function select($columns = '*', $option = '') { $this->select = $columns; - $this->distinct = $distinct; $this->selectOption = $option; return $this; } /** + * Sets the value indicating whether to SELECT DISTINCT or not. + * @param bool $value whether to SELECT DISTINCT or not. + * @return BaseQuery the query object itself + */ + public function distinct($value = true) + { + $this->distinct = $value; + return $this; + } + + /** * Sets the FROM part of the query. * @param mixed $tables the table(s) to be selected from. This can be either a string (e.g. 'tbl_user') * or an array (e.g. array('tbl_user', 'tbl_profile')) specifying one or several table names. * Table names can contain schema prefixes (e.g. 'public.tbl_user') and/or table aliases (e.g. 'tbl_user u'). * The method will automatically quote the table names unless it contains some parenthesis * (which means the table is given as a sub-query or DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function from($tables) { @@ -215,7 +224,7 @@ class BaseQuery extends \yii\base\Object * @param array $params the parameters (name=>value) to be bound to the query. * For anonymous parameters, they can alternatively be specified as separate parameters to this method. * For example, `where('type=? AND status=?', 100, 1)`. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see andWhere() * @see orWhere() */ @@ -237,7 +246,7 @@ class BaseQuery extends \yii\base\Object * on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see where() * @see orWhere() */ @@ -263,7 +272,7 @@ class BaseQuery extends \yii\base\Object * on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see where() * @see andWhere() */ @@ -292,7 +301,7 @@ class BaseQuery extends \yii\base\Object * Please refer to [[where()]] on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function join($table, $condition, $params = array()) { @@ -314,7 +323,7 @@ class BaseQuery extends \yii\base\Object * @param string|array $condition the join condition that should appear in the ON part. * Please refer to [[where()]] on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function leftJoin($table, $condition, $params = array()) { @@ -336,7 +345,7 @@ class BaseQuery extends \yii\base\Object * @param string|array $condition the join condition that should appear in the ON part. * Please refer to [[where()]] on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function rightJoin($table, $condition, $params = array()) { @@ -356,7 +365,7 @@ class BaseQuery extends \yii\base\Object * Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). * The method will automatically quote the table name unless it contains some parenthesis * (which means the table is given as a sub-query or DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function crossJoin($table) { @@ -371,7 +380,7 @@ class BaseQuery extends \yii\base\Object * Table name can contain schema prefix (e.g. 'public.tbl_user') and/or table alias (e.g. 'tbl_user u'). * The method will automatically quote the table name unless it contains some parenthesis * (which means the table is given as a sub-query or DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function naturalJoin($table) { @@ -385,7 +394,7 @@ class BaseQuery extends \yii\base\Object * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself * @see addGroupBy() */ public function groupBy($columns) @@ -400,7 +409,7 @@ class BaseQuery extends \yii\base\Object * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself * @see groupBy() */ public function addGroupBy($columns) @@ -425,7 +434,7 @@ class BaseQuery extends \yii\base\Object * Please refer to [[where()]] on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see andHaving() * @see orHaving() */ @@ -447,7 +456,7 @@ class BaseQuery extends \yii\base\Object * on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see having() * @see orHaving() */ @@ -473,7 +482,7 @@ class BaseQuery extends \yii\base\Object * on how to specify this parameter. * @param array $params the parameters (name=>value) to be bound to the query. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see having() * @see andHaving() */ @@ -498,7 +507,7 @@ class BaseQuery extends \yii\base\Object * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself * @see addOrderBy() */ public function orderBy($columns) @@ -513,7 +522,7 @@ class BaseQuery extends \yii\base\Object * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array (e.g. array('id ASC', 'name DESC')). * The method will automatically quote the column names unless a column contains some parenthesis * (which means the column contains a DB expression). - * @return Query the query object itself + * @return BaseQuery the query object itself * @see orderBy() */ public function addOrderBy($columns) @@ -535,7 +544,7 @@ class BaseQuery extends \yii\base\Object /** * Sets the LIMIT part of the query. * @param integer $limit the limit - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function limit($limit) { @@ -546,7 +555,7 @@ class BaseQuery extends \yii\base\Object /** * Sets the OFFSET part of the query. * @param integer $offset the offset - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function offset($offset) { @@ -557,7 +566,7 @@ class BaseQuery extends \yii\base\Object /** * Appends a SQL statement using UNION operator. * @param string $sql the SQL statement to be appended using UNION - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function union($sql) { @@ -570,7 +579,7 @@ class BaseQuery extends \yii\base\Object * @param array list of query parameter values indexed by parameter placeholders. * For example, `array(':name'=>'Dan', ':age'=>31)`. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see addParams() */ public function params($params) @@ -584,7 +593,7 @@ class BaseQuery extends \yii\base\Object * @param array list of query parameter values indexed by parameter placeholders. * For example, `array(':name'=>'Dan', ':age'=>31)`. * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return Query the query object itself + * @return BaseQuery the query object itself * @see params() */ public function addParams($params) @@ -703,7 +712,7 @@ class BaseQuery extends \yii\base\Object /** * Resets the query object to its original state. - * @return Query the query object itself + * @return BaseQuery the query object itself */ public function reset() { diff --git a/framework/db/dao/Query.php b/framework/db/dao/Query.php index d48744e..a6c4322 100644 --- a/framework/db/dao/Query.php +++ b/framework/db/dao/Query.php @@ -43,7 +43,7 @@ class Query extends BaseQuery { /** * @var array the operation that this query represents. This refers to the method call as well as - * the corresponding parameters for constructing a non-query SQL statement (e.g. INSERT, CREATE TABLE). + * the corresponding parameters for constructing a non-select SQL statement (e.g. INSERT, CREATE TABLE). * This property is mainly maintained by methods such as [[insert()]], [[update()]], [[createTable()]]. * If this property is not set, it means this query represents a SELECT statement. */ diff --git a/upgrade.md b/upgrade.md index d38beba..803be7c 100644 --- a/upgrade.md +++ b/upgrade.md @@ -31,6 +31,9 @@ Upgrading from v1.1.x - The root alias `@yii` now represents the framework installation directory. In 1.x, this is named as `system`. We also removed `zii` root alias. +- Object serves as the base class that supports properties. And Component extends + from Object and supports events and behaviors. Behaviors declared in + Component::behaviors() are attached on demand. - `CList` is renamed to `Vector`, and `CMap` is renamed to `Dictionary`. Other collection classes are dropped in favor of SPL classes.