Trait yii\db\ActiveRelationTrait

Implemented byluya\admin\ngrest\base\NgRestActiveQuery, yii\db\ActiveQuery
Available since version2.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

Hide inherited properties

Property Type Description Defined By
$inverseOf string The name of the relation that is the inverse of this 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

Hide inherited 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

Hide inherited properties

$inverseOf public property

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().

public string $inverseOf null
$modelClass public property
$multiple public property

Whether this query represents a relation to more than one record. 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 boolean $multiple null
$primaryModel public property

The primary model of a relational query. This is used only in lazy loading with dynamic query options.

$via public property

The query associated with the junction table. Please call via() to set this property instead of directly setting it. This property is only used in relational context.

See also via().

public array|object $via null

Method Details

Hide inherited methods

__clone() public method

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]];
    }
}

            
all() public method
public yii\db\ActiveRecordInterface[] all ( $db )
$db
return yii\db\ActiveRecordInterface[]
findFor() public method

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();
}

            
inverseOf() public method

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;
}

            
populateRelation() public method

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;
}

            
via() public method

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 function($query), where $query is the query to be customized.

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;
}