Trait yii\db\ActiveRelationTrait
Implemented by | luya\admin\ngrest\base\NgRestActiveQuery, yii\db\ActiveQuery |
---|---|
Available since version | 2.0 |
Source Code | https://github.com/yiisoft/yii2/blob/master/framework/db/ActiveRelationTrait.php |
ActiveRelationTrait implements the common methods and properties for active record relational queries.
Public Properties
Property | Type | Description | Defined By |
---|---|---|---|
$inverseOf | string | The name of the relation that is the inverse of this relation. | yii\db\ActiveRelationTrait |
$link | array | The columns of the primary and foreign tables that establish a relation. | yii\db\ActiveRelationTrait |
$modelClass | yii\db\ActiveRecord | yii\db\ActiveRelationTrait | |
$multiple | boolean | Whether this query represents a relation to more than one record. | yii\db\ActiveRelationTrait |
$primaryModel | yii\db\ActiveRecord | The primary model of a relational query. | yii\db\ActiveRelationTrait |
$via | array|object | The query associated with the junction table. | yii\db\ActiveRelationTrait |
Public Methods
Method | Description | Defined By |
---|---|---|
__clone() | Clones internal objects. | yii\db\ActiveRelationTrait |
all() | See yii\db\ActiveQueryInterface::all() for more info. | yii\db\ActiveRelationTrait |
findFor() | Finds the related records for the specified primary record. | yii\db\ActiveRelationTrait |
inverseOf() | Sets the name of the relation that is the inverse of this relation. | yii\db\ActiveRelationTrait |
one() | See yii\db\ActiveQueryInterface::one() for more info. | yii\db\ActiveRelationTrait |
populateRelation() | Finds the related records and populates them into the primary models. | yii\db\ActiveRelationTrait |
via() | Specifies the relation associated with the junction table. | yii\db\ActiveRelationTrait |
Property Details
The name of the relation that is the inverse of this relation.
For example, an order has a customer, which means the inverse of the "customer" relation
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.
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.
This property is only used in relational context.
See also inverseOf().
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 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. This property is only used in relational context.
The primary model of a relational query. This is used only in lazy loading with dynamic query options.
Method Details
Clones internal objects.
public void __clone ( ) |
public function __clone()
{
parent::__clone();
// make a clone of "via" object so that the same query object can be reused multiple times
if (is_object($this->via)) {
$this->via = clone $this->via;
} elseif (is_array($this->via)) {
$this->via = [$this->via[0], clone $this->via[1], $this->via[2]];
}
}
See yii\db\ActiveQueryInterface::all() for more info.
public yii\db\ActiveRecordInterface[] all ( $db ) | ||
$db | ||
return | yii\db\ActiveRecordInterface[] |
---|
Finds the related records for the specified primary record.
This method is invoked when a relation of an ActiveRecord is being accessed lazily.
public mixed findFor ( $name, $model ) | ||
$name | string |
The relation name |
$model | yii\db\ActiveRecordInterface|yii\db\BaseActiveRecord |
The primary model |
return | mixed |
The related record(s) |
---|---|---|
throws | yii\base\InvalidArgumentException |
if the relation is invalid |
public function findFor($name, $model)
{
if (method_exists($model, 'get' . $name)) {
$method = new \ReflectionMethod($model, 'get' . $name);
$realName = lcfirst(substr($method->getName(), 3));
if ($realName !== $name) {
throw new InvalidArgumentException('Relation names are case sensitive. ' . get_class($model) . " has a relation named \"$realName\" instead of \"$name\".");
}
}
return $this->multiple ? $this->all() : $this->one();
}
Sets the name of the relation that is the inverse of this relation.
For example, a customer has orders, which means 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.
For example, $customer->orders[0]->customer
and $customer
will be the same object,
and accessing the customer of an order will not trigger a new DB query.
Use this method when declaring a relation in the yii\db\ActiveRecord class, e.g. in Customer model:
public function getOrders()
{
return $this->hasMany(Order::class, ['customer_id' => 'id'])->inverseOf('customer');
}
This also may be used for Order model, but with caution:
public function getCustomer()
{
return $this->hasOne(Customer::class, ['id' => 'customer_id'])->inverseOf('orders');
}
in this case result will depend on how order(s) was loaded. Let's suppose customer has several orders. If only one order was loaded:
$orders = Order::find()->where(['id' => 1])->all();
$customerOrders = $orders[0]->customer->orders;
variable $customerOrders
will contain only one order. If orders was loaded like this:
$orders = Order::find()->with('customer')->where(['customer_id' => 1])->all();
$customerOrders = $orders[0]->customer->orders;
variable $customerOrders
will contain all orders of the customer.
public $this inverseOf ( $relationName ) | ||
$relationName | string |
The name of the relation that is the inverse of this relation. |
return | $this |
The relation object itself. |
---|
public function inverseOf($relationName)
{
$this->inverseOf = $relationName;
return $this;
}
See yii\db\ActiveQueryInterface::one() for more info.
public yii\db\ActiveRecordInterface|array|null one ( $db ) | ||
$db | ||
return | yii\db\ActiveRecordInterface|array|null |
---|
Finds the related records and populates them into the primary models.
public array populateRelation ( $name, &$primaryModels ) | ||
$name | string |
The relation name |
$primaryModels | array |
Primary models |
return | array |
The related models |
---|---|---|
throws | yii\base\InvalidConfigException |
if $link is invalid |
public function populateRelation($name, &$primaryModels)
{
if (!is_array($this->link)) {
throw new InvalidConfigException('Invalid link: it must be an array of key-value pairs.');
}
if ($this->via instanceof self) {
// via junction table
/* @var $viaQuery ActiveRelationTrait */
$viaQuery = $this->via;
$viaModels = $viaQuery->findJunctionRows($primaryModels);
$this->filterByModels($viaModels);
} elseif (is_array($this->via)) {
// via relation
/* @var $viaQuery ActiveRelationTrait|ActiveQueryTrait */
list($viaName, $viaQuery) = $this->via;
if ($viaQuery->asArray === null) {
// inherit asArray from primary query
$viaQuery->asArray($this->asArray);
}
$viaQuery->primaryModel = null;
$viaModels = array_filter($viaQuery->populateRelation($viaName, $primaryModels));
$this->filterByModels($viaModels);
} else {
$this->filterByModels($primaryModels);
}
if (!$this->multiple && count($primaryModels) === 1) {
$model = $this->one();
$primaryModel = reset($primaryModels);
if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $model);
} else {
$primaryModels[key($primaryModels)][$name] = $model;
}
if ($this->inverseOf !== null) {
$this->populateInverseRelation($primaryModels, [$model], $name, $this->inverseOf);
}
return [$model];
}
// https://github.com/yiisoft/yii2/issues/3197
// delay indexing related models after buckets are built
$indexBy = $this->indexBy;
$this->indexBy = null;
$models = $this->all();
if (isset($viaModels, $viaQuery)) {
$buckets = $this->buildBuckets($models, $this->link, $viaModels, $viaQuery);
} else {
$buckets = $this->buildBuckets($models, $this->link);
}
$this->indexBy = $indexBy;
if ($this->indexBy !== null && $this->multiple) {
$buckets = $this->indexBuckets($buckets, $this->indexBy);
}
$link = array_values($this->link);
if (isset($viaQuery)) {
$deepViaQuery = $viaQuery;
while ($deepViaQuery->via) {
$deepViaQuery = is_array($deepViaQuery->via) ? $deepViaQuery->via[1] : $deepViaQuery->via;
};
$link = array_values($deepViaQuery->link);
}
foreach ($primaryModels as $i => $primaryModel) {
$keys = null;
if ($this->multiple && count($link) === 1) {
$primaryModelKey = reset($link);
$keys = isset($primaryModel[$primaryModelKey]) ? $primaryModel[$primaryModelKey] : null;
}
if (is_array($keys)) {
$value = [];
foreach ($keys as $key) {
$key = $this->normalizeModelKey($key);
if (isset($buckets[$key])) {
if ($this->indexBy !== null) {
// if indexBy is set, array_merge will cause renumbering of numeric array
foreach ($buckets[$key] as $bucketKey => $bucketValue) {
$value[$bucketKey] = $bucketValue;
}
} else {
$value = array_merge($value, $buckets[$key]);
}
}
}
} else {
$key = $this->getModelKey($primaryModel, $link);
$value = isset($buckets[$key]) ? $buckets[$key] : ($this->multiple ? [] : null);
}
if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $value);
} else {
$primaryModels[$i][$name] = $value;
}
}
if ($this->inverseOf !== null) {
$this->populateInverseRelation($primaryModels, $models, $name, $this->inverseOf);
}
return $models;
}
Specifies the relation associated with the junction table.
Use this method to specify a pivot record/table when declaring a relation in the yii\db\ActiveRecord class:
class Order extends ActiveRecord
{
public function getOrderItems() {
return $this->hasMany(OrderItem::class, ['order_id' => 'id']);
}
public function getItems() {
return $this->hasMany(Item::class, ['id' => 'item_id'])
->via('orderItems');
}
}
public $this via ( $relationName, callable $callable = null ) | ||
$relationName | string |
The relation name. This refers to a relation declared in $primaryModel. |
$callable | callable|null |
A PHP callback for customizing the relation associated with the junction table.
Its signature should be |
return | $this |
The relation object itself. |
---|
public function via($relationName, callable $callable = null)
{
$relation = $this->primaryModel->getRelation($relationName);
$callableUsed = $callable !== null;
$this->via = [$relationName, $relation, $callableUsed];
if ($callable !== null) {
call_user_func($callable, $relation);
}
return $this;
}