Commit 1708a36d by Carsten Brandt

WIP merge ActiveRelation into ActiveQuery

allow extending only one class to add scopes, fixes #2146 TODO: - [ ] adjust guide docs - [ ] adjust README files of extensions - [ ] finish work and fix test breaks
parent 54476b48
...@@ -9,11 +9,19 @@ namespace yii\elasticsearch; ...@@ -9,11 +9,19 @@ namespace yii\elasticsearch;
use yii\db\ActiveQueryInterface; use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait; use yii\db\ActiveQueryTrait;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/** /**
* ActiveQuery represents a [[Query]] associated with an [[ActiveRecord]] class. * ActiveQuery represents a [[Query]] associated with an [[ActiveRecord]] class.
* *
* An ActiveQuery can be a normal query or be used in a relational context.
*
* ActiveQuery instances are usually created by [[ActiveRecord::find()]]. * ActiveQuery instances are usually created by [[ActiveRecord::find()]].
* Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
*
* Normal Query
* ------------
* *
* ActiveQuery mainly provides the following methods to retrieve the query results: * ActiveQuery mainly provides the following methods to retrieve the query results:
* *
...@@ -35,19 +43,40 @@ use yii\db\ActiveQueryTrait; ...@@ -35,19 +43,40 @@ use yii\db\ActiveQueryTrait;
* *
* These options can be configured using methods of the same name. For example: * These options can be configured using methods of the same name. For example:
* *
* ~~~ * ```php
* $customers = Customer::find()->with('orders')->asArray()->all(); * $customers = Customer::find()->with('orders')->asArray()->all();
* ~~~ * ```
* > NOTE: elasticsearch limits the number of records returned to 10 records by default.
* > If you expect to get more records you should specify limit explicitly.
*
* Relational query
* ----------------
*
* In relational context ActiveQuery represents a relation between two Active Record classes.
*
* Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveQuery object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
* *
* NOTE: elasticsearch limits the number of records returned to 10 records by default. * If a relation involves a pivot table, it may be specified by [[via()]].
* If you expect to get more records you should specify limit explicitly. * This methods may only be called in a relational context. Same is true for [[inverseOf()]], which
* marks a relation as inverse of another relation.
*
* > NOTE: elasticsearch limits the number of records returned by any query to 10 records by default.
* > If you expect to get more records you should specify limit explicitly in relation definition.
* > This is also important for relations that use [[via()]] so that if via records are limited to 10
* > the relations records can also not be more than 10.
* *
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends Query implements ActiveQueryInterface class ActiveQuery extends Query implements ActiveQueryInterface, ActiveRelationInterface
{ {
use ActiveQueryTrait; use ActiveQueryTrait;
use ActiveRelationTrait;
/** /**
* Creates a DB command that can be used to execute this query. * Creates a DB command that can be used to execute this query.
...@@ -57,6 +86,26 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -57,6 +86,26 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/ */
public function createCommand($db = null) public function createCommand($db = null)
{ {
if ($this->primaryModel !== null) {
// lazy loading
if (is_array($this->via)) {
// via relation
/** @var ActiveQuery $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass; $modelClass = $this->modelClass;
if ($db === null) { if ($db === null) {
......
...@@ -138,19 +138,32 @@ class ActiveRecord extends BaseActiveRecord ...@@ -138,19 +138,32 @@ class ActiveRecord extends BaseActiveRecord
// TODO add percolate functionality http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-percolate.html // TODO add percolate functionality http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-percolate.html
/** /**
* @inheritdoc * Creates an [[ActiveQuery]] instance.
*/ *
public static function createQuery() * This method is called by [[find()]], [[findBySql()]] to start a SELECT query but also
{ * by [[hasOne()]] and [[hasMany()]] to create a relational query.
return new ActiveQuery(['modelClass' => get_called_class()]); * You may override this method to return a customized query (e.g. `CustomerQuery` specified
} * written for querying `Customer` purpose.)
*
/** * You may also define default conditions that should apply to all queries unless overridden:
* @inheritdoc *
* ```php
* public static function createQuery()
* {
* return parent::createQuery()->where(['deleted' => false]);
* }
* ```
*
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition.
*
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createRelation($config = []) public static function createQuery($config)
{ {
return new ActiveRelation($config); $config['modelClass'] = get_called_class();
return new ActiveQuery($config);
} }
// TODO implement copy and move as pk change is not possible // TODO implement copy and move as pk change is not possible
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\elasticsearch;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/**
* ActiveRelation represents a relation between two Active Record classes.
*
* ActiveRelation instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveRelation object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]] method.
*
* NOTE: elasticsearch limits the number of records returned by any query to 10 records by default.
* If you expect to get more records you should specify limit explicitly in relation definition.
* This is also important for relations that use [[via()]] so that if via records are limited to 10
* the relations records can also not be more than 10.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{
use ActiveRelationTrait;
/**
* Creates a DB command that can be used to execute this query.
* @param Connection $db the DB connection used to create the DB command.
* If null, the DB connection returned by [[modelClass]] will be used.
* @return Command the created DB command instance.
*/
public function createCommand($db = null)
{
if ($this->primaryModel !== null) {
// lazy loading
if (is_array($this->via)) {
// via relation
/** @var ActiveRelation $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
return parent::createCommand($db);
}
}
...@@ -11,6 +11,9 @@ Yii Framework 2 elasticsearch extension Change Log ...@@ -11,6 +11,9 @@ Yii Framework 2 elasticsearch extension Change Log
- Enh #1765: Added support for primary key path mapping, pk can now be part of the attributes when mapping is defined (cebe) - Enh #1765: Added support for primary key path mapping, pk can now be part of the attributes when mapping is defined (cebe)
- Chg #1765: Changed handling of ActiveRecord primary keys, removed getId(), use getPrimaryKey() instead (cebe) - Chg #1765: Changed handling of ActiveRecord primary keys, removed getId(), use getPrimaryKey() instead (cebe)
- Chg #2281: Renamed `ActiveRecord::create()` to `populateRecord()` and changed signature. This method will not call instantiate() anymore (cebe) - Chg #2281: Renamed `ActiveRecord::create()` to `populateRecord()` and changed signature. This method will not call instantiate() anymore (cebe)
- Chg #2146: Removed `ActiveRelation` class and moved the functionality to `ActiveQuery`.
All relational queries are now directly served by `ActiveQuery` allowing to use
custom scopes in relations (cebe)
2.0.0 alpha, December 1, 2013 2.0.0 alpha, December 1, 2013
----------------------------- -----------------------------
......
...@@ -84,7 +84,7 @@ class Customer extends \yii\elasticsearch\ActiveRecord ...@@ -84,7 +84,7 @@ class Customer extends \yii\elasticsearch\ActiveRecord
} }
/** /**
* @return ActiveRelation defines a relation to the Order record (can be in other database, e.g. redis or sql) * @return ActiveQuery defines a relation to the Order record (can be in other database, e.g. redis or sql)
*/ */
public function getOrders() public function getOrders()
{ {
......
...@@ -62,7 +62,7 @@ class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') . ...@@ -62,7 +62,7 @@ class <?= $className ?> extends <?= '\\' . ltrim($generator->baseClass, '\\') .
<?php foreach ($relations as $name => $relation): ?> <?php foreach ($relations as $name => $relation): ?>
/** /**
* @return \yii\db\ActiveRelation * @return \yii\db\ActiveQuery
*/ */
public function get<?= $name ?>() public function get<?= $name ?>()
{ {
......
...@@ -9,10 +9,20 @@ namespace yii\mongodb; ...@@ -9,10 +9,20 @@ namespace yii\mongodb;
use yii\db\ActiveQueryInterface; use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait; use yii\db\ActiveQueryTrait;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/** /**
* ActiveQuery represents a Mongo query associated with an Active Record class. * ActiveQuery represents a Mongo query associated with an Active Record class.
* *
* An ActiveQuery can be a normal query or be used in a relational context.
*
* ActiveQuery instances are usually created by [[ActiveRecord::find()]].
* Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
*
* Normal Query
* ------------
*
* ActiveQuery instances are usually created by [[ActiveRecord::find()]]. * ActiveQuery instances are usually created by [[ActiveRecord::find()]].
* *
* Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]], * Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]],
...@@ -25,18 +35,66 @@ use yii\db\ActiveQueryTrait; ...@@ -25,18 +35,66 @@ use yii\db\ActiveQueryTrait;
* *
* These options can be configured using methods of the same name. For example: * These options can be configured using methods of the same name. For example:
* *
* ~~~ * ```php
* $customers = Customer::find()->with('orders')->asArray()->all(); * $customers = Customer::find()->with('orders')->asArray()->all();
* ~~~ * ```
*
* Relational query
* ----------------
*
* In relational context ActiveQuery represents a relation between two Active Record classes.
*
* Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveQuery object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]].
* This methods may only be called in a relational context. Same is true for [[inverseOf()]], which
* marks a relation as inverse of another relation.
* *
* @property Collection $collection Collection instance. This property is read-only. * @property Collection $collection Collection instance. This property is read-only.
* *
* @author Paul Klimov <klimov.paul@gmail.com> * @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends Query implements ActiveQueryInterface class ActiveQuery extends Query implements ActiveQueryInterface, ActiveRelationInterface
{ {
use ActiveQueryTrait; use ActiveQueryTrait;
use ActiveRelationTrait;
/**
* @inheritdoc
*/
protected function buildCursor($db = null)
{
if ($this->primaryModel !== null) {
// lazy loading
if ($this->via instanceof self) {
// via pivot collection
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveQuery $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
return parent::buildCursor($db);
}
/** /**
* Executes query and returns all results as an array. * Executes query and returns all results as an array.
......
...@@ -93,14 +93,31 @@ abstract class ActiveRecord extends BaseActiveRecord ...@@ -93,14 +93,31 @@ abstract class ActiveRecord extends BaseActiveRecord
/** /**
* Creates an [[ActiveQuery]] instance. * Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]] to start a "find" command. *
* This method is called by [[find()]], [[findBySql()]] to start a SELECT query but also
* by [[hasOne()]] and [[hasMany()]] to create a relational 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.)
*
* You may also define default conditions that should apply to all queries unless overridden:
*
* ```php
* public static function createQuery()
* {
* return parent::createQuery()->where(['deleted' => false]);
* }
* ```
*
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition.
*
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQuery the newly created [[ActiveQuery]] instance. * @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createQuery() public static function createQuery($config)
{ {
return new ActiveQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new ActiveQuery($config);
} }
/** /**
...@@ -142,18 +159,6 @@ abstract class ActiveRecord extends BaseActiveRecord ...@@ -142,18 +159,6 @@ abstract class ActiveRecord extends BaseActiveRecord
} }
/** /**
* 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.
*/
public static function createRelation($config = [])
{
return new ActiveRelation($config);
}
/**
* Returns the list of all attribute names of the model. * Returns the list of all attribute names of the model.
* This method must be overridden by child classes to define available attributes. * This method must be overridden by child classes to define available attributes.
* Note: primary key attribute "_id" should be always present in returned array. * Note: primary key attribute "_id" should be always present in returned array.
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\mongodb;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/**
* ActiveRelation represents a relation to Mongo Active Record class.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{
use ActiveRelationTrait;
/**
* @inheritdoc
*/
protected function buildCursor($db = null)
{
if ($this->primaryModel !== null) {
// lazy loading
if ($this->via instanceof self) {
// via pivot collection
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveRelation $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
return parent::buildCursor($db);
}
}
\ No newline at end of file
...@@ -9,6 +9,8 @@ namespace yii\mongodb\file; ...@@ -9,6 +9,8 @@ namespace yii\mongodb\file;
use yii\db\ActiveQueryInterface; use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait; use yii\db\ActiveQueryTrait;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/** /**
* ActiveQuery represents a Mongo query associated with an file Active Record class. * ActiveQuery represents a Mongo query associated with an file Active Record class.
...@@ -34,9 +36,10 @@ use yii\db\ActiveQueryTrait; ...@@ -34,9 +36,10 @@ use yii\db\ActiveQueryTrait;
* @author Paul Klimov <klimov.paul@gmail.com> * @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends Query implements ActiveQueryInterface class ActiveQuery extends Query implements ActiveQueryInterface, ActiveRelationInterface
{ {
use ActiveQueryTrait; use ActiveQueryTrait;
use ActiveRelationTrait;
/** /**
* Executes query and returns all results as an array. * Executes query and returns all results as an array.
......
...@@ -46,14 +46,31 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord ...@@ -46,14 +46,31 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord
{ {
/** /**
* Creates an [[ActiveQuery]] instance. * Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]] to start a "find" command. *
* You may override this method to return a customized query (e.g. `ImageFileQuery` specified * This method is called by [[find()]], [[findBySql()]] to start a SELECT query but also
* written for querying `ImageFile` purpose.) * by [[hasOne()]] and [[hasMany()]] to create a relational query.
* You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.)
*
* You may also define default conditions that should apply to all queries unless overridden:
*
* ```php
* public static function createQuery()
* {
* return parent::createQuery()->where(['deleted' => false]);
* }
* ```
*
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition.
*
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQuery the newly created [[ActiveQuery]] instance. * @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createQuery() public static function createQuery($config)
{ {
return new ActiveQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new ActiveQuery($config);
} }
/** /**
...@@ -66,18 +83,6 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord ...@@ -66,18 +83,6 @@ abstract class ActiveRecord extends \yii\mongodb\ActiveRecord
} }
/** /**
* 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.
*/
public static function createRelation($config = [])
{
return new ActiveRelation($config);
}
/**
* Returns the list of all attribute names of the model. * Returns the list of all attribute names of the model.
* This method could be overridden by child classes to define available attributes. * This method could be overridden by child classes to define available attributes.
* Note: all attributes defined in base Active Record class should be always present * Note: all attributes defined in base Active Record class should be always present
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\mongodb\file;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/**
* ActiveRelation represents a relation to Mongo GridFS Active Record class.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{
use ActiveRelationTrait;
}
\ No newline at end of file
...@@ -10,13 +10,20 @@ use yii\base\InvalidParamException; ...@@ -10,13 +10,20 @@ use yii\base\InvalidParamException;
use yii\base\NotSupportedException; use yii\base\NotSupportedException;
use yii\db\ActiveQueryInterface; use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait; use yii\db\ActiveQueryTrait;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
use yii\db\QueryTrait; use yii\db\QueryTrait;
/** /**
* ActiveQuery represents a query associated with an Active Record class. * ActiveQuery represents a query associated with an Active Record class.
* *
* ActiveQuery instances are usually created by [[ActiveRecord::find()]] * An ActiveQuery can be a normal query or be used in a relational context.
* and [[ActiveRecord::count()]]. *
* ActiveQuery instances are usually created by [[ActiveRecord::find()]].
* Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
*
* Normal Query
* ------------
* *
* ActiveQuery mainly provides the following methods to retrieve the query results: * ActiveQuery mainly provides the following methods to retrieve the query results:
* *
...@@ -40,17 +47,34 @@ use yii\db\QueryTrait; ...@@ -40,17 +47,34 @@ use yii\db\QueryTrait;
* *
* These options can be configured using methods of the same name. For example: * These options can be configured using methods of the same name. For example:
* *
* ~~~ * ```php
* $customers = Customer::find()->with('orders')->asArray()->all(); * $customers = Customer::find()->with('orders')->asArray()->all();
* ~~~ * ```
*
* Relational query
* ----------------
*
* In relational context ActiveQuery represents a relation between two Active Record classes.
*
* Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveQuery object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]].
* This methods may only be called in a relational context. Same is true for [[inverseOf()]], which
* marks a relation as inverse of another relation.
* *
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface, ActiveRelationInterface
{ {
use QueryTrait; use QueryTrait;
use ActiveQueryTrait; use ActiveQueryTrait;
use ActiveRelationTrait;
/** /**
* Executes the query and returns all results as an array. * Executes the query and returns all results as an array.
...@@ -252,6 +276,30 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface ...@@ -252,6 +276,30 @@ class ActiveQuery extends \yii\base\Component implements ActiveQueryInterface
*/ */
protected function executeScript($db, $type, $columnName = null) protected function executeScript($db, $type, $columnName = null)
{ {
if ($this->primaryModel !== null) {
// lazy loading
if ($this->via instanceof self) {
// via pivot table
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveQuery $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
if (!empty($this->orderBy)) { if (!empty($this->orderBy)) {
throw new NotSupportedException('orderBy is currently not supported by redis ActiveRecord.'); throw new NotSupportedException('orderBy is currently not supported by redis ActiveRecord.');
} }
......
...@@ -49,19 +49,32 @@ class ActiveRecord extends BaseActiveRecord ...@@ -49,19 +49,32 @@ class ActiveRecord extends BaseActiveRecord
} }
/** /**
* @inheritdoc * Creates an [[ActiveQuery]] instance.
*/ *
public static function createQuery() * This method is called by [[find()]], [[findBySql()]] to start a SELECT query but also
{ * by [[hasOne()]] and [[hasMany()]] to create a relational query.
return new ActiveQuery(['modelClass' => get_called_class()]); * You may override this method to return a customized query (e.g. `CustomerQuery` specified
} * written for querying `Customer` purpose.)
*
/** * You may also define default conditions that should apply to all queries unless overridden:
* @inheritdoc *
* ```php
* public static function createQuery()
* {
* return parent::createQuery()->where(['deleted' => false]);
* }
* ```
*
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition.
*
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createRelation($config = []) public static function createQuery($config)
{ {
return new ActiveRelation($config); $config['modelClass'] = get_called_class();
return new ActiveQuery($config);
} }
/** /**
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\redis;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/**
* ActiveRelation represents a relation between two Active Record classes.
*
* ActiveRelation instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveRelation object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method.
*
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{
use ActiveRelationTrait;
/**
* Executes a script created by [[LuaScriptBuilder]]
* @param Connection $db the database connection used to execute the query.
* If this parameter is not given, the `db` application component will be used.
* @param string $type the type of the script to generate
* @param null $column
* @return array|bool|null|string
*/
protected function executeScript($db, $type, $column=null)
{
if ($this->primaryModel !== null) {
// lazy loading
if ($this->via instanceof self) {
// via pivot table
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveRelation $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
return parent::executeScript($db, $type, $column);
}
}
...@@ -7,6 +7,9 @@ Yii Framework 2 redis extension Change Log ...@@ -7,6 +7,9 @@ Yii Framework 2 redis extension Change Log
- Bug #1993: afterFind event in AR is now called after relations have been populated (cebe, creocoder) - Bug #1993: afterFind event in AR is now called after relations have been populated (cebe, creocoder)
- Enh #1773: keyPrefix property of Session and Cache is not restricted to alnum characters anymore (cebe) - Enh #1773: keyPrefix property of Session and Cache is not restricted to alnum characters anymore (cebe)
- Chg #2281: Renamed `ActiveRecord::create()` to `populateRecord()` and changed signature. This method will not call instantiate() anymore (cebe) - Chg #2281: Renamed `ActiveRecord::create()` to `populateRecord()` and changed signature. This method will not call instantiate() anymore (cebe)
- Chg #2146: Removed `ActiveRelation` class and moved the functionality to `ActiveQuery`.
All relational queries are now directly served by `ActiveQuery` allowing to use
custom scopes in relations (cebe)
2.0.0 alpha, December 1, 2013 2.0.0 alpha, December 1, 2013
----------------------------- -----------------------------
......
...@@ -148,7 +148,7 @@ class Customer extends \yii\redis\ActiveRecord ...@@ -148,7 +148,7 @@ class Customer extends \yii\redis\ActiveRecord
} }
/** /**
* @return ActiveRelation defines a relation to the Order record (can be in other database, e.g. elasticsearch or sql) * @return ActiveQuery defines a relation to the Order record (can be in other database, e.g. elasticsearch or sql)
*/ */
public function getOrders() public function getOrders()
{ {
......
...@@ -10,11 +10,18 @@ namespace yii\sphinx; ...@@ -10,11 +10,18 @@ namespace yii\sphinx;
use yii\base\InvalidCallException; use yii\base\InvalidCallException;
use yii\db\ActiveQueryInterface; use yii\db\ActiveQueryInterface;
use yii\db\ActiveQueryTrait; use yii\db\ActiveQueryTrait;
use yii\db\ActiveRelationInterface;
/** /**
* ActiveQuery represents a Sphinx query associated with an Active Record class. * ActiveQuery represents a Sphinx query associated with an Active Record class.
* *
* An ActiveQuery can be a normal query or be used in a relational context.
*
* ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]]. * ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]].
* Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
*
* Normal Query
* ------------
* *
* Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]], * Because ActiveQuery extends from [[Query]], one can use query methods, such as [[where()]],
* [[orderBy()]] to customize the query options. * [[orderBy()]] to customize the query options.
...@@ -54,12 +61,29 @@ use yii\db\ActiveQueryTrait; ...@@ -54,12 +61,29 @@ use yii\db\ActiveQueryTrait;
* $articles = Article::find()->with('source')->snippetByModel()->all(); * $articles = Article::find()->with('source')->snippetByModel()->all();
* ~~~ * ~~~
* *
* Relational query
* ----------------
*
* In relational context ActiveQuery represents a relation between two Active Record classes.
*
* Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveQuery object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]].
* This methods may only be called in a relational context. Same is true for [[inverseOf()]], which
* marks a relation as inverse of another relation.
*
* @author Paul Klimov <klimov.paul@gmail.com> * @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends Query implements ActiveQueryInterface class ActiveQuery extends Query implements ActiveQueryInterface, ActiveRelationInterface
{ {
use ActiveQueryTrait; use ActiveQueryTrait;
use ActiveRelationTrait;
/** /**
* @var string the SQL statement to be executed for retrieving AR records. * @var string the SQL statement to be executed for retrieving AR records.
...@@ -165,6 +189,30 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -165,6 +189,30 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/ */
public function createCommand($db = null) public function createCommand($db = null)
{ {
if ($this->primaryModel !== null) {
// lazy loading a relational query
if ($this->via instanceof self) {
// via pivot index
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveRelation $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
$this->setConnection($db); $this->setConnection($db);
$db = $this->getConnection(); $db = $this->getConnection();
......
...@@ -135,14 +135,31 @@ abstract class ActiveRecord extends BaseActiveRecord ...@@ -135,14 +135,31 @@ abstract class ActiveRecord extends BaseActiveRecord
/** /**
* Creates an [[ActiveQuery]] instance. * Creates an [[ActiveQuery]] instance.
* This method is called by [[find()]], [[findBySql()]] and [[count()]] to start a SELECT query. *
* You may override this method to return a customized query (e.g. `ArticleQuery` specified * This method is called by [[find()]], [[findBySql()]] to start a SELECT query but also
* written for querying `Article` purpose.) * by [[hasOne()]] and [[hasMany()]] to create a relational query.
* You may override this method to return a customized query (e.g. `CustomerQuery` specified
* written for querying `Customer` purpose.)
*
* You may also define default conditions that should apply to all queries unless overridden:
*
* ```php
* public static function createQuery()
* {
* return parent::createQuery()->where(['deleted' => false]);
* }
* ```
*
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition.
*
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQuery the newly created [[ActiveQuery]] instance. * @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createQuery() public static function createQuery($config)
{ {
return new ActiveQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new ActiveQuery($config);
} }
/** /**
...@@ -304,18 +321,6 @@ abstract class ActiveRecord extends BaseActiveRecord ...@@ -304,18 +321,6 @@ abstract class ActiveRecord extends BaseActiveRecord
} }
/** /**
* Creates an [[ActiveRelationInterface]] 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 ActiveRelationInterface the newly created [[ActiveRelation]] instance.
*/
public static function createRelation($config = [])
{
return new ActiveRelation($config);
}
/**
* Returns the list of all attribute names of the model. * Returns the list of all attribute names of the model.
* The default implementation will return all column names of the table associated with this AR class. * The default implementation will return all column names of the table associated with this AR class.
* @return array list of attribute names. * @return array list of attribute names.
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\sphinx;
use yii\db\ActiveRelationInterface;
use yii\db\ActiveRelationTrait;
/**
* ActiveRelation represents a relation to Sphinx Active Record class.
*
* @author Paul Klimov <klimov.paul@gmail.com>
* @since 2.0
*/
class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{
use ActiveRelationTrait;
/**
* @inheritdoc
*/
public function createCommand($db = null)
{
if ($this->primaryModel !== null) {
// lazy loading
if ($this->via instanceof self) {
// via pivot index
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveRelation $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
}
return parent::createCommand($db);
}
}
\ No newline at end of file
...@@ -5,9 +5,12 @@ Yii Framework 2 sphinx extension Change Log ...@@ -5,9 +5,12 @@ Yii Framework 2 sphinx extension Change Log
---------------------------- ----------------------------
- Bug #1993: afterFind event in AR is now called after relations have been populated (cebe, creocoder) - Bug #1993: afterFind event in AR is now called after relations have been populated (cebe, creocoder)
- Bug #2160: SphinxQL does not support OFFSET (qiangxue, romeo7) - Bug #2160: SphinxQL does not support `OFFSET` (qiangxue, romeo7)
- Enh #1398: Refactor ActiveRecord to use BaseActiveRecord class of the framework (klimov-paul) - Enh #1398: Refactor ActiveRecord to use BaseActiveRecord class of the framework (klimov-paul)
- Chg #2281: Renamed `ActiveRecord::create()` to `populateRecord()` and changed signature. This method will not call instantiate() anymore (cebe) - Chg #2281: Renamed `ActiveRecord::create()` to `populateRecord()` and changed signature. This method will not call instantiate() anymore (cebe)
- Chg #2146: Removed `ActiveRelation` class and moved the functionality to `ActiveQuery`.
All relational queries are now directly served by `ActiveQuery` allowing to use
custom scopes in relations (cebe)
2.0.0 alpha, December 1, 2013 2.0.0 alpha, December 1, 2013
----------------------------- -----------------------------
......
...@@ -175,7 +175,9 @@ Yii Framework 2 Change Log ...@@ -175,7 +175,9 @@ Yii Framework 2 Change Log
- Chg: Advanced app template: moved database connection DSN, login and password to `-local` config not to expose it to VCS (samdark) - Chg: Advanced app template: moved database connection DSN, login and password to `-local` config not to expose it to VCS (samdark)
- Chg: Renamed `yii\web\Request::acceptedLanguages` to `acceptableLanguages` (qiangxue) - Chg: Renamed `yii\web\Request::acceptedLanguages` to `acceptableLanguages` (qiangxue)
- Chg: Removed implementation of `Arrayable` from `yii\Object` (qiangxue) - Chg: Removed implementation of `Arrayable` from `yii\Object` (qiangxue)
- Chg: Renamed `ActiveRecordInterface::createActiveRelation()` to `createRelation()` (qiangxue) - Chg #2146: Removed `ActiveRelation` class and moved the functionality to `ActiveQuery`. All relational queries are
now directly served by `ActiveQuery` allowing to use custom scopes in relations.
Also removed `ActiveRecordInterface::createActiveRelation()` (cebe)
- Chg: The scripts in asset bundles are now registered in `View` at the end of `endBody()`. It was done in `endPage()` previously (qiangxue) - Chg: The scripts in asset bundles are now registered in `View` at the end of `endBody()`. It was done in `endPage()` previously (qiangxue)
- Chg: Renamed `csrf-var` to `csrf-param` for CSRF header name (Dilip) - Chg: Renamed `csrf-var` to `csrf-param` for CSRF header name (Dilip)
- Chg: The directory holding email templates is renamed from `mails` to `mail` (qiangxue) - Chg: The directory holding email templates is renamed from `mails` to `mail` (qiangxue)
......
...@@ -7,11 +7,18 @@ ...@@ -7,11 +7,18 @@
*/ */
namespace yii\db; namespace yii\db;
use yii\base\Object;
/** /**
* ActiveQuery represents a DB query associated with an Active Record class. * ActiveQuery represents a DB query associated with an Active Record class.
* *
* An ActiveQuery can be a normal query or be used in a relational context.
*
* ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]]. * ActiveQuery instances are usually created by [[ActiveRecord::find()]] and [[ActiveRecord::findBySql()]].
* Relational queries are created by [[ActiveRecord::hasOne()]] and [[ActiveRecord::hasMany()]].
*
* Normal Query
* ------------
* *
* ActiveQuery mainly provides the following methods to retrieve the query results: * ActiveQuery mainly provides the following methods to retrieve the query results:
* *
...@@ -37,23 +44,49 @@ namespace yii\db; ...@@ -37,23 +44,49 @@ namespace yii\db;
* *
* These options can be configured using methods of the same name. For example: * These options can be configured using methods of the same name. For example:
* *
* ~~~ * ```php
* $customers = Customer::find()->with('orders')->asArray()->all(); * $customers = Customer::find()->with('orders')->asArray()->all();
* ~~~ * ```
*
* Relational query
* ----------------
*
* In relational context ActiveQuery represents a relation between two Active Record classes.
*
* Relational ActiveQuery instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveQuery object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method.
* These methods may only be called in a relational context. Same is true for [[inverseOf()]], which
* marks a relation as inverse of another relation and [[onCondition()]] which adds a condition that
* is to be added to relational querys join condition.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
* @since 2.0 * @since 2.0
*/ */
class ActiveQuery extends Query implements ActiveQueryInterface class ActiveQuery extends Query implements ActiveQueryInterface, ActiveRelationInterface
{ {
use ActiveQueryTrait; use ActiveQueryTrait;
use ActiveRelationTrait;
/** /**
* @var string the SQL statement to be executed for retrieving AR records. * @var string the SQL statement to be executed for retrieving AR records.
* This is set by [[ActiveRecord::findBySql()]]. * This is set by [[ActiveRecord::findBySql()]].
*/ */
public $sql; public $sql;
/**
* @var string|array the join condition to be used when this query is used in a relational context.
* The condition will be used in the ON part when [[ActiveQuery::joinWith()]] is called.
* Otherwise, the condition will be used in the WHERE part of a query.
* Please refer to [[Query::where()]] on how to specify this parameter.
* @see onCondition()
*/
public $on;
/** /**
...@@ -175,6 +208,31 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -175,6 +208,31 @@ class ActiveQuery extends Query implements ActiveQueryInterface
*/ */
public function createCommand($db = null) public function createCommand($db = null)
{ {
if ($this->primaryModel === null) {
// not a relational context or eager loading
if (!empty($this->on)) {
$where = $this->where;
$this->andWhere($this->on);
$command = $this->createCommandInternal($db);
$this->where = $where;
return $command;
} else {
return $this->createCommandInternal($db);
}
} else {
// lazy loading of a relation
return $this->createRelationalCommand($db);
}
}
/**
* Creates a DB command that can be used to execute this query.
* @param Connection $db the DB connection used to create the DB command.
* If null, the DB connection returned by [[modelClass]] will be used.
* @return Command the created DB command instance.
*/
protected function createCommandInternal($db)
{
/** @var ActiveRecord $modelClass */ /** @var ActiveRecord $modelClass */
$modelClass = $this->modelClass; $modelClass = $this->modelClass;
if ($db === null) { if ($db === null) {
...@@ -191,6 +249,47 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -191,6 +249,47 @@ class ActiveQuery extends Query implements ActiveQueryInterface
} }
/** /**
* Creates a command for lazy loading of a relation.
* @param Connection $db the DB connection used to create the DB command.
* @return Command the created DB command instance.
*/
private function createRelationalCommand($db = null)
{
$where = $this->where;
if ($this->via instanceof self) {
// via pivot table
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveQuery $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
if (!empty($this->on)) {
$this->andWhere($this->on);
}
$command = $this->createCommandInternal($db);
$this->where = $where;
return $command;
}
/**
* Joins with the specified relations. * Joins with the specified relations.
* *
* This method allows you to reuse existing relation definitions to perform JOIN queries. * This method allows you to reuse existing relation definitions to perform JOIN queries.
...@@ -355,14 +454,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -355,14 +454,14 @@ class ActiveQuery extends Query implements ActiveQueryInterface
* Joins a parent query with a child query. * Joins a parent query with a child query.
* The current query object will be modified accordingly. * The current query object will be modified accordingly.
* @param ActiveQuery $parent * @param ActiveQuery $parent
* @param ActiveRelation $child * @param ActiveRelationInterface $child
* @param string $joinType * @param string $joinType
*/ */
private function joinWithRelation($parent, $child, $joinType) private function joinWithRelation($parent, $child, $joinType)
{ {
$via = $child->via; $via = $child->via;
$child->via = null; $child->via = null;
if ($via instanceof ActiveRelation) { if ($via instanceof ActiveRelationInterface) {
// via table // via table
$this->joinWithRelation($parent, $via, $joinType); $this->joinWithRelation($parent, $via, $joinType);
$this->joinWithRelation($via, $child, $joinType); $this->joinWithRelation($via, $child, $joinType);
...@@ -426,4 +525,67 @@ class ActiveQuery extends Query implements ActiveQueryInterface ...@@ -426,4 +525,67 @@ class ActiveQuery extends Query implements ActiveQueryInterface
} }
} }
} }
/**
* Sets the ON condition for a relational query.
* The condition will be used in the ON part when [[ActiveQuery::joinWith()]] is called.
* Otherwise, the condition will be used in the WHERE part of a query.
*
* Use this method to specify additional conditions when declaring a relation in the [[ActiveRecord]] class:
*
* ```php
* public function getActiveUsers()
* {
* return $this->hasMany(User::className(), ['id' => 'user_id'])->onCondition(['active' => true]);
* }
* ```
*
* @param string|array $condition the ON condition. Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
* @return static the query object itself
*/
public function onCondition($condition, $params = [])
{
$this->on = $condition;
$this->addParams($params);
return $this;
}
/**
* Specifies the pivot table for a relational query.
*
* Use this method to specify a pivot table when declaring a relation in the [[ActiveRecord]] class:
*
* ```php
* public function getItems()
* {
* return $this->hasMany(Item::className(), ['id' => 'item_id'])
* ->viaTable('tbl_order_item', ['order_id' => 'id']);
* }
* ```
*
* @param string $tableName the name of the pivot table.
* @param array $link the link between the pivot table and the table associated with [[primaryModel]].
* The keys of the array represent the columns in the pivot table, and the values represent the columns
* in the [[primaryModel]] table.
* @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
* @see via()
*/
public function viaTable($tableName, $link, $callable = null)
{
$relation = new ActiveQuery([
'modelClass' => get_class($this->primaryModel),
'from' => [$tableName],
'link' => $link,
'multiple' => true,
'asArray' => true,
]);
$this->via = $relation;
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}
} }
...@@ -151,7 +151,8 @@ class ActiveRecord extends BaseActiveRecord ...@@ -151,7 +151,8 @@ class ActiveRecord extends BaseActiveRecord
/** /**
* Creates an [[ActiveQuery]] instance. * Creates an [[ActiveQuery]] instance.
* *
* This method is called by [[find()]], [[findBySql()]] to start a SELECT query. * This method is called by [[find()]], [[findBySql()]] to start a SELECT query but also
* by [[hasOne()]] and [[hasMany()]] to create a relational 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.)
* *
...@@ -167,11 +168,13 @@ class ActiveRecord extends BaseActiveRecord ...@@ -167,11 +168,13 @@ class ActiveRecord extends BaseActiveRecord
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the * Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition. * default condition. Using [[Query::where()]] will override the default condition.
* *
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQuery the newly created [[ActiveQuery]] instance. * @return ActiveQuery the newly created [[ActiveQuery]] instance.
*/ */
public static function createQuery() public static function createQuery($config)
{ {
return new ActiveQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new ActiveQuery($config);
} }
/** /**
...@@ -263,18 +266,6 @@ class ActiveRecord extends BaseActiveRecord ...@@ -263,18 +266,6 @@ class ActiveRecord extends BaseActiveRecord
} }
/** /**
* 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.
*/
public static function createRelation($config = [])
{
return new ActiveRelation($config);
}
/**
* @inheritdoc * @inheritdoc
*/ */
public static function populateRecord($record, $row) public static function populateRecord($record, $row)
......
...@@ -112,7 +112,10 @@ interface ActiveRecordInterface ...@@ -112,7 +112,10 @@ interface ActiveRecordInterface
/** /**
* Creates an [[ActiveQueryInterface|ActiveQuery]] instance. * Creates an [[ActiveQueryInterface|ActiveQuery]] instance.
* *
* This method is called by [[find()]] to start a SELECT query. * This method is called by [[find()]] to start a SELECT query but also
* by [[BaseActiveRecord::hasOne()]] and [[BaseActiveRecord::hasMany()]] to
* create a relational 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.)
* *
...@@ -128,9 +131,10 @@ interface ActiveRecordInterface ...@@ -128,9 +131,10 @@ interface ActiveRecordInterface
* Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the * Note that all queries should use [[Query::andWhere()]] and [[Query::orWhere()]] to keep the
* default condition. Using [[Query::where()]] will override the default condition. * default condition. Using [[Query::where()]] will override the default condition.
* *
* @param array $config the configuration passed to the ActiveRelation class.
* @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance. * @return ActiveQueryInterface the newly created [[ActiveQueryInterface|ActiveQuery]] instance.
*/ */
public static function createQuery(); public static function createQuery($config);
/** /**
* Updates records using the provided attribute values and conditions. * Updates records using the provided attribute values and conditions.
...@@ -256,21 +260,12 @@ interface ActiveRecordInterface ...@@ -256,21 +260,12 @@ interface ActiveRecordInterface
public function equals($record); public function equals($record);
/** /**
* Creates an [[ActiveRelationInterface|ActiveRelation]] instance.
* This method is called by [[BaseActiveRecord::hasOne()]] and [[BaseActiveRecord::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.
*/
public static function createRelation($config = []);
/**
* Returns the relation object with the specified name. * Returns the relation object with the specified name.
* A relation is defined by a getter method which returns an [[ActiveRelationInterface|ActiveRelation]] object. * A relation is defined by a getter method which returns an object implementing the [[ActiveRelationInterface]]
* (normally this would be an [[ActiveQuery]] object).
* It can be declared in either the ActiveRecord class itself or one of its behaviors. * It can be declared in either the ActiveRecord class itself or one of its behaviors.
* @param string $name the relation name * @param string $name the relation name
* @return ActiveRelation the relation object * @return ActiveRelationInterface the relation object
*/ */
public function getRelation($name); public function getRelation($name);
......
<?php
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\db;
/**
* ActiveRelation represents a relation between two Active Record classes.
*
* ActiveRelation instances are usually created by calling [[ActiveRecord::hasOne()]] and
* [[ActiveRecord::hasMany()]]. An Active Record class declares a relation by defining
* a getter method which calls one of the above methods and returns the created ActiveRelation object.
*
* A relation is specified by [[link]] which represents the association between columns
* of different tables; and the multiplicity of the relation is indicated by [[multiple]].
*
* If a relation involves a pivot table, it may be specified by [[via()]] or [[viaTable()]] method.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc>
* @since 2.0
*/
class ActiveRelation extends ActiveQuery implements ActiveRelationInterface
{
use ActiveRelationTrait;
/**
* @var string|array the join condition. Please refer to [[Query::where()]] on how to specify this parameter.
* The condition will be used in the ON part when [[ActiveQuery::joinWith()]] is called.
* Otherwise, the condition will be used in the WHERE part of a query.
*/
public $on;
/**
* Sets the ON condition for the query.
* The condition will be used in the ON part when [[ActiveQuery::joinWith()]] is called.
* Otherwise, the condition will be used in the WHERE part of a query.
* @param string|array $condition the ON condition. Please refer to [[Query::where()]] on how to specify this parameter.
* @param array $params the parameters (name => value) to be bound to the query.
* @return static the query object itself
*/
public function onCondition($condition, $params = [])
{
$this->on = $condition;
$this->addParams($params);
return $this;
}
/**
* Specifies the pivot table.
* @param string $tableName the name of the pivot table.
* @param array $link the link between the pivot table and the table associated with [[primaryModel]].
* The keys of the array represent the columns in the pivot table, and the values represent the columns
* in the [[primaryModel]] table.
* @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
*/
public function viaTable($tableName, $link, $callable = null)
{
$relation = new ActiveRelation([
'modelClass' => get_class($this->primaryModel),
'from' => [$tableName],
'link' => $link,
'multiple' => true,
'asArray' => true,
]);
$this->via = $relation;
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}
/**
* Creates a DB command that can be used to execute this query.
* @param Connection $db the DB connection used to create the DB command.
* If null, the DB connection returned by [[modelClass]] will be used.
* @return Command the created DB command instance.
*/
public function createCommand($db = null)
{
if ($this->primaryModel === null) {
// eager loading
if (!empty($this->on)) {
$where = $this->where;
$this->andWhere($this->on);
$command = parent::createCommand($db);
$this->where = $where;
return $command;
} else {
return parent::createCommand($db);
}
}
// lazy loading
$where = $this->where;
if ($this->via instanceof self) {
// via pivot table
$viaModels = $this->via->findPivotRows([$this->primaryModel]);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/** @var ActiveRelation $viaQuery */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->multiple) {
$viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels);
} else {
$model = $viaQuery->one();
$this->primaryModel->populateRelation($viaName, $model);
$viaModels = $model === null ? [] : [$model];
}
$this->filterByModels($viaModels);
} else {
$this->filterByModels([$this->primaryModel]);
}
if (!empty($this->on)) {
$this->andWhere($this->on);
}
$command = parent::createCommand($db);
$this->where = $where;
return $command;
}
}
...@@ -6,9 +6,10 @@ ...@@ -6,9 +6,10 @@
*/ */
namespace yii\db; namespace yii\db;
use yii\base\InvalidParamException;
/** /**
* ActiveRelationInterface defines the common interface to be implemented by active record relation classes. * ActiveRelationInterface defines the common interface to be implemented by relational active record query classes.
* *
* A class implementing this interface should also use [[ActiveRelationTrait]]. * A class implementing this interface should also use [[ActiveRelationTrait]].
* *
...@@ -26,4 +27,14 @@ interface ActiveRelationInterface extends ActiveQueryInterface ...@@ -26,4 +27,14 @@ interface ActiveRelationInterface extends ActiveQueryInterface
* @return static the relation object itself. * @return static the relation object itself.
*/ */
public function via($relationName, $callable = null); public function via($relationName, $callable = null);
/**
* Finds the related records for the specified primary record.
* This method is invoked when a relation of an ActiveRecord is being accessed in a lazy fashion.
* @param string $name the relation name
* @param ActiveRecordInterface $model the primary model
* @return mixed the related record(s)
* @throws InvalidParamException if the relation is invalid
*/
public function findFor($name, $model);
} }
...@@ -11,7 +11,7 @@ use yii\base\InvalidConfigException; ...@@ -11,7 +11,7 @@ use yii\base\InvalidConfigException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
/** /**
* ActiveRelationTrait implements the common methods and properties for active record relation classes. * ActiveRelationTrait implements the common methods and properties for active record relational queries.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @author Carsten Brandt <mail@cebe.cc> * @author Carsten Brandt <mail@cebe.cc>
...@@ -20,25 +20,30 @@ use yii\base\InvalidParamException; ...@@ -20,25 +20,30 @@ use yii\base\InvalidParamException;
trait ActiveRelationTrait trait ActiveRelationTrait
{ {
/** /**
* @var boolean whether this relation should populate all query results into AR instances. * @var boolean whether this query represents a relation to more than one record.
* If false, only the first row of the results will be retrieved. * This property is only used in relational context. If true, this relation will
* populate all query results into AR instances using [[all()]].
* If false, only the first row of the results will be retrieved using [[one()]].
*/ */
public $multiple; public $multiple;
/** /**
* @var ActiveRecord the primary model that this relation is associated with. * @var ActiveRecord the primary model of a relational query.
* This is used only in lazy loading with dynamic query options. * This is used only in lazy loading with dynamic query options.
*/ */
public $primaryModel; public $primaryModel;
/** /**
* @var array the columns of the primary and foreign tables that establish the relation. * @var array the columns of the primary and foreign tables that establish a relation.
* The array keys must be columns of the table for this relation, and the array values * The array keys must be columns of the table for this relation, and the array values
* must be the corresponding columns from the primary table. * must be the corresponding columns from the primary table.
* Do not prefix or quote the column names as this will be done automatically by Yii. * Do not prefix or quote the column names as this will be done automatically by Yii.
* This property is only used in relational context.
*/ */
public $link; public $link;
/** /**
* @var array the query associated with the pivot table. Please call [[via()]] * @var array the query associated with the pivot table. Please call [[via()]]
* to set this property instead of directly setting it. * to set this property instead of directly setting it.
* This property is only used in relational context.
* @see via()
*/ */
public $via; public $via;
/** /**
...@@ -48,9 +53,12 @@ trait ActiveRelationTrait ...@@ -48,9 +53,12 @@ trait ActiveRelationTrait
* If this property is set, the primary record(s) will be referenced through the specified relation. * If this property is set, the primary record(s) will be referenced through the specified relation.
* For example, `$customer->orders[0]->customer` and `$customer` will be the same object, * For example, `$customer->orders[0]->customer` and `$customer` will be the same object,
* and accessing the customer of an order will not trigger new DB query. * and accessing the customer of an order will not trigger new DB query.
* This property is only used in relational context.
* @see inverseOf()
*/ */
public $inverseOf; public $inverseOf;
/** /**
* Clones internal objects. * Clones internal objects.
*/ */
...@@ -66,6 +74,22 @@ trait ActiveRelationTrait ...@@ -66,6 +74,22 @@ trait ActiveRelationTrait
/** /**
* Specifies the relation associated with the pivot table. * Specifies the relation associated with the pivot table.
*
* Use this method to specify a pivot record/table when declaring a relation in the [[ActiveRecord]] class:
*
* ```php
* public function getOrders()
* {
* return $this->hasOne(Order::className(), ['id' => 'order_id']);
* }
*
* public function getOrderItems()
* {
* return $this->hasMany(Item::className(), ['id' => 'item_id'])
* ->via('orders', ['order_id' => 'id']);
* }
* ```
*
* @param string $relationName the relation name. This refers to a relation declared in [[primaryModel]]. * @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. * @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. * Its signature should be `function($query)`, where `$query` is the query to be customized.
...@@ -87,7 +111,17 @@ trait ActiveRelationTrait ...@@ -87,7 +111,17 @@ trait ActiveRelationTrait
* is the "orders", and the inverse of the "orders" relation is the "customer". * is the "orders", and the inverse of the "orders" relation is the "customer".
* If this property is set, the primary record(s) will be referenced through the specified relation. * If this property is set, the primary record(s) will be referenced through the specified relation.
* For example, `$customer->orders[0]->customer` and `$customer` will be the same object, * For example, `$customer->orders[0]->customer` and `$customer` will be the same object,
* and accessing the customer of an order will not trigger new DB query. * and accessing the customer of an order will not trigger a new DB query.
*
* Use this method when declaring a relation in the [[ActiveRecord]] class:
*
* ```php
* public function getOrders()
* {
* return $this->hasMany(Order::className(), ['customer_id' => 'id'])->inverseOf('customer');
* }
* ```
*
* @param string $relationName the name of the relation that is the inverse of this relation. * @param string $relationName the name of the relation that is the inverse of this relation.
* @return static the relation object itself. * @return static the relation object itself.
*/ */
......
...@@ -289,7 +289,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -289,7 +289,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
/** /**
* Declares a `has-one` relation. * Declares a `has-one` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance * The declaration is returned in terms of a relational [[ActiveQuery]] instance
* through which the related record can be queried and retrieved back. * through which the related record can be queried and retrieved back.
* *
* A `has-one` relation means that there is at most one related record matching * A `has-one` relation means that there is at most one related record matching
...@@ -309,7 +309,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -309,7 +309,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* in the related class `Country`, while the 'country_id' value refers to an attribute name * in the related class `Country`, while the 'country_id' value refers to an attribute name
* in the current AR class. * in the current AR class.
* *
* Call methods declared in [[ActiveRelation]] to further customize the relation. * Call methods declared in [[ActiveQuery]] to further customize the relation.
* *
* @param string $class the class name of the related record * @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to * @param array $link the primary-foreign key constraint. The keys of the array refer to
...@@ -320,7 +320,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -320,7 +320,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
public function hasOne($class, $link) public function hasOne($class, $link)
{ {
/** @var ActiveRecord $class */ /** @var ActiveRecord $class */
return $class::createRelation([ return $class::createQuery([
'modelClass' => $class, 'modelClass' => $class,
'primaryModel' => $this, 'primaryModel' => $this,
'link' => $link, 'link' => $link,
...@@ -330,7 +330,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -330,7 +330,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
/** /**
* Declares a `has-many` relation. * Declares a `has-many` relation.
* The declaration is returned in terms of an [[ActiveRelation]] instance * The declaration is returned in terms of a relational [[ActiveQuery]] instance
* through which the related record can be queried and retrieved back. * through which the related record can be queried and retrieved back.
* *
* A `has-many` relation means that there are multiple related records matching * A `has-many` relation means that there are multiple related records matching
...@@ -350,6 +350,8 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -350,6 +350,8 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* an attribute name in the related class `Order`, while the 'id' value refers to * an attribute name in the related class `Order`, while the 'id' value refers to
* an attribute name in the current AR class. * an attribute name in the current AR class.
* *
* Call methods declared in [[ActiveQuery]] to further customize the relation.
*
* @param string $class the class name of the related record * @param string $class the class name of the related record
* @param array $link the primary-foreign key constraint. The keys of the array refer to * @param array $link the primary-foreign key constraint. The keys of the array refer to
* the attributes of the record associated with the `$class` model, while the values of the * the attributes of the record associated with the `$class` model, while the values of the
...@@ -359,7 +361,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -359,7 +361,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
public function hasMany($class, $link) public function hasMany($class, $link)
{ {
/** @var ActiveRecord $class */ /** @var ActiveRecord $class */
return $class::createRelation([ return $class::createQuery([
'modelClass' => $class, 'modelClass' => $class,
'primaryModel' => $this, 'primaryModel' => $this,
'link' => $link, 'link' => $link,
...@@ -1035,10 +1037,10 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -1035,10 +1037,10 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
/** /**
* Returns the relation object with the specified name. * Returns the relation object with the specified name.
* A relation is defined by a getter method which returns an [[ActiveRelation]] object. * A relation is defined by a getter method which returns an [[ActiveRelationInterface]] object.
* It can be declared in either the Active Record class itself or one of its behaviors. * It can be declared in either the Active Record class itself or one of its behaviors.
* @param string $name the relation name * @param string $name the relation name
* @return ActiveRelation the relation object * @return ActiveRelationInterface|ActiveQuery the relation object
* @throws InvalidParamException if the named relation does not exist. * @throws InvalidParamException if the named relation does not exist.
*/ */
public function getRelation($name) public function getRelation($name)
...@@ -1082,7 +1084,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -1082,7 +1084,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
* @param ActiveRecord $model the model to be linked with the current one. * @param ActiveRecord $model the model to be linked with the current one.
* @param array $extraColumns additional column values to be saved into the pivot table. * @param array $extraColumns additional column values to be saved into the pivot table.
* This parameter is only meaningful for a relationship involving a pivot table * This parameter is only meaningful for a relationship involving a pivot table
* (i.e., a relation set with `[[ActiveRelation::via()]]` or `[[ActiveRelation::viaTable()]]`.) * (i.e., a relation set with [[ActiveRelationTrait::via()]] or `[[ActiveQuery::viaTable()]]`.)
* @throws InvalidCallException if the method is unable to link two models. * @throws InvalidCallException if the method is unable to link two models.
*/ */
public function link($name, $model, $extraColumns = []) public function link($name, $model, $extraColumns = [])
...@@ -1094,7 +1096,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -1094,7 +1096,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
throw new InvalidCallException('Unable to link models: both models must NOT be newly created.'); throw new InvalidCallException('Unable to link models: both models must NOT be newly created.');
} }
if (is_array($relation->via)) { if (is_array($relation->via)) {
/** @var ActiveRelation $viaRelation */ /** @var ActiveQuery $viaRelation */
list($viaName, $viaRelation) = $relation->via; list($viaName, $viaRelation) = $relation->via;
$viaClass = $viaRelation->modelClass; $viaClass = $viaRelation->modelClass;
// unset $viaName so that it can be reloaded to reflect the change // unset $viaName so that it can be reloaded to reflect the change
...@@ -1178,7 +1180,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface ...@@ -1178,7 +1180,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface
if ($relation->via !== null) { if ($relation->via !== null) {
if (is_array($relation->via)) { if (is_array($relation->via)) {
/** @var ActiveRelation $viaRelation */ /** @var ActiveQuery $viaRelation */
list($viaName, $viaRelation) = $relation->via; list($viaName, $viaRelation) = $relation->via;
$viaClass = $viaRelation->modelClass; $viaClass = $viaRelation->modelClass;
unset($this->_related[$viaName]); unset($this->_related[$viaName]);
......
...@@ -41,8 +41,9 @@ class Customer extends ActiveRecord ...@@ -41,8 +41,9 @@ class Customer extends ActiveRecord
parent::afterSave($insert); parent::afterSave($insert);
} }
public static function createQuery() public static function createQuery($config)
{ {
return new CustomerQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new CustomerQuery($config);
} }
} }
...@@ -63,8 +63,9 @@ class Customer extends ActiveRecord ...@@ -63,8 +63,9 @@ class Customer extends ActiveRecord
} }
public static function createQuery() public static function createQuery($config)
{ {
return new CustomerQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new CustomerQuery($config);
} }
} }
...@@ -25,8 +25,9 @@ class Customer extends ActiveRecord ...@@ -25,8 +25,9 @@ class Customer extends ActiveRecord
return $this->hasMany(CustomerOrder::className(), ['customer_id' => '_id']); return $this->hasMany(CustomerOrder::className(), ['customer_id' => '_id']);
} }
public static function createQuery() public static function createQuery($config)
{ {
return new CustomerQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new CustomerQuery($config);
} }
} }
\ No newline at end of file
...@@ -20,8 +20,9 @@ class CustomerFile extends ActiveRecord ...@@ -20,8 +20,9 @@ class CustomerFile extends ActiveRecord
); );
} }
public static function createQuery() public static function createQuery($config)
{ {
return new CustomerFileQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new CustomerFileQuery($config);
} }
} }
\ No newline at end of file
...@@ -17,7 +17,7 @@ class Customer extends ActiveRecord ...@@ -17,7 +17,7 @@ class Customer extends ActiveRecord
} }
/** /**
* @return \yii\redis\ActiveRelation * @return \yii\redis\ActiveQuery
*/ */
public function getOrders() public function getOrders()
{ {
...@@ -31,8 +31,9 @@ class Customer extends ActiveRecord ...@@ -31,8 +31,9 @@ class Customer extends ActiveRecord
parent::afterSave($insert); parent::afterSave($insert);
} }
public static function createQuery() public static function createQuery($config)
{ {
return new CustomerQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new CustomerQuery($config);
} }
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace yiiunit\data\ar\sphinx; namespace yiiunit\data\ar\sphinx;
use yii\sphinx\ActiveRelation; use yii\sphinx\ActiveQuery;
use yiiunit\data\ar\ActiveRecord as ActiveRecordDb; use yiiunit\data\ar\ActiveRecord as ActiveRecordDb;
class ArticleDb extends ActiveRecordDb class ArticleDb extends ActiveRecordDb
...@@ -20,6 +20,6 @@ class ArticleDb extends ActiveRecordDb ...@@ -20,6 +20,6 @@ class ArticleDb extends ActiveRecordDb
'link' => ['id' => 'id'], 'link' => ['id' => 'id'],
'multiple' => false, 'multiple' => false,
]; ];
return new ActiveRelation($config); return new ActiveQuery($config);
} }
} }
\ No newline at end of file
...@@ -25,8 +25,9 @@ class ArticleIndex extends ActiveRecord ...@@ -25,8 +25,9 @@ class ArticleIndex extends ActiveRecord
return $this->source->content; return $this->source->content;
} }
public static function createQuery() public static function createQuery($config)
{ {
return new ArticleIndexQuery(['modelClass' => get_called_class()]); $config['modelClass'] = get_called_class();
return new ArticleIndexQuery($config);
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment