From 5ee7fabbf948f3a759f5cfd9f76c72eef17694c8 Mon Sep 17 00:00:00 2001 From: drlibra <13391053+drlibra@users.noreply.github.com> Date: Mon, 10 Sep 2018 01:44:10 +0500 Subject: [PATCH] Fixes #16552: Added check in `yii\db\ActiveQuery::prepare()` to prevent populating already populated relation when another relation is requested with `via` --- framework/CHANGELOG.md | 1 + framework/db/ActiveQuery.php | 16 ++++++++++++---- framework/db/BaseActiveRecord.php | 12 ++++++++---- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 48c96e8da6..6fdd16f3ed 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -49,6 +49,7 @@ Yii Framework 2 Change Log - Enh #16603: Added `yii\mutex\FileMutex::$isWindows` for Windows file shares on Unix guest machines (brandonkelly) - Bug #16666: Fixed `yii\helpers\ArrayHelper::merge` (rustamwin) - Enh: `yii\helpers\UnsetArrayValue`, `yii\helpers\ReplaceArrayValue` object now can be restored after serialization using `var_export()` function (silvefire) +- Bug #16552: Added check in `yii\db\ActiveQuery::prepare()` to prevent populating already populated relation when another relation is requested with `via` (drlibra) 2.0.15.1 March 21, 2018 ----------------------- diff --git a/framework/db/ActiveQuery.php b/framework/db/ActiveQuery.php index 46086fbbab..5af019e441 100644 --- a/framework/db/ActiveQuery.php +++ b/framework/db/ActiveQuery.php @@ -172,11 +172,19 @@ class ActiveQuery extends Query implements ActiveQueryInterface /* @var $viaQuery ActiveQuery */ list($viaName, $viaQuery) = $this->via; if ($viaQuery->multiple) { - $viaModels = $viaQuery->all(); - $this->primaryModel->populateRelation($viaName, $viaModels); + if ($this->primaryModel->isRelationPopulated($viaName)) { + $viaModels = $this->primaryModel->$viaName; + } else { + $viaModels = $viaQuery->all(); + $this->primaryModel->populateRelation($viaName, $viaModels); + } } else { - $model = $viaQuery->one(); - $this->primaryModel->populateRelation($viaName, $model); + if ($this->primaryModel->isRelationPopulated($viaName)) { + $model = $this->primaryModel->$viaName; + } else { + $model = $viaQuery->one(); + $this->primaryModel->populateRelation($viaName, $model); + } $viaModels = $model === null ? [] : [$model]; } $this->filterByModels($viaModels); diff --git a/framework/db/BaseActiveRecord.php b/framework/db/BaseActiveRecord.php index e19b0a8fbb..cc47375f64 100644 --- a/framework/db/BaseActiveRecord.php +++ b/framework/db/BaseActiveRecord.php @@ -223,7 +223,7 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface * 1. Create a column to store the version number of each row. The column type should be `BIGINT DEFAULT 0`. * Override this method to return the name of this column. * 2. Ensure the version value is submitted and loaded to your model before any update or delete. - * Or add [[\yii\behaviors\OptimisticLockBehavior|OptimisticLockBehavior]] to your model + * Or add [[\yii\behaviors\OptimisticLockBehavior|OptimisticLockBehavior]] to your model * class in order to automate the process. * 3. In the Web form that collects the user input, add a hidden field that stores * the lock version of the recording being updated. @@ -1734,18 +1734,22 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface * Sets relation dependencies for a property * @param string $name property name * @param ActiveQueryInterface $relation relation instance + * @param string|null $viaRelationName intermediate relation */ - private function setRelationDependencies($name, $relation) + private function setRelationDependencies($name, $relation, $viaRelationName = null) { if (empty($relation->via) && $relation->link) { foreach ($relation->link as $attribute) { $this->_relationsDependencies[$attribute][$name] = $name; + if ($viaRelationName !== null) { + $this->_relationsDependencies[$attribute][] = $viaRelationName; + } } } elseif ($relation->via instanceof ActiveQueryInterface) { $this->setRelationDependencies($name, $relation->via); } elseif (is_array($relation->via)) { - list(, $viaQuery) = $relation->via; - $this->setRelationDependencies($name, $viaQuery); + list($viaRelationName, $viaQuery) = $relation->via; + $this->setRelationDependencies($name, $viaQuery, $viaRelationName); } } }