From 1978a4efca3cf10607bb7a4f0ba013cfbcb8e51c Mon Sep 17 00:00:00 2001 From: Qiang Xue Date: Mon, 30 Jan 2012 13:27:12 -0500 Subject: [PATCH] ... --- framework/YiiBase.php | 28 +- framework/base/Object.php | 27 +- framework/db/ar/ActiveQuery.php | 542 ++++++++++++++++++++++-- framework/db/ar/ActiveQueryBuilder.php | 17 + framework/db/ar/ActiveRecord.php | 28 +- framework/db/dao/BaseQuery.php | 724 --------------------------------- framework/db/dao/Query.php | 685 ++++++++++++++++++++++++++++++- framework/db/dao/QueryBuilder.php | 63 ++- 8 files changed, 1282 insertions(+), 832 deletions(-) delete mode 100644 framework/db/dao/BaseQuery.php diff --git a/framework/YiiBase.php b/framework/YiiBase.php index b962c19..f647792 100644 --- a/framework/YiiBase.php +++ b/framework/YiiBase.php @@ -358,25 +358,25 @@ class YiiBase $class = static::import($class, true); } - if (($n = func_num_args()-1) > 0) { + if (($n = func_num_args()) > 1) { $args = func_get_args(); - array_shift($args); // remove $config - } - - if ($n === 0) { - $object = new $class; - } elseif ($n === 1) { - $object = new $class($args[0]); - } elseif ($n === 2) { - $object = new $class($args[0], $args[1]); - } elseif ($n === 3) { - $object = new $class($args[0], $args[1], $args[2]); + if ($n === 2) { + $object = new $class($args[1]); + } elseif ($n === 3) { + $object = new $class($args[1], $args[2]); + } elseif ($n === 4) { + $object = new $class($args[1], $args[2], $args[3]); + } else { + array_shift($args); // remove $config + $r = new \ReflectionClass($class); + $object = $r->newInstanceArgs($args); + } } else { - $r = new \ReflectionClass($class); - $object = $r->newInstanceArgs($args); + $object = new $class; } $class = '\\' . get_class($object); + if (isset(\Yii::$objectConfig[$class])) { $config = array_merge(\Yii::$objectConfig[$class], $config); } diff --git a/framework/base/Object.php b/framework/base/Object.php index af72f2a..78385fc 100644 --- a/framework/base/Object.php +++ b/framework/base/Object.php @@ -302,22 +302,21 @@ class Object { $class = '\\' . get_called_class(); - if (($n = func_num_args()-1) > 0) { + if (($n = func_num_args()) > 1) { $args = func_get_args(); - array_shift($args); // remove $config - } - - if ($n === 0) { - $object = new $class; - } elseif ($n === 1) { - $object = new $class($args[0]); - } elseif ($n === 2) { - $object = new $class($args[0], $args[1]); - } elseif ($n === 3) { - $object = new $class($args[0], $args[1], $args[2]); + if ($n === 2) { + $object = new $class($args[1]); + } elseif ($n === 3) { + $object = new $class($args[1], $args[2]); + } elseif ($n === 4) { + $object = new $class($args[1], $args[2], $args[3]); + } else { + array_shift($args); // remove $config + $r = new \ReflectionClass($class); + $object = $r->newInstanceArgs($args); + } } else { - $r = new \ReflectionClass($class); - $object = $r->newInstanceArgs($args); + $object = new $class; } if (isset(\Yii::$objectConfig[$class])) { diff --git a/framework/db/ar/ActiveQuery.php b/framework/db/ar/ActiveQuery.php index b1f0872..5a10953 100644 --- a/framework/db/ar/ActiveQuery.php +++ b/framework/db/ar/ActiveQuery.php @@ -10,8 +10,8 @@ namespace yii\db\ar; -use yii\db\dao\BaseQuery; use yii\base\VectorIterator; +use yii\db\dao\Query; /** * ActiveFinder.php is ... @@ -20,31 +20,45 @@ use yii\base\VectorIterator; * @author Qiang Xue * @since 2.0 */ -class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, \Countable +class ActiveQuery extends \yii\base\Object implements \IteratorAggregate, \ArrayAccess, \Countable { public $modelClass; + /** + * @var \yii\db\dao\Query the Query object + */ + public $query; + public $with; - public $alias; + public $tableAlias; public $indexBy; public $asArray; + public $scopes; public $records; public $sql; + public function __construct($modelClass) + { + $this->modelClass = $modelClass; + $this->query = new Query; + } + public function all($refresh = false) { if ($this->records === null || $refresh) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } return $this->records; } - public function one($refresh = false) + public function one($refresh = false, $limitOne = true) { if ($this->records === null || $refresh) { - $this->limit = 1; - $this->records = $this->performQuery(); + if ($limitOne) { + $this->limit(1); + } + $this->records = $this->findRecords(); } if (isset($this->records[0])) { return $this->records[0]; @@ -53,6 +67,11 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, } } + public function exists() + { + + } + public function asArray($value = true) { $this->asArray = $value; @@ -71,9 +90,9 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, return $this; } - public function alias($tableAlias) + public function tableAlias($value) { - $this->alias = $tableAlias; + $this->tableAlias = $value; return $this; } @@ -123,7 +142,7 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, public function getIterator() { if ($this->records === null) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } return new VectorIterator($this->records); } @@ -142,7 +161,7 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, return $this->performCountQuery(); } else { if ($this->records === null) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } return count($this->records); } @@ -158,7 +177,7 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, public function offsetExists($offset) { if ($this->records === null) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } return isset($this->records[$offset]); } @@ -175,7 +194,7 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, public function offsetGet($offset) { if ($this->records === null) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } return isset($this->records[$offset]) ? $this->records[$offset] : null; } @@ -194,7 +213,7 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, public function offsetSet($offset, $item) { if ($this->records === null) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } $this->records[$offset] = $item; } @@ -210,37 +229,502 @@ class ActiveQuery extends BaseQuery implements \IteratorAggregate, \ArrayAccess, public function offsetUnset($offset) { if ($this->records === null) { - $this->records = $this->performQuery(); + $this->records = $this->findRecords(); } unset($this->records[$offset]); } - protected function performQuery() + /** + * Sets the SELECT part of the query. + * @param mixed $columns the columns to be selected. Defaults to '*', meaning all columns. + * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')). + * 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 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 BaseQuery the query object itself + */ + public function select($columns = '*', $option = '') { - $db = $this->getDbConnection(); - $this->sql = $this->getSql($db); - $command = $db->createCommand($this->sql); - $command->bindValues($this->params); + $this->query->select($columns, $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->query->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 BaseQuery the query object itself + */ + public function from($tables) + { + $this->query->from($tables); + return $this; + } + + /** + * Sets the WHERE part of the query. + * + * The method requires a $condition parameter, and optionally a $params parameter + * specifying the values to be bound to the query. + * + * The $condition parameter should be either a string (e.g. 'id=1') or an array. + * If the latter, it must be in one of the following two formats: + * + * - hash format: `array('column1' => value1, 'column2' => value2, ...)` + * - operator format: `array(operator, operand1, operand2, ...)` + * + * A condition in hash format represents the following SQL expression in general: + * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, + * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used + * in the generated expression. Below are some examples: + * + * - `array('type'=>1, 'status'=>2)` generates `(type=1) AND (status=2)`. + * - `array('id'=>array(1,2,3), 'status'=>2)` generates `(id IN (1,2,3)) AND (status=2)`. + * - `array('status'=>null) generates `status IS NULL`. + * + * A condition in operator format generates the SQL expression according to the specified operator, which + * can be one of the followings: + * + * - `and`: the operands should be concatenated together using `AND`. For example, + * `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array, + * it will be converted into a string using the rules described here. For example, + * `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`. + * The method will NOT do any quoting or escaping. + * + * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. + * + * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the + * starting and ending values of the range that the column is in. + * For example, `array('between', 'id', 1, 10)` will generate `id BETWEEN 1 AND 10`. + * + * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` + * in the generated condition. + * + * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing + * the range of the values that the column or DB expression should be in. For example, + * `array('in', 'id', array(1,2,3))` will generate `id IN (1,2,3)`. + * The method will properly quote the column name and escape values in the range. + * + * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. + * + * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing + * the values that the column or DB expression should be like. + * For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`. + * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated + * using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate + * `name LIKE '%test%' AND name LIKE '%sample%'`. + * The method will properly quote the column name and escape values in the range. + * + * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` + * predicates when operand 2 is an array. + * + * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` + * in the generated condition. + * + * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate + * the `NOT LIKE` predicates. + * + * @param string|array $condition the conditions that should be put in the WHERE part. + * @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 BaseQuery the query object itself + * @see andWhere() + * @see orWhere() + */ + public function where($condition, $params = array()) + { + if (is_array($params)) { + $this->query->where($condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'AND' operator. + * @param string|array $condition the new WHERE condition. 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 BaseQuery the query object itself + * @see where() + * @see orWhere() + */ + public function andWhere($condition, $params = array()) + { + if (is_array($params)) { + $this->query->andWhere($condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'OR' operator. + * @param string|array $condition the new WHERE condition. 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 BaseQuery the query object itself + * @see where() + * @see andWhere() + */ + public function orWhere($condition, $params = array()) + { + if (is_array($params)) { + $this->query->orWhere($condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Appends an INNER JOIN part to the query. + * @param string $table the table to be joined. + * 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). + * @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. + * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. + * @return BaseQuery the query object itself + */ + public function join($table, $condition, $params = array()) + { + if (is_array($params)) { + $this->query->join($table, $condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Appends a LEFT OUTER JOIN part to the query. + * @param string $table the table to be joined. + * 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). + * @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 BaseQuery the query object itself + */ + public function leftJoin($table, $condition, $params = array()) + { + if (is_array($params)) { + $this->query->leftJoin($table, $condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Appends a RIGHT OUTER JOIN part to the query. + * @param string $table the table to be joined. + * 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). + * @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 BaseQuery the query object itself + */ + public function rightJoin($table, $condition, $params = array()) + { + if (is_array($params)) { + $this->query->rightJoin($table, $condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Appends a CROSS JOIN part to the query. + * Note that not all DBMS support CROSS JOIN. + * @param string $table the table to be joined. + * 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 BaseQuery the query object itself + */ + public function crossJoin($table) + { + $this->query->crossJoin($table); + return $this; + } + + /** + * Appends a NATURAL JOIN part to the query. + * Note that not all DBMS support NATURAL JOIN. + * @param string $table the table to be joined. + * 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 BaseQuery the query object itself + */ + public function naturalJoin($table) + { + $this->query->naturalJoin($table); + return $this; + } + + /** + * Sets the GROUP BY part of the query. + * @param string|array $columns the columns to be grouped by. + * 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 BaseQuery the query object itself + * @see addGroupBy() + */ + public function groupBy($columns) + { + $this->query->groupBy($columns); + return $this; + } + + /** + * Adds additional group-by columns to the existing ones. + * @param string|array $columns additional columns to be grouped by. + * 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 BaseQuery the query object itself + * @see groupBy() + */ + public function addGroupBy($columns) + { + $this->query->addGroupBy($columns); + return $this; + } + + /** + * Sets the HAVING part of the query. + * @param string|array $condition the conditions to be put after HAVING. + * 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 BaseQuery the query object itself + * @see andHaving() + * @see orHaving() + */ + public function having($condition, $params = array()) + { + if (is_array($params)) { + $this->query->having($condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Adds an additional HAVING condition to the existing one. + * The new condition and the existing one will be joined using the 'AND' operator. + * @param string|array $condition the new HAVING condition. 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 BaseQuery the query object itself + * @see having() + * @see orHaving() + */ + public function andHaving($condition, $params = array()) + { + if (is_array($params)) { + $this->query->andHaving($condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Adds an additional HAVING condition to the existing one. + * The new condition and the existing one will be joined using the 'OR' operator. + * @param string|array $condition the new HAVING condition. 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 BaseQuery the query object itself + * @see having() + * @see andHaving() + */ + public function orHaving($condition, $params = array()) + { + if (is_array($params)) { + $this->query->orHaving($condition, $params); + } else { + call_user_func_array(array($this->query, __FUNCTION__), func_get_args()); + } + return $this; + } + + /** + * Sets the ORDER BY part of the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * 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 BaseQuery the query object itself + * @see addOrderBy() + */ + public function orderBy($columns) + { + $this->query->orderBy($columns); + return $this; + } + + /** + * Adds additional ORDER BY columns to the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * 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 BaseQuery the query object itself + * @see orderBy() + */ + public function addOrderBy($columns) + { + $this->query->addOrderBy($columns); + return $this; + } + + /** + * Sets the LIMIT part of the query. + * @param integer $limit the limit + * @return BaseQuery the query object itself + */ + public function limit($limit) + { + $this->query->limit($limit); + return $this; + } + + /** + * Sets the OFFSET part of the query. + * @param integer $offset the offset + * @return BaseQuery the query object itself + */ + public function offset($offset) + { + $this->query->offset($offset); + return $this; + } + + /** + * Appends a SQL statement using UNION operator. + * @param string|Query $sql the SQL statement to be appended using UNION + * @return BaseQuery the query object itself + */ + public function union($sql) + { + $this->query->union($sql); + return $this; + } + + /** + * Sets the parameters to be bound to the query. + * @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 BaseQuery the query object itself + * @see addParams() + */ + public function params($params) + { + $this->query->params($params); + return $this; + } + + /** + * Adds additional parameters to be bound to the query. + * @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 BaseQuery the query object itself + * @see params() + */ + public function addParams($params) + { + $this->query->addParams($params); + return $this; + } + + protected function findRecords() + { + /* + * public $with; + */ + + if ($this->query->from === null) { + $modelClass = $this->modelClass; + $this->query->from = $modelClass::tableName(); + if ($this->tableAlias !== null) { + $this->query->from .= $this->tableAlias; + } + } + $command = $this->query->createCommand($this->getDbConnection()); + $this->sql = $command->getSql(); $rows = $command->queryAll(); if ($this->asArray) { - $records = $rows; + if ($this->indexBy === null) { + return $rows; + } + $records = array(); + foreach ($rows as $row) { + $records[$row[$this->indexBy]] = $row; + } + return $records; } else { $records = array(); $class = $this->modelClass; - foreach ($rows as $row) { - $records[] = $class::populateData($row); + if ($this->indexBy === null) { + foreach ($rows as $row) { + $records[] = $class::populateData($row); + } + } else { + $attribute = $this->indexBy; + foreach ($rows as $row) { + $record = $class::populateData($row); + $records[$record->$attribute] = $record; + } } + return $records; } - return $records; } protected function performCountQuery() { - $this->select = 'COUNT(*)'; - $class = $this->modelClass; - $command = $this->createCommand($class::getDbConnection()); + $this->query->select = 'COUNT(*)'; + $command = $this->query->createCommand($this->getDbConnection()); $this->sql = $command->getSql(); - $count = $command->queryScalar(); - return $count; + return $command->queryScalar(); } } diff --git a/framework/db/ar/ActiveQueryBuilder.php b/framework/db/ar/ActiveQueryBuilder.php index 7c18b51..e17157f 100644 --- a/framework/db/ar/ActiveQueryBuilder.php +++ b/framework/db/ar/ActiveQueryBuilder.php @@ -17,5 +17,22 @@ namespace yii\db\ar; */ class ActiveQueryBuilder extends \yii\base\Object { + /** + * @var \yii\db\dao\QueryBuilder + */ + public $queryBuilder; + /** + * @var ActiveQuery + */ + public $query; + public function __construct($query) + { + $this->query = $query; + } + + public function build() + { + + } } \ No newline at end of file diff --git a/framework/db/ar/ActiveRecord.php b/framework/db/ar/ActiveRecord.php index 19f20ac..f037757 100644 --- a/framework/db/ar/ActiveRecord.php +++ b/framework/db/ar/ActiveRecord.php @@ -53,23 +53,25 @@ abstract class ActiveRecord extends \yii\base\Model /** * @static - * @param string|array|ActiveQuery $q + * @param string|array|Query $q * @return ActiveQuery * @throws \yii\db\Exception */ public static function find($q = null) { - $query = $q instanceof ActiveQuery? $q : static::createQuery(); - $query->modelClass = '\\' . get_called_class(); - $query->from = static::tableName(); - if (is_array($q)) { + $query = static::createActiveQuery(); + if ($q instanceof Query) { + $query->query = $q; + } elseif (is_array($q)) { + // query by attributes $query->where($q); - } elseif ($q !== null && $query !== $q) { + } elseif ($q !== null) { + // query by primary key $primaryKey = static::getMetaData()->table->primaryKey; if (is_string($primaryKey)) { $query->where(array($primaryKey => $q)); } else { - throw new Exception("Multiple column values are required to find by composite primary keys."); + throw new Exception('Composite primary keys require multiple column values.'); } } return $query; @@ -77,21 +79,15 @@ abstract class ActiveRecord extends \yii\base\Model public static function findBySql($sql, $params = array()) { - $query = static::createQuery(); if (!is_array($params)) { $params = func_get_args(); array_shift($params); } - $query->setSql($sql); - $query->modelClass = '\\' . get_called_class(); + $query = static::createActiveQuery(); + $query->sql = $sql; return $query->params($params); } - public static function exists($condition, $params) - { - - } - public static function updateAll() { @@ -107,7 +103,7 @@ abstract class ActiveRecord extends \yii\base\Model } - public static function createQuery() + public static function createActiveQuery() { return new ActiveQuery('\\' . get_called_class()); } diff --git a/framework/db/dao/BaseQuery.php b/framework/db/dao/BaseQuery.php deleted file mode 100644 index d9b1520..0000000 --- a/framework/db/dao/BaseQuery.php +++ /dev/null @@ -1,724 +0,0 @@ - - * @link http://www.yiiframework.com/ - * @copyright Copyright © 2008-2012 Yii Software LLC - * @license http://www.yiiframework.com/license/ - */ - -namespace yii\db\dao; - -/** - * BaseQuery represents a SQL statement in a way that is independent of DBMS. - * - * 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. - * - * BaseQuery provides a set of methods to facilitate the specification of different clauses. - * These methods can be chained together. For example, - * - * ~~~ - * $query = new Query; - * $query->select('id, name') - * ->from('tbl_user') - * ->limit(10); - * // get the actual SQL statement - * echo $query->getSql(); - * // or execute the query - * $users = $query->createCommand()->queryAll(); - * ~~~ - * - * By calling [[getSql()]], we can obtain the actual SQL statement from a Query object. - * And by calling [[createCommand()]], we can get a [[Command]] instance which can be further - * used to perform/execute the DB query against a database. - * - * @property string $sql the SQL statement represented by this query object. - * - * @author Qiang Xue - * @since 2.0 - */ -class BaseQuery extends \yii\base\Object -{ - /** - * @var string|array the columns being selected. This refers to the SELECT clause in a SQL - * statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`). - * If not set, if means all columns. - * @see select() - */ - public $select; - /** - * @var string additional option that should be appended to the 'SELECT' keyword. For example, - * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used. - */ - public $selectOption; - /** - * @var boolean whether to select distinct rows of data only. If this is set true, - * the SELECT clause would be changed to SELECT DISTINCT. - */ - public $distinct; - /** - * @var string|array the table(s) to be selected from. This refers to the FROM clause in a SQL statement. - * It can be either a string (e.g. `'tbl_user, tbl_post'`) or an array (e.g. `array('tbl_user', 'tbl_post')`). - * @see from() - */ - public $from; - /** - * @var string|array query condition. This refers to the WHERE clause in a SQL statement. - * For example, `age > 31 AND team = 1`. - * @see where() - */ - public $where; - /** - * @var integer maximum number of records to be returned. If not set or less than 0, it means no limit. - */ - public $limit; - /** - * @var integer zero-based offset from where the records are to be returned. If not set or - * less than 0, it means starting from the beginning. - */ - public $offset; - /** - * @var string|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement. - * It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`). - */ - public $orderBy; - /** - * @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement. - * It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`). - */ - public $groupBy; - /** - * @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement. - * It can either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g. - * `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`). - * @see join() - */ - public $join; - /** - * @var string|array the condition to be applied in the GROUP BY clause. - * It can be either a string or an array. Please refer to [[where()]] on how to specify the condition. - */ - public $having; - /** - * @var array list of query parameter values indexed by parameter placeholders. - * For example, `array(':name'=>'Dan', ':age'=>31)`. - */ - public $params; - /** - * @var string|array the UNION clause(s) in a SQL statement. This can be either a string - * representing a single UNION clause or an array representing multiple UNION clauses. - * Each union clause can be a string or a `Query` object which refers to the SQL statement. - */ - public $union; - - /** - * Sets the SELECT part of the query. - * @param mixed $columns the columns to be selected. Defaults to '*', meaning all columns. - * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')). - * 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 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 BaseQuery the query object itself - */ - public function select($columns = '*', $option = '') - { - $this->select = $columns; - $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 BaseQuery the query object itself - */ - public function from($tables) - { - $this->from = $tables; - return $this; - } - - /** - * Sets the WHERE part of the query. - * - * The method requires a $condition parameter, and optionally a $params parameter - * specifying the values to be bound to the query. - * - * The $condition parameter should be either a string (e.g. 'id=1') or an array. - * If the latter, it must be in one of the following two formats: - * - * - hash format: `array('column1' => value1, 'column2' => value2, ...)` - * - operator format: `array(operator, operand1, operand2, ...)` - * - * A condition in hash format represents the following SQL expression in general: - * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, - * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used - * in the generated expression. Below are some examples: - * - * - `array('type'=>1, 'status'=>2)` generates `(type=1) AND (status=2)`. - * - `array('id'=>array(1,2,3), 'status'=>2)` generates `(id IN (1,2,3)) AND (status=2)`. - * - `array('status'=>null) generates `status IS NULL`. - * - * A condition in operator format generates the SQL expression according to the specified operator, which - * can be one of the followings: - * - * - `and`: the operands should be concatenated together using `AND`. For example, - * `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array, - * it will be converted into a string using the rules described here. For example, - * `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`. - * The method will NOT do any quoting or escaping. - * - * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. - * - * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the - * starting and ending values of the range that the column is in. - * For example, `array('between', 'id', 1, 10)` will generate `id BETWEEN 1 AND 10`. - * - * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` - * in the generated condition. - * - * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing - * the range of the values that the column or DB expression should be in. For example, - * `array('in', 'id', array(1,2,3))` will generate `id IN (1,2,3)`. - * The method will properly quote the column name and escape values in the range. - * - * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. - * - * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing - * the values that the column or DB expression should be like. - * For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`. - * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated - * using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate - * `name LIKE '%test%' AND name LIKE '%sample%'`. - * The method will properly quote the column name and escape values in the range. - * - * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` - * predicates when operand 2 is an array. - * - * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` - * in the generated condition. - * - * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate - * the `NOT LIKE` predicates. - * - * @param string|array $condition the conditions that should be put in the WHERE part. - * @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 BaseQuery the query object itself - * @see andWhere() - * @see orWhere() - */ - public function where($condition, $params = array()) - { - $this->where = $condition; - if (!is_array($params)) { - $params = func_get_args(); - unset($params[0]); - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new WHERE condition. 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 BaseQuery the query object itself - * @see where() - * @see orWhere() - */ - public function andWhere($condition, $params = array()) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = array('and', $this->where, $condition); - } - if (!is_array($params)) { - $params = func_get_args(); - unset($params[0]); - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional WHERE condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new WHERE condition. 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 BaseQuery the query object itself - * @see where() - * @see andWhere() - */ - public function orWhere($condition, $params = array()) - { - if ($this->where === null) { - $this->where = $condition; - } else { - $this->where = array('or', $this->where, $condition); - } - if (!is_array($params)) { - $params = func_get_args(); - unset($params[0]); - } - $this->addParams($params); - return $this; - } - - /** - * Appends an INNER JOIN part to the query. - * @param string $table the table to be joined. - * 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). - * @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. - * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. - * @return BaseQuery the query object itself - */ - public function join($table, $condition, $params = array()) - { - $this->join[] = array('JOIN', $table, $condition); - if (!is_array($params)) { - $params = func_get_args(); - array_shift($params); - unset($params[0]); - } - return $this->addParams($params); - } - - /** - * Appends a LEFT OUTER JOIN part to the query. - * @param string $table the table to be joined. - * 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). - * @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 BaseQuery the query object itself - */ - public function leftJoin($table, $condition, $params = array()) - { - $this->join[] = array('LEFT JOIN', $table, $condition); - if (!is_array($params)) { - $params = func_get_args(); - array_shift($params); - unset($params[0]); - } - return $this->addParams($params); - } - - /** - * Appends a RIGHT OUTER JOIN part to the query. - * @param string $table the table to be joined. - * 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). - * @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 BaseQuery the query object itself - */ - public function rightJoin($table, $condition, $params = array()) - { - $this->join[] = array('RIGHT JOIN', $table, $condition); - if (!is_array($params)) { - $params = func_get_args(); - array_shift($params); - unset($params[0]); - } - return $this->addParams($params); - } - - /** - * Appends a CROSS JOIN part to the query. - * Note that not all DBMS support CROSS JOIN. - * @param string $table the table to be joined. - * 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 BaseQuery the query object itself - */ - public function crossJoin($table) - { - $this->join[] = array('CROSS JOIN', $table); - return $this; - } - - /** - * Appends a NATURAL JOIN part to the query. - * Note that not all DBMS support NATURAL JOIN. - * @param string $table the table to be joined. - * 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 BaseQuery the query object itself - */ - public function naturalJoin($table) - { - $this->join[] = array('NATURAL JOIN', $table); - return $this; - } - - /** - * Sets the GROUP BY part of the query. - * @param string|array $columns the columns to be grouped by. - * 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 BaseQuery the query object itself - * @see addGroupBy() - */ - public function groupBy($columns) - { - $this->groupBy = $columns; - return $this; - } - - /** - * Adds additional group-by columns to the existing ones. - * @param string|array $columns additional columns to be grouped by. - * 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 BaseQuery the query object itself - * @see groupBy() - */ - public function addGroupBy($columns) - { - if (empty($this->groupBy)) { - $this->groupBy = $columns; - } else { - if (!is_array($this->groupBy)) { - $this->groupBy = preg_split('/\s*,\s*/', trim($this->groupBy), -1, PREG_SPLIT_NO_EMPTY); - } - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - $this->groupBy = array_merge($this->groupBy, $columns); - } - return $this; - } - - /** - * Sets the HAVING part of the query. - * @param string|array $condition the conditions to be put after HAVING. - * 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 BaseQuery the query object itself - * @see andHaving() - * @see orHaving() - */ - public function having($condition, $params = array()) - { - $this->having = $condition; - if (!is_array($params)) { - $params = func_get_args(); - unset($params[0]); - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional HAVING condition to the existing one. - * The new condition and the existing one will be joined using the 'AND' operator. - * @param string|array $condition the new HAVING condition. 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 BaseQuery the query object itself - * @see having() - * @see orHaving() - */ - public function andHaving($condition, $params = array()) - { - if ($this->having === null) { - $this->having = $condition; - } else { - $this->having = array('and', $this->having, $condition); - } - if (!is_array($params)) { - $params = func_get_args(); - unset($params[0]); - } - $this->addParams($params); - return $this; - } - - /** - * Adds an additional HAVING condition to the existing one. - * The new condition and the existing one will be joined using the 'OR' operator. - * @param string|array $condition the new HAVING condition. 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 BaseQuery the query object itself - * @see having() - * @see andHaving() - */ - public function orHaving($condition, $params = array()) - { - if ($this->having === null) { - $this->having = $condition; - } else { - $this->having = array('or', $this->having, $condition); - } - if (!is_array($params)) { - $params = func_get_args(); - unset($params[0]); - } - $this->addParams($params); - return $this; - } - - /** - * Sets the ORDER BY part of the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * 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 BaseQuery the query object itself - * @see addOrderBy() - */ - public function orderBy($columns) - { - $this->orderBy = $columns; - return $this; - } - - /** - * Adds additional ORDER BY columns to the query. - * @param string|array $columns the columns (and the directions) to be ordered by. - * 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 BaseQuery the query object itself - * @see orderBy() - */ - public function addOrderBy($columns) - { - if (empty($this->orderBy)) { - $this->orderBy = $columns; - } else { - if (!is_array($this->orderBy)) { - $this->orderBy = preg_split('/\s*,\s*/', trim($this->orderBy), -1, PREG_SPLIT_NO_EMPTY); - } - if (!is_array($columns)) { - $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); - } - $this->orderBy = array_merge($this->orderBy, $columns); - } - return $this; - } - - /** - * Sets the LIMIT part of the query. - * @param integer $limit the limit - * @return BaseQuery the query object itself - */ - public function limit($limit) - { - $this->limit = $limit; - return $this; - } - - /** - * Sets the OFFSET part of the query. - * @param integer $offset the offset - * @return BaseQuery the query object itself - */ - public function offset($offset) - { - $this->offset = $offset; - return $this; - } - - /** - * Appends a SQL statement using UNION operator. - * @param string $sql the SQL statement to be appended using UNION - * @return BaseQuery the query object itself - */ - public function union($sql) - { - $this->union[] = $sql; - return $this; - } - - /** - * Sets the parameters to be bound to the query. - * @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 BaseQuery the query object itself - * @see addParams() - */ - public function params($params) - { - $this->params = $params; - return $this; - } - - /** - * Adds additional parameters to be bound to the query. - * @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 BaseQuery the query object itself - * @see params() - */ - public function addParams($params) - { - if ($this->params === null) { - $this->params = $params; - } else { - foreach ($params as $name => $value) { - if (is_integer($name)) { - $this->params[] = $value; - } else { - $this->params[$name] = $value; - } - } - } - return $this; - } - - /** - * Merges this query with another one. - * - * The merging is done according to the following rules: - * - * - [[select]]: the union of both queries' [[select]] property values. - * - [[selectOption]], [[distinct]], [[limit]], [[offset]]: the new query - * takes precedence over this query. - * - [[where]], [[having]]: the new query's corresponding property value - * will be 'AND' together with the existing one. - * - [[params]], [[orderBy]], [[groupBy]], [[join]], [[union]]: the new query's - * corresponding property value will be appended to the existing one. - * - * In general, the merging makes the resulting query more restrictive and specific. - * @param BaseQuery $query the new query to be merged with this query. - * @return BaseQuery the query object itself - */ - public function mergeWith($query) - { - if ($this->select !== $query->select) { - if (empty($this->select)) { - $this->select = $query->select; - } elseif (!empty($query->select)) { - $select1 = is_string($this->select) ? preg_split('/\s*,\s*/', trim($this->select), -1, PREG_SPLIT_NO_EMPTY) : $this->select; - $select2 = is_string($query->select) ? preg_split('/\s*,\s*/', trim($query->select), -1, PREG_SPLIT_NO_EMPTY) : $query->select; - $this->select = array_merge($select1, array_diff($select2, $select1)); - } - } - - if ($query->selectOption !== null) { - $this->selectOption = $query->selectOption; - } - - if ($query->distinct !== null) { - $this->distinct = $query->distinct; - } - - if ($query->limit !== null) { - $this->limit = $query->limit; - } - - if ($query->offset !== null) { - $this->offset = $query->offset; - } - - if ($query->where !== null) { - $this->andWhere($query->where); - } - - if ($query->having !== null) { - $this->andHaving($query->having); - } - - if ($query->params !== null) { - $this->addParams($query->params); - } - - if ($query->orderBy !== null) { - $this->addOrderBy($query->orderBy); - } - - if ($query->groupBy !== null) { - $this->addGroupBy($query->groupBy); - } - - if ($query->join !== null) { - if (empty($this->join)) { - $this->join = $query->join; - } else { - if (!is_array($this->join)) { - $this->join = array($this->join); - } - if (is_array($query->join)) { - $this->join = array_merge($this->join, $query->join); - } else { - $this->join[] = $query->join; - } - } - } - - if ($query->union !== null) { - if (empty($this->union)) { - $this->union = $query->union; - } else { - if (!is_array($this->union)) { - $this->union = array($this->union); - } - if (is_array($query->union)) { - $this->union = array_merge($this->union, $query->union); - } else { - $this->union[] = $query->union; - } - } - } - - return $this; - } - - /** - * Resets the query object to its original state. - * @return BaseQuery the query object itself - */ - public function reset() - { - foreach (get_object_vars($this) as $name => $value) { - $this->$name = null; - } - return $this; - } -} diff --git a/framework/db/dao/Query.php b/framework/db/dao/Query.php index a6c4322..b84d71d 100644 --- a/framework/db/dao/Query.php +++ b/framework/db/dao/Query.php @@ -39,7 +39,7 @@ namespace yii\db\dao; * @author Qiang Xue * @since 2.0 */ -class Query extends BaseQuery +class Query extends \yii\base\Object { /** * @var array the operation that this query represents. This refers to the method call as well as @@ -48,7 +48,77 @@ class Query extends BaseQuery * If this property is not set, it means this query represents a SELECT statement. */ public $operation; - + /** + * @var string|array the columns being selected. This refers to the SELECT clause in a SQL + * statement. It can be either a string (e.g. `'id, name'`) or an array (e.g. `array('id', 'name')`). + * If not set, if means all columns. + * @see select() + */ + public $select; + /** + * @var string additional option that should be appended to the 'SELECT' keyword. For example, + * in MySQL, the option 'SQL_CALC_FOUND_ROWS' can be used. + */ + public $selectOption; + /** + * @var boolean whether to select distinct rows of data only. If this is set true, + * the SELECT clause would be changed to SELECT DISTINCT. + */ + public $distinct; + /** + * @var string|array the table(s) to be selected from. This refers to the FROM clause in a SQL statement. + * It can be either a string (e.g. `'tbl_user, tbl_post'`) or an array (e.g. `array('tbl_user', 'tbl_post')`). + * @see from() + */ + public $from; + /** + * @var string|array query condition. This refers to the WHERE clause in a SQL statement. + * For example, `age > 31 AND team = 1`. + * @see where() + */ + public $where; + /** + * @var integer maximum number of records to be returned. If not set or less than 0, it means no limit. + */ + public $limit; + /** + * @var integer zero-based offset from where the records are to be returned. If not set or + * less than 0, it means starting from the beginning. + */ + public $offset; + /** + * @var string|array how to sort the query results. This refers to the ORDER BY clause in a SQL statement. + * It can be either a string (e.g. `'id ASC, name DESC'`) or an array (e.g. `array('id ASC', 'name DESC')`). + */ + public $orderBy; + /** + * @var string|array how to group the query results. This refers to the GROUP BY clause in a SQL statement. + * It can be either a string (e.g. `'company, department'`) or an array (e.g. `array('company', 'department')`). + */ + public $groupBy; + /** + * @var string|array how to join with other tables. This refers to the JOIN clause in a SQL statement. + * It can either a string (e.g. `'LEFT JOIN tbl_user ON tbl_user.id=author_id'`) or an array (e.g. + * `array('LEFT JOIN tbl_user ON tbl_user.id=author_id', 'LEFT JOIN tbl_team ON tbl_team.id=team_id')`). + * @see join() + */ + public $join; + /** + * @var string|array the condition to be applied in the GROUP BY clause. + * It can be either a string or an array. Please refer to [[where()]] on how to specify the condition. + */ + public $having; + /** + * @var array list of query parameter values indexed by parameter placeholders. + * For example, `array(':name'=>'Dan', ':age'=>31)`. + */ + public $params; + /** + * @var string|Query[] the UNION clause(s) in a SQL statement. This can be either a string + * representing a single UNION clause or an array representing multiple UNION clauses. + * Each union clause can be a string or a `Query` object which refers to the SQL statement. + */ + public $union; /** * Generates and returns the SQL statement according to this query. @@ -304,4 +374,615 @@ class Query extends BaseQuery $this->operation = array(__FUNCTION__, $name, $table); return $this; } + + /** + * Sets the SELECT part of the query. + * @param mixed $columns the columns to be selected. Defaults to '*', meaning all columns. + * Columns can be specified in either a string (e.g. "id, name") or an array (e.g. array('id', 'name')). + * 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 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 + */ + public function select($columns = '*', $option = '') + { + $this->select = $columns; + $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 Query 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 + */ + public function from($tables) + { + $this->from = $tables; + return $this; + } + + /** + * Sets the WHERE part of the query. + * + * The method requires a $condition parameter, and optionally a $params parameter + * specifying the values to be bound to the query. + * + * The $condition parameter should be either a string (e.g. 'id=1') or an array. + * If the latter, it must be in one of the following two formats: + * + * - hash format: `array('column1' => value1, 'column2' => value2, ...)` + * - operator format: `array(operator, operand1, operand2, ...)` + * + * A condition in hash format represents the following SQL expression in general: + * `column1=value1 AND column2=value2 AND ...`. In case when a value is an array, + * an `IN` expression will be generated. And if a value is null, `IS NULL` will be used + * in the generated expression. Below are some examples: + * + * - `array('type'=>1, 'status'=>2)` generates `(type=1) AND (status=2)`. + * - `array('id'=>array(1,2,3), 'status'=>2)` generates `(id IN (1,2,3)) AND (status=2)`. + * - `array('status'=>null) generates `status IS NULL`. + * + * A condition in operator format generates the SQL expression according to the specified operator, which + * can be one of the followings: + * + * - `and`: the operands should be concatenated together using `AND`. For example, + * `array('and', 'id=1', 'id=2')` will generate `id=1 AND id=2`. If an operand is an array, + * it will be converted into a string using the rules described here. For example, + * `array('and', 'type=1', array('or', 'id=1', 'id=2'))` will generate `type=1 AND (id=1 OR id=2)`. + * The method will NOT do any quoting or escaping. + * + * - `or`: similar to the `and` operator except that the operands are concatenated using `OR`. + * + * - `between`: operand 1 should be the column name, and operand 2 and 3 should be the + * starting and ending values of the range that the column is in. + * For example, `array('between', 'id', 1, 10)` will generate `id BETWEEN 1 AND 10`. + * + * - `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN` + * in the generated condition. + * + * - `in`: operand 1 should be a column or DB expression, and operand 2 be an array representing + * the range of the values that the column or DB expression should be in. For example, + * `array('in', 'id', array(1,2,3))` will generate `id IN (1,2,3)`. + * The method will properly quote the column name and escape values in the range. + * + * - `not in`: similar to the `in` operator except that `IN` is replaced with `NOT IN` in the generated condition. + * + * - `like`: operand 1 should be a column or DB expression, and operand 2 be a string or an array representing + * the values that the column or DB expression should be like. + * For example, `array('like', 'name', '%tester%')` will generate `name LIKE '%tester%'`. + * When the value range is given as an array, multiple `LIKE` predicates will be generated and concatenated + * using `AND`. For example, `array('like', 'name', array('%test%', '%sample%'))` will generate + * `name LIKE '%test%' AND name LIKE '%sample%'`. + * The method will properly quote the column name and escape values in the range. + * + * - `or like`: similar to the `like` operator except that `OR` is used to concatenate the `LIKE` + * predicates when operand 2 is an array. + * + * - `not like`: similar to the `like` operator except that `LIKE` is replaced with `NOT LIKE` + * in the generated condition. + * + * - `or not like`: similar to the `not like` operator except that `OR` is used to concatenate + * the `NOT LIKE` predicates. + * + * @param string|array $condition the conditions that should be put in the WHERE part. + * @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 + * @see andWhere() + * @see orWhere() + */ + public function where($condition, $params = array()) + { + $this->where = $condition; + if (!is_array($params)) { + $params = func_get_args(); + unset($params[0]); + } + $this->addParams($params); + return $this; + } + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'AND' operator. + * @param string|array $condition the new WHERE condition. 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 + * @see where() + * @see orWhere() + */ + public function andWhere($condition, $params = array()) + { + if ($this->where === null) { + $this->where = $condition; + } else { + $this->where = array('and', $this->where, $condition); + } + if (!is_array($params)) { + $params = func_get_args(); + unset($params[0]); + } + $this->addParams($params); + return $this; + } + + /** + * Adds an additional WHERE condition to the existing one. + * The new condition and the existing one will be joined using the 'OR' operator. + * @param string|array $condition the new WHERE condition. 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 + * @see where() + * @see andWhere() + */ + public function orWhere($condition, $params = array()) + { + if ($this->where === null) { + $this->where = $condition; + } else { + $this->where = array('or', $this->where, $condition); + } + if (!is_array($params)) { + $params = func_get_args(); + unset($params[0]); + } + $this->addParams($params); + return $this; + } + + /** + * Appends an INNER JOIN part to the query. + * @param string $table the table to be joined. + * 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). + * @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. + * Please refer to [[where()]] on alternative syntax of specifying anonymous parameters. + * @return Query the query object itself + */ + public function join($table, $condition, $params = array()) + { + $this->join[] = array('JOIN', $table, $condition); + if (!is_array($params)) { + $params = func_get_args(); + array_shift($params); + unset($params[0]); + } + return $this->addParams($params); + } + + /** + * Appends a LEFT OUTER JOIN part to the query. + * @param string $table the table to be joined. + * 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). + * @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 + */ + public function leftJoin($table, $condition, $params = array()) + { + $this->join[] = array('LEFT JOIN', $table, $condition); + if (!is_array($params)) { + $params = func_get_args(); + array_shift($params); + unset($params[0]); + } + return $this->addParams($params); + } + + /** + * Appends a RIGHT OUTER JOIN part to the query. + * @param string $table the table to be joined. + * 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). + * @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 + */ + public function rightJoin($table, $condition, $params = array()) + { + $this->join[] = array('RIGHT JOIN', $table, $condition); + if (!is_array($params)) { + $params = func_get_args(); + array_shift($params); + unset($params[0]); + } + return $this->addParams($params); + } + + /** + * Appends a CROSS JOIN part to the query. + * Note that not all DBMS support CROSS JOIN. + * @param string $table the table to be joined. + * 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 + */ + public function crossJoin($table) + { + $this->join[] = array('CROSS JOIN', $table); + return $this; + } + + /** + * Appends a NATURAL JOIN part to the query. + * Note that not all DBMS support NATURAL JOIN. + * @param string $table the table to be joined. + * 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 + */ + public function naturalJoin($table) + { + $this->join[] = array('NATURAL JOIN', $table); + return $this; + } + + /** + * Sets the GROUP BY part of the query. + * @param string|array $columns the columns to be grouped by. + * 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 + * @see addGroupBy() + */ + public function groupBy($columns) + { + $this->groupBy = $columns; + return $this; + } + + /** + * Adds additional group-by columns to the existing ones. + * @param string|array $columns additional columns to be grouped by. + * 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 + * @see groupBy() + */ + public function addGroupBy($columns) + { + if (empty($this->groupBy)) { + $this->groupBy = $columns; + } else { + if (!is_array($this->groupBy)) { + $this->groupBy = preg_split('/\s*,\s*/', trim($this->groupBy), -1, PREG_SPLIT_NO_EMPTY); + } + if (!is_array($columns)) { + $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); + } + $this->groupBy = array_merge($this->groupBy, $columns); + } + return $this; + } + + /** + * Sets the HAVING part of the query. + * @param string|array $condition the conditions to be put after HAVING. + * 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 + * @see andHaving() + * @see orHaving() + */ + public function having($condition, $params = array()) + { + $this->having = $condition; + if (!is_array($params)) { + $params = func_get_args(); + unset($params[0]); + } + $this->addParams($params); + return $this; + } + + /** + * Adds an additional HAVING condition to the existing one. + * The new condition and the existing one will be joined using the 'AND' operator. + * @param string|array $condition the new HAVING condition. 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 + * @see having() + * @see orHaving() + */ + public function andHaving($condition, $params = array()) + { + if ($this->having === null) { + $this->having = $condition; + } else { + $this->having = array('and', $this->having, $condition); + } + if (!is_array($params)) { + $params = func_get_args(); + unset($params[0]); + } + $this->addParams($params); + return $this; + } + + /** + * Adds an additional HAVING condition to the existing one. + * The new condition and the existing one will be joined using the 'OR' operator. + * @param string|array $condition the new HAVING condition. 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 + * @see having() + * @see andHaving() + */ + public function orHaving($condition, $params = array()) + { + if ($this->having === null) { + $this->having = $condition; + } else { + $this->having = array('or', $this->having, $condition); + } + if (!is_array($params)) { + $params = func_get_args(); + unset($params[0]); + } + $this->addParams($params); + return $this; + } + + /** + * Sets the ORDER BY part of the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * 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 + * @see addOrderBy() + */ + public function orderBy($columns) + { + $this->orderBy = $columns; + return $this; + } + + /** + * Adds additional ORDER BY columns to the query. + * @param string|array $columns the columns (and the directions) to be ordered by. + * 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 + * @see orderBy() + */ + public function addOrderBy($columns) + { + if (empty($this->orderBy)) { + $this->orderBy = $columns; + } else { + if (!is_array($this->orderBy)) { + $this->orderBy = preg_split('/\s*,\s*/', trim($this->orderBy), -1, PREG_SPLIT_NO_EMPTY); + } + if (!is_array($columns)) { + $columns = preg_split('/\s*,\s*/', trim($columns), -1, PREG_SPLIT_NO_EMPTY); + } + $this->orderBy = array_merge($this->orderBy, $columns); + } + return $this; + } + + /** + * Sets the LIMIT part of the query. + * @param integer $limit the limit + * @return Query the query object itself + */ + public function limit($limit) + { + $this->limit = $limit; + return $this; + } + + /** + * Sets the OFFSET part of the query. + * @param integer $offset the offset + * @return Query the query object itself + */ + public function offset($offset) + { + $this->offset = $offset; + return $this; + } + + /** + * Appends a SQL statement using UNION operator. + * @param string|Query $sql the SQL statement to be appended using UNION + * @return Query the query object itself + */ + public function union($sql) + { + $this->union[] = $sql; + return $this; + } + + /** + * Sets the parameters to be bound to the query. + * @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 + * @see addParams() + */ + public function params($params) + { + $this->params = $params; + return $this; + } + + /** + * Adds additional parameters to be bound to the query. + * @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 + * @see params() + */ + public function addParams($params) + { + if ($params !== array()) { + if ($this->params === null) { + $this->params = $params; + } else { + foreach ($params as $name => $value) { + if (is_integer($name)) { + $this->params[] = $value; + } else { + $this->params[$name] = $value; + } + } + } + } + return $this; + } + + /** + * Merges this query with another one. + * + * The merging is done according to the following rules: + * + * - [[select]]: the union of both queries' [[select]] property values. + * - [[selectOption]], [[distinct]], [[limit]], [[offset]]: the new query + * takes precedence over this query. + * - [[where]], [[having]]: the new query's corresponding property value + * will be 'AND' together with the existing one. + * - [[params]], [[orderBy]], [[groupBy]], [[join]], [[union]]: the new query's + * corresponding property value will be appended to the existing one. + * + * In general, the merging makes the resulting query more restrictive and specific. + * @param Query $query the new query to be merged with this query. + * @return Query the query object itself + */ + public function mergeWith($query) + { + if ($this->select !== $query->select) { + if (empty($this->select)) { + $this->select = $query->select; + } elseif (!empty($query->select)) { + $select1 = is_string($this->select) ? preg_split('/\s*,\s*/', trim($this->select), -1, PREG_SPLIT_NO_EMPTY) : $this->select; + $select2 = is_string($query->select) ? preg_split('/\s*,\s*/', trim($query->select), -1, PREG_SPLIT_NO_EMPTY) : $query->select; + $this->select = array_merge($select1, array_diff($select2, $select1)); + } + } + + if ($query->selectOption !== null) { + $this->selectOption = $query->selectOption; + } + + if ($query->distinct !== null) { + $this->distinct = $query->distinct; + } + + if ($query->limit !== null) { + $this->limit = $query->limit; + } + + if ($query->offset !== null) { + $this->offset = $query->offset; + } + + if ($query->where !== null) { + $this->andWhere($query->where); + } + + if ($query->having !== null) { + $this->andHaving($query->having); + } + + if ($query->params !== null) { + $this->addParams($query->params); + } + + if ($query->orderBy !== null) { + $this->addOrderBy($query->orderBy); + } + + if ($query->groupBy !== null) { + $this->addGroupBy($query->groupBy); + } + + if ($query->join !== null) { + if (empty($this->join)) { + $this->join = $query->join; + } else { + if (!is_array($this->join)) { + $this->join = array($this->join); + } + if (is_array($query->join)) { + $this->join = array_merge($this->join, $query->join); + } else { + $this->join[] = $query->join; + } + } + } + + if ($query->union !== null) { + if (empty($this->union)) { + $this->union = $query->union; + } else { + if (!is_array($this->union)) { + $this->union = array($this->union); + } + if (is_array($query->union)) { + $this->union = array_merge($this->union, $query->union); + } else { + $this->union[] = $query->union; + } + } + } + + return $this; + } + + /** + * Resets the query object to its original state. + * @return Query the query object itself + */ + public function reset() + { + foreach (get_object_vars($this) as $name => $value) { + $this->$name = null; + } + return $this; + } } diff --git a/framework/db/dao/QueryBuilder.php b/framework/db/dao/QueryBuilder.php index 80b2b92..0fa41c5 100644 --- a/framework/db/dao/QueryBuilder.php +++ b/framework/db/dao/QueryBuilder.php @@ -24,33 +24,28 @@ use yii\db\Exception; class QueryBuilder extends \yii\base\Object { /** - * @var array the abstract column types mapped to physical column types. - * This is mainly used to support creating/modifying tables using DB-independent data type specifications. - * Child classes should override this property to declare supported type mappings. - */ - public $typeMap = array(); - /** * @var Connection the database connection. */ public $connection; /** - * @var Driver the database driver used for this query builder. - */ - public $driver; - /** * @var string the separator between different fragments of a SQL statement. * Defaults to an empty space. This is mainly used by [[build()]] when generating a SQL statement. */ public $separator = " "; /** - * @var Query the Query object that is currently processed by the query builder to generate a SQL statement. - * This property will be set null upon completion of [[build()]]. - */ - public $query; - /** * @var boolean whether to automatically quote table and column names when generating SQL statements. */ public $autoQuote = true; + /** + * @var array the abstract column types mapped to physical column types. + * This is mainly used to support creating/modifying tables using DB-independent data type specifications. + * Child classes should override this property to declare supported type mappings. + */ + public $typeMap = array(); + /** + * @var Query the Query object that is currently processed by the query builder to generate a SQL statement. + */ + public $query; /** * Constructor. @@ -59,7 +54,6 @@ class QueryBuilder extends \yii\base\Object public function __construct($connection) { $this->connection = $connection; - $this->driver = $connection->getDriver(); } /** @@ -74,8 +68,9 @@ class QueryBuilder extends \yii\base\Object $this->query = $query; if ($query->operation !== null) { // non-SELECT query - $method = array_shift($query->operation); - $sql = call_user_func_array(array($this, $method), $query->operation); + $params = $query->operation; + $method = array_shift($params); + return call_user_func_array(array($this, $method), $params); } else { // SELECT query $clauses = array( @@ -89,10 +84,8 @@ class QueryBuilder extends \yii\base\Object $this->buildOrderBy(), $this->buildLimit(), ); - $sql = implode($this->separator, array_filter($clauses)); + return implode($this->separator, array_filter($clauses)); } - $this->query = null; - return $sql; } /** @@ -477,7 +470,7 @@ class QueryBuilder extends \yii\base\Object /** * Parses the condition specification and generates the corresponding SQL expression. - * @param string|array $condition the condition specification. Please refer to [[Query::where()]] + * @param string|array $condition the condition specification. Please refer to [[BaseQuery::where()]] * on how to specify a condition. * @return string the generated SQL expression * @throws \yii\db\Exception if the condition is in bad format @@ -651,6 +644,7 @@ class QueryBuilder extends \yii\base\Object } if ($this->autoQuote) { + $driver = $this->connection->driver; if (!is_array($columns)) { if (strpos($columns, '(') !== false) { return $select . ' ' . $columns; @@ -663,9 +657,9 @@ class QueryBuilder extends \yii\base\Object $columns[$i] = (string)$column; } elseif (strpos($column, '(') === false) { if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)([\w\-\.])$/', $column, $matches)) { - $columns[$i] = $this->driver->quoteColumnName($matches[1]) . ' AS ' . $this->driver->quoteSimpleColumnName($matches[2]); + $columns[$i] = $driver->quoteColumnName($matches[1]) . ' AS ' . $driver->quoteSimpleColumnName($matches[2]); } else { - $columns[$i] = $this->driver->quoteColumnName($column); + $columns[$i] = $driver->quoteColumnName($column); } } } @@ -690,6 +684,7 @@ class QueryBuilder extends \yii\base\Object $tables = $this->query->from; if ($this->autoQuote) { + $driver = $this->connection->driver; if (!is_array($tables)) { if (strpos($tables, '(') !== false) { return 'FROM ' . $tables; @@ -700,9 +695,9 @@ class QueryBuilder extends \yii\base\Object foreach ($tables as $i => $table) { if (strpos($table, '(') === false) { if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/i', $table, $matches)) { // with alias - $tables[$i] = $this->driver->quoteTableName($matches[1]) . ' ' . $this->driver->quoteTableName($matches[2]); + $tables[$i] = $driver->quoteTableName($matches[1]) . ' ' . $driver->quoteTableName($matches[2]); } else { - $tables[$i] = $this->driver->quoteTableName($table); + $tables[$i] = $driver->quoteTableName($table); } } } @@ -733,10 +728,11 @@ class QueryBuilder extends \yii\base\Object if (isset($join[0], $join[1])) { $table = $join[1]; if ($this->autoQuote && strpos($table, '(') === false) { + $driver = $this->connection->driver; if (preg_match('/^(.*?)(?i:\s+as\s+|\s+)(.*)$/', $table, $matches)) { // with alias - $table = $this->driver->quoteTableName($matches[1]) . ' ' . $this->driver->quoteTableName($matches[2]); + $table = $driver->quoteTableName($matches[1]) . ' ' . $driver->quoteTableName($matches[2]); } else { - $table = $this->driver->quoteTableName($table); + $table = $driver->quoteTableName($table); } } $joins[$i] = strtoupper($join[0]) . ' ' . $table; @@ -792,6 +788,7 @@ class QueryBuilder extends \yii\base\Object } $columns = $this->query->orderBy; if ($this->autoQuote) { + $driver = $this->connection->driver; if (!is_array($columns)) { if (strpos($columns, '(') !== false) { return 'ORDER BY ' . $columns; @@ -804,9 +801,9 @@ class QueryBuilder extends \yii\base\Object $columns[$i] = (string)$column; } elseif (strpos($column, '(') === false) { if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { - $columns[$i] = $this->driver->quoteColumnName($matches[1]) . ' ' . $matches[2]; + $columns[$i] = $driver->quoteColumnName($matches[1]) . ' ' . $matches[2]; } else { - $columns[$i] = $this->driver->quoteColumnName($column); + $columns[$i] = $driver->quoteColumnName($column); } } } @@ -873,7 +870,7 @@ class QueryBuilder extends \yii\base\Object if (is_object($column)) { $columns[$i] = (string)$column; } elseif (strpos($column, '(') === false) { - $columns[$i] = $this->driver->quoteColumnName($column); + $columns[$i] = $this->quoteColumnName($column); } } } @@ -890,7 +887,7 @@ class QueryBuilder extends \yii\base\Object protected function quoteTableName($name, $simple = false) { if ($this->autoQuote) { - return $simple ? $this->driver->quoteSimpleTableName($name) : $this->driver->quoteTableName($name); + return $this->connection->quoteTableName($name, $simple); } else { return $name; } @@ -906,7 +903,7 @@ class QueryBuilder extends \yii\base\Object protected function quoteColumnName($name, $simple = false) { if ($this->autoQuote) { - return $simple ? $this->driver->quoteSimpleColumnName($name) : $this->driver->quoteColumnName($name); + return $this->connection->quoteColumnName($name, $simple); } else { return $name; }