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 = $viaQuery->populateRelation($viaName, $primaryModels);
$this->filterByModels($viaModels);
} else {
$this->filterByModels($primaryModels);
}
if (!$this->multiple && count($primaryModels) === 1) {
$model = $this->one();
foreach ($primaryModels as $i => $primaryModel) {
if ($primaryModel instanceof ActiveRecordInterface) {
$primaryModel->populateRelation($name, $model);
} else {
$primaryModels[$i][$name] = $model;
}
if ($this->inverseOf !== null) {
$this->populateInverseRelation($primaryModels, [$model], $name, $this->inverseOf);
}
}
return [$model];
} else {
// 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->link);
} 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(isset($viaQuery) ? $viaQuery->link : $this->link);
foreach ($primaryModels as $i => $primaryModel) {
if ($this->multiple && count($link) === 1 && is_array($keys = $primaryModel[reset($link)])) {
$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;
}
}