Browse Source

refactored ActiveRecord classes to use Interfaces and traits

this allows us to implement other activerecord implementations based on
NoSQL dbms
tags/2.0.0-beta
Carsten Brandt 11 years ago
parent
commit
65338972c7
  1. 4
      docs/guide/query-builder.md
  2. 59
      framework/yii/ar/ActiveQueryInterface.php
  3. 16
      framework/yii/ar/ActiveQueryTrait.php
  4. 36
      framework/yii/ar/ActiveRelationInterface.php
  5. 1
      framework/yii/ar/ActiveRelationTrait.php
  6. 20
      framework/yii/data/ActiveDataProvider.php
  7. 10
      framework/yii/db/ActiveQuery.php
  8. 28
      framework/yii/db/ActiveRecord.php
  9. 13
      framework/yii/db/ActiveRelation.php
  10. 20
      framework/yii/db/Query.php
  11. 2
      framework/yii/db/QueryBuilder.php
  12. 205
      framework/yii/db/QueryInterface.php
  13. 109
      framework/yii/db/QueryTrait.php

4
docs/guide/query-builder.md

@ -167,8 +167,8 @@ For ordering results `orderBy` and `addOrderBy` could be used:
```php ```php
$query->orderBy([ $query->orderBy([
'id' => Query::SORT_ASC, 'id' => SORT_ASC,
'name' => Query::SORT_DESC, 'name' => SORT_DESC,
]); ]);
``` ```

59
framework/yii/ar/ActiveQueryInterface.php

@ -0,0 +1,59 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\ar;
use yii\db\QueryInterface;
/**
* ActiveQueryInterface defines the common interface to be implemented by active record relation classes.
*
* A class implementing this interface should also use [[ActiveQueryTrait]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
interface ActiveQueryInterface extends QueryInterface
{
/**
* Sets the [[asArray]] property.
* @param boolean $value whether to return the query results in terms of arrays instead of Active Records.
* @return static the query object itself
*/
public function asArray($value = true);
/**
* Specifies the relations with which this query should be performed.
*
* The parameters to this method can be either one or multiple strings, or a single array
* of relation names and the optional callbacks to customize the relations.
*
* A relation name can refer to a relation defined in [[modelClass]]
* or a sub-relation that stands for a relation of a related record.
* For example, `orders.address` means the `address` relation defined
* in the model class corresponding to the `orders` relation.
*
* The followings are some usage examples:
*
* ~~~
* // find customers together with their orders and country
* Customer::find()->with('orders', 'country')->all();
* // find customers together with their orders and the orders' shipping address
* Customer::find()->with('orders.address')->all();
* // find customers together with their country and orders of status 1
* Customer::find()->with([
* 'orders' => function($query) {
* $query->andWhere('status = 1');
* },
* 'country',
* ])->all();
* ~~~
*
* @return static the query object itself
*/
public function with();
}

16
framework/yii/ar/ActiveQueryTrait.php

@ -10,10 +10,7 @@ namespace yii\ar;
use yii\db\ActiveRecord; use yii\db\ActiveRecord;
/** /**
* ActiveQuery represents a DB query associated with an Active Record class. * ActiveQueryTrait implements the common set of methods that are used by DB queries associated with an Active Record class.
*
* ActiveQuery instances are usually created by [[ActiveRecord::find()]], [[ActiveRecord::findBySql()]]
* and [[ActiveRecord::count()]].
* *
* ActiveQuery mainly provides the following methods to retrieve the query results: * ActiveQuery mainly provides the following methods to retrieve the query results:
* *
@ -150,6 +147,11 @@ trait ActiveQueryTrait
return parent::indexBy($column); return parent::indexBy($column);
} }
/**
* Converts found rows into model instances
* @param array $rows
* @return array|ActiveRecord[]
*/
private function createModels($rows) private function createModels($rows)
{ {
$models = []; $models = [];
@ -187,6 +189,10 @@ trait ActiveQueryTrait
return $models; return $models;
} }
/**
* @param ActiveRecord[] $models
* @param array $with
*/
private function populateRelations(&$models, $with) private function populateRelations(&$models, $with)
{ {
$primaryModel = new $this->modelClass; $primaryModel = new $this->modelClass;
@ -203,7 +209,7 @@ trait ActiveQueryTrait
/** /**
* @param ActiveRecord $model * @param ActiveRecord $model
* @param array $with * @param array $with
* @return ActiveRelation[] * @return ActiveRelationInterface[]
*/ */
private function normalizeRelations($model, $with) private function normalizeRelations($model, $with)
{ {

36
framework/yii/ar/ActiveRelationInterface.php

@ -0,0 +1,36 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\ar;
/**
* ActiveRelationInterface defines the common interface to be implemented by active record relation classes.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
interface ActiveRelationInterface extends ActiveQueryInterface
{
/**
* Specifies the relation associated with the pivot table.
* @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]].
* @param callable $callable a PHP callback for customizing the relation associated with the pivot table.
* Its signature should be `function($query)`, where `$query` is the query to be customized.
* @return static the relation object itself.
*/
public function via($relationName, $callable = null);
/**
* Finds the related records and populates them into the primary models.
* This method is internally used by [[ActiveQuery]]. Do not call it directly.
* @param string $name the relation name
* @param array $primaryModels primary models
* @return array the related models
*/
public function findWith($name, &$primaryModels);
}

1
framework/yii/ar/ActiveRelationTrait.php

@ -23,6 +23,7 @@ use yii\db\ActiveRecord;
* If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method. * If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
trait ActiveRelationTrait trait ActiveRelationTrait

20
framework/yii/data/ActiveDataProvider.php

@ -8,11 +8,11 @@
namespace yii\data; namespace yii\data;
use Yii; use Yii;
use yii\ar\ActiveQueryInterface;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\Model; use yii\base\Model;
use yii\db\Query;
use yii\db\ActiveQuery;
use yii\db\Connection; use yii\db\Connection;
use yii\db\QueryInterface;
/** /**
* ActiveDataProvider implements a data provider based on [[Query]] and [[ActiveQuery]]. * ActiveDataProvider implements a data provider based on [[Query]] and [[ActiveQuery]].
@ -54,7 +54,7 @@ use yii\db\Connection;
class ActiveDataProvider extends BaseDataProvider class ActiveDataProvider extends BaseDataProvider
{ {
/** /**
* @var Query the query that is used to fetch data models and [[totalCount]] * @var QueryInterface the query that is used to fetch data models and [[totalCount]]
* if it is not explicitly set. * if it is not explicitly set.
*/ */
public $query; public $query;
@ -97,8 +97,8 @@ class ActiveDataProvider extends BaseDataProvider
*/ */
protected function prepareModels() protected function prepareModels()
{ {
if (!$this->query instanceof Query) { if (!$this->query instanceof QueryInterface) {
throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.');
} }
if (($pagination = $this->getPagination()) !== false) { if (($pagination = $this->getPagination()) !== false) {
$pagination->totalCount = $this->getTotalCount(); $pagination->totalCount = $this->getTotalCount();
@ -125,7 +125,7 @@ class ActiveDataProvider extends BaseDataProvider
} }
} }
return $keys; return $keys;
} elseif ($this->query instanceof ActiveQuery) { } elseif ($this->query instanceof ActiveQueryInterface) {
/** @var \yii\db\ActiveRecord $class */ /** @var \yii\db\ActiveRecord $class */
$class = $this->query->modelClass; $class = $this->query->modelClass;
$pks = $class::primaryKey(); $pks = $class::primaryKey();
@ -154,11 +154,11 @@ class ActiveDataProvider extends BaseDataProvider
*/ */
protected function prepareTotalCount() protected function prepareTotalCount()
{ {
if (!$this->query instanceof Query) { if (!$this->query instanceof QueryInterface) {
throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.'); throw new InvalidConfigException('The "query" property must be an instance of a class that implements the QueryInterface e.g. yii\db\Query or its subclasses.');
} }
$query = clone $this->query; $query = clone $this->query;
return (int) $query->limit(-1)->offset(-1)->count('*', $this->db); return (int) $query->limit(-1)->offset(-1)->count($this->db);
} }
/** /**
@ -167,7 +167,7 @@ class ActiveDataProvider extends BaseDataProvider
public function setSort($value) public function setSort($value)
{ {
parent::setSort($value); parent::setSort($value);
if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) { if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQueryInterface) {
/** @var Model $model */ /** @var Model $model */
$model = new $this->query->modelClass; $model = new $this->query->modelClass;
foreach ($model->attributes() as $attribute) { foreach ($model->attributes() as $attribute) {

10
framework/yii/db/ActiveQuery.php

@ -7,12 +7,13 @@
*/ */
namespace yii\db; namespace yii\db;
use yii\ar\ActiveQueryInterface;
use yii\ar\ActiveQueryTrait;
/** /**
* ActiveQuery represents a DB query associated with an Active Record class. * ActiveQuery represents a DB query associated with an Active Record class.
* *
* ActiveQuery instances are usually created by [[ActiveRecord::find()]], [[ActiveRecord::findBySql()]] * ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]].
* and [[ActiveRecord::count()]].
* *
* ActiveQuery mainly provides the following methods to retrieve the query results: * ActiveQuery mainly provides the following methods to retrieve the query results:
* *
@ -42,11 +43,12 @@ namespace yii\db;
* ~~~ * ~~~
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends Query class ActiveQuery extends Query implements ActiveQueryInterface
{ {
use \yii\ar\ActiveQueryTrait; use ActiveQueryTrait;
/** /**
* @var string the SQL statement to be executed for retrieving AR records. * @var string the SQL statement to be executed for retrieving AR records.

28
framework/yii/db/ActiveRecord.php

@ -8,6 +8,7 @@
namespace yii\db; namespace yii\db;
use yii\ar\ActiveRelationInterface;
use yii\base\InvalidConfigException; use yii\base\InvalidConfigException;
use yii\base\Model; use yii\base\Model;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
@ -36,6 +37,7 @@ use yii\helpers\Inflector;
* the key value is null). This property is read-only. * the key value is null). This property is read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveRecord extends Model class ActiveRecord extends Model
@ -95,10 +97,6 @@ class ActiveRecord extends Model
const OP_ALL = 0x07; const OP_ALL = 0x07;
/** /**
* @var string the name of the class to use for relations.
*/
protected $relationClassName = 'yii\\db\\ActiveRelation';
/**
* @var array attribute values indexed by attribute names * @var array attribute values indexed by attribute names
*/ */
private $_attributes = []; private $_attributes = [];
@ -256,7 +254,7 @@ class ActiveRecord extends Model
/** /**
* Creates an [[ActiveQuery]] instance. * Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query. * This method is called by [[find()]], [[findBySql()]] to start a SELECT query.
* You may override this method to return a customized query (e.g. `CustomerQuery` specified * You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.) * written for querying `Customer` purpose.)
* @return ActiveQuery the newly created [[ActiveQuery]] instance. * @return ActiveQuery the newly created [[ActiveQuery]] instance.
@ -389,7 +387,7 @@ class ActiveRecord extends Model
return $this->_related[$name]; return $this->_related[$name];
} }
$value = parent::__get($name); $value = parent::__get($name);
if ($value instanceof $this->relationClassName) { if ($value instanceof ActiveRelationInterface) {
return $this->_related[$name] = $value->multiple ? $value->all() : $value->one(); return $this->_related[$name] = $value->multiple ? $value->all() : $value->one();
} else { } else {
return $value; return $value;
@ -478,7 +476,7 @@ class ActiveRecord extends Model
*/ */
public function hasOne($class, $link) public function hasOne($class, $link)
{ {
return new $this->relationClassName([ return $this->createActiveRelation([
'modelClass' => $class, 'modelClass' => $class,
'primaryModel' => $this, 'primaryModel' => $this,
'link' => $link, 'link' => $link,
@ -516,7 +514,7 @@ class ActiveRecord extends Model
*/ */
public function hasMany($class, $link) public function hasMany($class, $link)
{ {
return new $this->relationClassName([ return $this->createActiveRelation([
'modelClass' => $class, 'modelClass' => $class,
'primaryModel' => $this, 'primaryModel' => $this,
'link' => $link, 'link' => $link,
@ -525,6 +523,18 @@ class ActiveRecord extends Model
} }
/** /**
* Creates an [[ActiveRelation]] instance.
* This method is called by [[hasOne()]] and [[hasMany()]] to create a relation instance.
* You may override this method to return a customized relation.
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveRelation the newly created [[ActiveRelation]] instance.
*/
protected function createActiveRelation($config = [])
{
return new ActiveRelation($config);
}
/**
* Populates the named relation with the related records. * Populates the named relation with the related records.
* Note that this method does not check if the relation exists or not. * Note that this method does not check if the relation exists or not.
* @param string $name the relation name (case-sensitive) * @param string $name the relation name (case-sensitive)
@ -1287,7 +1297,7 @@ class ActiveRecord extends Model
$getter = 'get' . $name; $getter = 'get' . $name;
try { try {
$relation = $this->$getter(); $relation = $this->$getter();
if ($relation instanceof $this->relationClassName) { if ($relation instanceof ActiveRelationInterface) {
return $relation; return $relation;
} else { } else {
return null; return null;

13
framework/yii/db/ActiveRelation.php

@ -7,6 +7,8 @@
*/ */
namespace yii\db; namespace yii\db;
use yii\ar\ActiveRelationInterface;
use yii\ar\ActiveRelationTrait;
/** /**
* ActiveRelation represents a relation between two Active Record classes. * ActiveRelation represents a relation between two Active Record classes.
@ -24,17 +26,12 @@ namespace yii\db;
* or [[viaTable()]] to set this property instead of directly setting it. * or [[viaTable()]] to set this property instead of directly setting it.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveRelation extends ActiveQuery class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{ {
use \yii\ar\ActiveRelationTrait; use ActiveRelationTrait;
/**
* @var array|ActiveRelation the query associated with the pivot table. Please call [[via()]]
* or [[viaTable()]] to set this property instead of directly setting it.
*/
public $via;
/** /**
* Specifies the pivot table. * Specifies the pivot table.

20
framework/yii/db/Query.php

@ -33,24 +33,14 @@ use yii\base\Component;
* ~~~ * ~~~
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class Query extends Component class Query extends Component implements QueryInterface
{ {
use QueryTrait; use QueryTrait;
/** /**
* Sort ascending
* @see orderBy()
*/
const SORT_ASC = false;
/**
* Sort descending
* @see orderBy()
*/
const SORT_DESC = true;
/**
* @var array the columns being selected. For example, `['id', 'name']`. * @var array the columns being selected. For example, `['id', 'name']`.
* This is used to construct the SELECT clause in a SQL statement. If not set, if means selecting all columns. * This is used to construct the SELECT clause in a SQL statement. If not set, if means selecting all columns.
* @see select() * @see select()
@ -189,13 +179,13 @@ class Query extends Component
/** /**
* Returns the number of records. * Returns the number of records.
* @param Connection $db the database connection used to generate the SQL statement.
* If this parameter is not given (or null), the `db` application component will be used.
* @param string $q the COUNT expression. Defaults to '*'. * @param string $q the COUNT expression. Defaults to '*'.
* Make sure you properly quote column names in the expression. * Make sure you properly quote column names in the expression.
* @param Connection $db the database connection used to generate the SQL statement.
* If this parameter is not given, the `db` application component will be used.
* @return integer number of records * @return integer number of records
*/ */
public function count($q = '*', $db = null) public function count($db = null, $q = '*')
{ {
$this->select = ["COUNT($q)"]; $this->select = ["COUNT($q)"];
return $this->createCommand($db)->queryScalar(); return $this->createCommand($db)->queryScalar();

2
framework/yii/db/QueryBuilder.php

@ -683,7 +683,7 @@ class QueryBuilder extends \yii\base\Object
if (is_object($direction)) { if (is_object($direction)) {
$orders[] = (string)$direction; $orders[] = (string)$direction;
} else { } else {
$orders[] = $this->db->quoteColumnName($name) . ($direction === Query::SORT_DESC ? ' DESC' : ''); $orders[] = $this->db->quoteColumnName($name) . ($direction === SORT_DESC ? ' DESC' : '');
} }
} }

205
framework/yii/db/QueryInterface.php

@ -0,0 +1,205 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db;
/**
* The QueryInterface defines the minimum set of methods to be implemented by a database query.
*
* The default implementation of this interface is provided by [[QueryTrait]].
*
* It has support for getting [[one]] instance or [[all]].
* Allows pagination via [[limit]] and [[offset]].
* Sorting is supported via [[orderBy]] and items can be limited to match some conditions using [[where]].
*
* By calling [[createCommand()]], we can get a [[Command]] instance which can be further
* used to perform/execute the DB query against a database.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
interface QueryInterface
{
/**
* Executes the query and returns all results as an array.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
public function all($db = null);
/**
* Executes the query and returns a single row of result.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query
* results in nothing.
*/
public function one($db = null);
/**
* Returns the number of records.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return integer number of records
*/
public function count($db = null);
/**
* Returns a value indicating whether the query result contains any row of data.
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @return boolean whether the query result contains any row of data.
*/
public function exists($db = null);
/**
* Sets the [[indexBy]] property.
* @param string|callable $column the name of the column by which the query results should be indexed by.
* This can also be a callable (e.g. anonymous function) that returns the index value based on the given
* row data. The signature of the callable should be:
*
* ~~~
* function ($row)
* {
* // return the index value corresponding to $row
* }
* ~~~
*
* @return static the query object itself
*/
public function indexBy($column);
/**
* Sets the WHERE part of the query.
*
* The method requires a $condition parameter.
*
* The $condition parameter should be an array in one of the following two formats:
*
* - hash format: `['column1' => value1, 'column2' => value2, ...]`
* - operator format: `[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:
*
* - `['type' => 1, 'status' => 2]` generates `(type = 1) AND (status = 2)`.
* - `['id' => [1, 2, 3], 'status' => 2]` generates `(id IN (1, 2, 3)) AND (status = 2)`.
* - `['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,
* `['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,
* `['and', 'type=1', ['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, `['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,
* `['in', 'id', [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, `['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, `['like', 'name', ['%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 array $condition the conditions that should be put in the WHERE part.
* @return static the query object itself
* @see andWhere()
* @see orWhere()
*/
public function where($condition);
/**
* 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.
* @return static the query object itself
* @see where()
* @see orWhere()
*/
public function andWhere($condition);
/**
* 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.
* @return static the query object itself
* @see where()
* @see andWhere()
*/
public function orWhere($condition);
/**
* 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. `['id' => SORT_ASC, 'name' => SORT_DESC]`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return static the query object itself
* @see addOrderBy()
*/
public function orderBy($columns);
/**
* 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. `['id' => SORT_ASC, 'name' => SORT_DESC]`).
* The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression).
* @return static the query object itself
* @see orderBy()
*/
public function addOrderBy($columns);
/**
* Sets the LIMIT part of the query.
* @param integer $limit the limit. Use null or negative value to disable limit.
* @return static the query object itself
*/
public function limit($limit);
/**
* Sets the OFFSET part of the query.
* @param integer $offset the offset. Use null or negative value to disable offset.
* @return static the query object itself
*/
public function offset($offset);
}

109
framework/yii/db/QueryTrait.php

@ -7,18 +7,6 @@
namespace yii\db; namespace yii\db;
// TODO where to put these constants?
/**
* Sort ascending
* @see orderBy
*/
const SORT_ASC = false;
/**
* Sort descending
* @see orderBy
*/
const SORT_DESC = true;
/** /**
* The BaseQuery trait represents the minimum method set of a database Query. * The BaseQuery trait represents the minimum method set of a database Query.
* *
@ -53,8 +41,10 @@ trait QueryTrait
/** /**
* @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement. * @var array how to sort the query results. This is used to construct the ORDER BY clause in a SQL statement.
* The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which * The array keys are the columns to be sorted by, and the array values are the corresponding sort directions which
* can be either [[Query::SORT_ASC]] or [[Query::SORT_DESC]]. The array may also contain [[Expression]] objects. * can be either [SORT_ASC](http://php.net/manual/en/array.constants.php#constant.sort-asc)
* If that is the case, the expressions will be converted into strings without any change. * or [SORT_DESC](http://php.net/manual/en/array.constants.php#constant.sort-desc).
* The array may also contain [[Expression]] objects. If that is the case, the expressions
* will be converted into strings without any change.
*/ */
public $orderBy; public $orderBy;
/** /**
@ -86,90 +76,9 @@ trait QueryTrait
} }
/** /**
* Executes the query and returns all results as an array.
* @return array the query results. If the query results in nothing, an empty array will be returned.
*/
abstract public function all();
/**
* Executes the query and returns a single row of result.
* @return array|boolean the first row (in terms of an array) of the query result. False is returned if the query
* results in nothing.
*/
abstract public function one();
/**
* Returns the number of records.
* @return integer number of records
*/
abstract public function count();
/**
* Returns a value indicating whether the query result contains any row of data.
* @return boolean whether the query result contains any row of data.
*/
abstract public function exists();
/**
* Sets the WHERE part of the query. * Sets the WHERE part of the query.
* *
* The method requires a $condition parameter. * See [[QueryInterface::where()]] for detailed documentation.
*
* The $condition parameter should be an array in one of the following two formats:
*
* - hash format: `['column1' => value1, 'column2' => value2, ...]`
* - operator format: `[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:
*
* - `['type' => 1, 'status' => 2]` generates `(type = 1) AND (status = 2)`.
* - `['id' => [1, 2, 3], 'status' => 2]` generates `(id IN (1, 2, 3)) AND (status = 2)`.
* - `['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,
* `['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,
* `['and', 'type=1', ['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, `['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,
* `['in', 'id', [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, `['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, `['like', 'name', ['%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 array $condition the conditions that should be put in the WHERE part. * @param array $condition the conditions that should be put in the WHERE part.
* @return static the query object itself * @return static the query object itself
@ -224,7 +133,7 @@ trait QueryTrait
* Sets the ORDER BY part of the query. * Sets the ORDER BY part of the query.
* @param string|array $columns the columns (and the directions) to be ordered by. * @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 * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`). * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`).
* The method will automatically quote the column names unless a column contains some parenthesis * The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression). * (which means the column contains a DB expression).
* @return static the query object itself * @return static the query object itself
@ -240,7 +149,7 @@ trait QueryTrait
* Adds additional ORDER BY columns to the query. * Adds additional ORDER BY columns to the query.
* @param string|array $columns the columns (and the directions) to be ordered by. * @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 * Columns can be specified in either a string (e.g. "id ASC, name DESC") or an array
* (e.g. `['id' => Query::SORT_ASC, 'name' => Query::SORT_DESC]`). * (e.g. `['id' => SORT_ASC, 'name' => SORT_DESC]`).
* The method will automatically quote the column names unless a column contains some parenthesis * The method will automatically quote the column names unless a column contains some parenthesis
* (which means the column contains a DB expression). * (which means the column contains a DB expression).
* @return static the query object itself * @return static the query object itself
@ -266,9 +175,9 @@ trait QueryTrait
$result = []; $result = [];
foreach ($columns as $column) { foreach ($columns as $column) {
if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) { if (preg_match('/^(.*?)\s+(asc|desc)$/i', $column, $matches)) {
$result[$matches[1]] = strcasecmp($matches[2], 'desc') ? self::SORT_ASC : self::SORT_DESC; $result[$matches[1]] = strcasecmp($matches[2], 'desc') ? SORT_ASC : SORT_DESC;
} else { } else {
$result[$column] = self::SORT_ASC; $result[$column] = SORT_ASC;
} }
} }
return $result; return $result;

Loading…
Cancel
Save