active-record
active-record copied to clipboard
Faulty caching in AR relations with via and callable
The following code yields an unexpected behavior:
public function getCity()
{
return $this->hasOne(Cities::className(), ['id' => 'city_id'])
->via('orderPts',function($q){
$q->andWhere(['order_pts.idx' => 1]);
})
}
The problem is due to callable in via
. If I use $model->city
the result of the city
relation is cached together with the additional condition from the callable. Then all requests to $model->orderPts
return the result cached by $model->city
with additional condition.
Hm... relation should not be cached in this case... Would you be able to create a unit test case?
@cebe I found this issue too. I can't create Unit test for you, but you can repeat problem in following way:
public function getRealtyTypes()
{
return $this->hasMany(RealtyType::className(), ['realty_object_id' => 'id']);
}
public function getRealtyBuildings()
{
return $this->hasMany(RealtyBuilding::className(), ['id' => 'realty_building_id'])->via('realtyTypes', function($q){
$q->andWhere(['is_active' => 0]); //wrongQuery. Result = 0 rows
});
}
public function test(){
$this->realtyTypes; //Now we have all Types here
$this->realtyBuildings; //Now we overwrite all types by empty array
//...
}
This really bad thing, if you modify data in relation, and then this data was populated from via
on another relation...
Verified, created a PR with a failing test.
#11107
bug.tar.gz test example failed, when i use $category->products all products listed, but after use of $category->versions with filter, this filter is also used in $category->products, if you use after 'version' a 'products' so it is listed with filter which is in "version filter - function($q){ $q->andWhere(['products.id' => 1]); }"
Checking the code I only find ways to fix this that include a BC break. For now you should be able to work around the issue by using viaTable()
instead of via()
.
https://github.com/yiisoft/yii2/pull/11107