ActiveRecord::refresh() should not unset all relations but only the ones whose corresponding foreign key has changed
The https://github.com/yiisoft/yii2/pull/13618 introduced "magic" functionality that makes it look like changing foreign key attribute of a model also changes loaded relation model dependent on this foreign key. This was achieved by simply unsetting the affected relation (whose foreign key has changed).
This was actually a BC breaking change later documented in UPGRADE.md as:
Active Record relations are now being reset when corresponding key fields are changed.
Unfortunately, the original implementation didn't follow its own logic thoroughly and left the ActiveRecord::refresh() implemented incorrectly - unsetting ALL relations regardless of changes to the foreign keys. And so, if relations loaded before refresh() are used again after refresh() additional queries against database are executed to fetch the same data recently unset by refresh().
What steps will reproduce the problem?
$project = Project::findOne(123);
$project->manager; // Load relation.
$project->manager_id = 456; // Change relation foreign key.
var_dump($project->isRelationPopulated('manager')); // false - OK: foreign key changed, previously loaded relation is considered outdated and is unset.
$project = Project::findOne(123);
$project->manager;
$project->refresh(); // Assuming manager_id has not changed.
var_dump($project->isRelationPopulated('manager')); // false - BUG (expected true): foreign key is the same but relation is unset.
$project->manager; // If the relation is used later, another query must be performed against DB that loads the same data (unset by refresh()).What is the expected result?
false true
What do you get instead?
false false
Additional info
| Q | A |
|---|---|
| Yii version | 2.0.48 |
| PHP version | irrelevant |
| Operating system | irrelevant |
Source: yiisoft/yii2