Fixes #17089: Fixed caching of related records when via() using with callable

This commit is contained in:
Pavel Ivanov
2019-02-13 22:22:07 +02:00
committed by Alexander Makarov
parent 6aa6359bbc
commit 2da6773b68
5 changed files with 50 additions and 6 deletions

View File

@ -6,7 +6,7 @@ Yii Framework 2 Change Log
- Bug #17094: Fixed response on 204 status. Now it is empty (GHopperMSK) - Bug #17094: Fixed response on 204 status. Now it is empty (GHopperMSK)
- Bug #17098: Fixed message/extract when using message params returned from method calls (rugabarbo) - Bug #17098: Fixed message/extract when using message params returned from method calls (rugabarbo)
- Bug #17089: Fixed caching of related records when `via()` using with callable (rugabarbo)
2.0.16 January 30, 2019 2.0.16 January 30, 2019
----------------------- -----------------------

View File

@ -170,16 +170,20 @@ class ActiveQuery extends Query implements ActiveQueryInterface
} elseif (is_array($this->via)) { } elseif (is_array($this->via)) {
// via relation // via relation
/* @var $viaQuery ActiveQuery */ /* @var $viaQuery ActiveQuery */
list($viaName, $viaQuery) = $this->via; list($viaName, $viaQuery, $viaCallableUsed) = $this->via;
if ($viaQuery->multiple) { if ($viaQuery->multiple) {
if ($this->primaryModel->isRelationPopulated($viaName)) { if ($viaCallableUsed) {
$viaModels = $viaQuery->all();
} elseif ($this->primaryModel->isRelationPopulated($viaName)) {
$viaModels = $this->primaryModel->$viaName; $viaModels = $this->primaryModel->$viaName;
} else { } else {
$viaModels = $viaQuery->all(); $viaModels = $viaQuery->all();
$this->primaryModel->populateRelation($viaName, $viaModels); $this->primaryModel->populateRelation($viaName, $viaModels);
} }
} else { } else {
if ($this->primaryModel->isRelationPopulated($viaName)) { if ($viaCallableUsed) {
$model = $viaQuery->one();
} elseif ($this->primaryModel->isRelationPopulated($viaName)) {
$model = $this->primaryModel->$viaName; $model = $this->primaryModel->$viaName;
} else { } else {
$model = $viaQuery->one(); $model = $viaQuery->one();

View File

@ -74,7 +74,7 @@ trait ActiveRelationTrait
if (is_object($this->via)) { if (is_object($this->via)) {
$this->via = clone $this->via; $this->via = clone $this->via;
} elseif (is_array($this->via)) { } elseif (is_array($this->via)) {
$this->via = [$this->via[0], clone $this->via[1]]; $this->via = [$this->via[0], clone $this->via[1], $this->via[2]];
} }
} }
@ -105,7 +105,8 @@ trait ActiveRelationTrait
public function via($relationName, callable $callable = null) public function via($relationName, callable $callable = null)
{ {
$relation = $this->primaryModel->getRelation($relationName); $relation = $this->primaryModel->getRelation($relationName);
$this->via = [$relationName, $relation]; $callableUsed = $callable !== null;
$this->via = [$relationName, $relation, $callableUsed];
if ($callable !== null) { if ($callable !== null) {
call_user_func($callable, $relation); call_user_func($callable, $relation);
} }

View File

@ -7,6 +7,8 @@
namespace yiiunit\data\ar; namespace yiiunit\data\ar;
use yii\db\ActiveQuery;
/** /**
* Class Order. * Class Order.
* *
@ -14,6 +16,9 @@ namespace yiiunit\data\ar;
* @property int $customer_id * @property int $customer_id
* @property int $created_at * @property int $created_at
* @property string $total * @property string $total
*
* @property-read Item[] $expensiveItemsUsingViaWithCallable
* @property-read Item[] $cheapItemsUsingViaWithCallable
*/ */
class Order extends ActiveRecord class Order extends ActiveRecord
{ {
@ -78,6 +83,22 @@ class Order extends ActiveRecord
})->orderBy('item.id'); })->orderBy('item.id');
} }
public function getExpensiveItemsUsingViaWithCallable()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->via('orderItems', function (ActiveQuery $q) {
$q->where(['>=', 'subtotal', 10]);
});
}
public function getCheapItemsUsingViaWithCallable()
{
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->via('orderItems', function (ActiveQuery $q) {
$q->where(['<', 'subtotal', 10]);
});
}
public function getItemsIndexed() public function getItemsIndexed()
{ {
return $this->hasMany(Item::className(), ['id' => 'item_id']) return $this->hasMany(Item::className(), ['id' => 'item_id'])

View File

@ -1275,4 +1275,22 @@ trait ActiveRecordTestTrait
$this->assertFalse($customer->canGetProperty('non_existing_property')); $this->assertFalse($customer->canGetProperty('non_existing_property'));
$this->assertFalse($customer->canSetProperty('non_existing_property')); $this->assertFalse($customer->canSetProperty('non_existing_property'));
} }
/**
* @see https://github.com/yiisoft/yii2/issues/17089
*/
public function testViaWithCallable()
{
$order = Order::findOne(2);
$expensiveItems = $order->expensiveItemsUsingViaWithCallable;
$cheapItems = $order->cheapItemsUsingViaWithCallable;
$this->assertCount(2, $expensiveItems);
$this->assertEquals(4, $expensiveItems[0]->id);
$this->assertEquals(5, $expensiveItems[1]->id);
$this->assertCount(1, $cheapItems);
$this->assertEquals(3, $cheapItems[0]->id);
}
} }