From 54f25c4b04a0c1fb24b9c9583c878555f5d1ecef Mon Sep 17 00:00:00 2001 From: Bizley Date: Sun, 14 Mar 2021 17:04:07 +0100 Subject: [PATCH] Fix #17174: Fix `yii\db\BaseActiveRecord::unlink()` to not ignore `on` conditions in `via` relations --- framework/CHANGELOG.md | 3 +- framework/db/BaseActiveRecord.php | 6 ++ tests/data/ar/Order.php | 25 +++--- tests/data/cubrid.sql | 2 +- tests/data/mssql.sql | 2 +- tests/data/mysql.sql | 2 +- tests/data/oci.sql | 2 +- tests/data/postgres.sql | 2 +- tests/data/sqlite.sql | 2 +- tests/framework/ar/ActiveRecordTestTrait.php | 113 +++++++++++++------------- tests/framework/db/ActiveRecordTest.php | 46 ++++++++++- tests/framework/db/pgsql/ActiveRecordTest.php | 7 +- 12 files changed, 126 insertions(+), 86 deletions(-) diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index 0f1384f..daa5119 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -7,7 +7,8 @@ Yii Framework 2 Change Log - Enh #18534: Added `prepareSearchQuery` property in `yii\rest\IndexAction` (programmis) - Bug #17479: Fix `yii\grid\ActionColumn` to render icons when no glyphicons are available (simialbi) - Bug #18544: Fix `yii\validators\NumberValidator` to disallow values with whitespaces (bizley) -- Bug #18552: Fix bug with `yii\data\SqlDataProvider` not properly handling SQL with `ORDER BY` clause (bizley) +- Bug #18552: Fix `yii\data\SqlDataProvider` to properly handle SQL with `ORDER BY` clause (bizley) +- Bug #17174: Fix `yii\db\BaseActiveRecord::unlink()` to not ignore `on` conditions in `via` relations (bizley) - Bug #18557: Fix `yii\data\ActiveDataProvider` to handle DB connection configuration of different type than just `yii\db\Connection` (bizley) diff --git a/framework/db/BaseActiveRecord.php b/framework/db/BaseActiveRecord.php index aa5f3b0..403979d 100644 --- a/framework/db/BaseActiveRecord.php +++ b/framework/db/BaseActiveRecord.php @@ -1384,9 +1384,12 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface * If `false`, the model's foreign key will be set `null` and saved. * If `true`, the model containing the foreign key will be deleted. * @throws InvalidCallException if the models cannot be unlinked + * @throws Exception + * @throws StaleObjectException */ public function unlink($name, $model, $delete = false) { + /* @var $relation ActiveQueryInterface|ActiveQuery */ $relation = $this->getRelation($name); if ($relation->via !== null) { @@ -1410,6 +1413,9 @@ abstract class BaseActiveRecord extends Model implements ActiveRecordInterface foreach (array_keys($columns) as $a) { $nulls[$a] = null; } + if ($viaRelation->on !== null) { + $columns = ['and', $columns, $viaRelation->on]; + } if (is_array($relation->via)) { /* @var $viaClass ActiveRecordInterface */ if ($delete) { diff --git a/tests/data/ar/Order.php b/tests/data/ar/Order.php index 475ff1a..6fbc5b0 100644 --- a/tests/data/ar/Order.php +++ b/tests/data/ar/Order.php @@ -19,6 +19,7 @@ use yii\db\ActiveQuery; * * @property-read Item[] $expensiveItemsUsingViaWithCallable * @property-read Item[] $cheapItemsUsingViaWithCallable + * @property-read Item[] $itemsFor8 */ class Order extends ActiveRecord { @@ -169,13 +170,6 @@ class Order extends ActiveRecord ->viaTable('order_item', ['order_id' => 'id']); } -// public function getBooksQuerysyntax() -// { -// return $this->hasMany(Item::className(), ['id' => 'item_id']) -// ->onCondition(['{{@item}}.category_id' => 1]) -// ->viaTable('order_item', ['order_id' => 'id']); -// } - public function getBooksExplicitA() { return $this->hasMany(Item::className(), ['id' => 'item_id'])->alias('bo') @@ -183,13 +177,6 @@ class Order extends ActiveRecord ->viaTable('order_item', ['order_id' => 'id']); } -// public function getBooksQuerysyntaxA() -// { -// return $this->hasMany(Item::className(), ['id' => 'item_id'])->alias('bo') -// ->onCondition(['{{@item}}.category_id' => 1]) -// ->viaTable('order_item', ['order_id' => 'id']); -// } - public function getBookItems() { return $this->hasMany(Item::className(), ['id' => 'item_id'])->alias('books') @@ -241,4 +228,14 @@ class Order extends ActiveRecord { return $this->hasMany(OrderItem::className(), ['order_id' => 'id', 'quantity' => 'id']); } + + public function getOrderItemsFor8() + { + return $this->hasMany(OrderItemWithNullFK::className(), ['order_id' => 'id'])->andOnCondition(['subtotal' => 8.0]); + } + + public function getItemsFor8() + { + return $this->hasMany(Item::className(), ['id' => 'item_id'])->via('orderItemsFor8'); + } } diff --git a/tests/data/cubrid.sql b/tests/data/cubrid.sql index f0c5897..19cdee5 100644 --- a/tests/data/cubrid.sql +++ b/tests/data/cubrid.sql @@ -229,7 +229,7 @@ INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VA INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 8.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); INSERT INTO "document" (title, content, version) VALUES ('Yii 2.0 guide', 'This is Yii 2.0 guide', 0); diff --git a/tests/data/mssql.sql b/tests/data/mssql.sql index 57f4e59..0536147 100644 --- a/tests/data/mssql.sql +++ b/tests/data/mssql.sql @@ -247,7 +247,7 @@ INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (1, 2, 2, 40.0); INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 4, 1, 10.0); INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 15.0); -INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 3, 1, 8.0); +INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (2, 5, 1, 8.0); INSERT INTO [dbo].[order_item_with_null_fk] ([order_id], [item_id], [quantity], [subtotal]) VALUES (3, 2, 1, 40.0); INSERT INTO [dbo].[document] ([title], [content], [version]) VALUES ('Yii 2.0 guide', 'This is Yii 2.0 guide', 0); diff --git a/tests/data/mysql.sql b/tests/data/mysql.sql index a509a56..afc8a4c 100644 --- a/tests/data/mysql.sql +++ b/tests/data/mysql.sql @@ -264,7 +264,7 @@ INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VA INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 8.0); INSERT INTO `order_item_with_null_fk` (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); INSERT INTO `document` (title, content, version) VALUES ('Yii 2.0 guide', 'This is Yii 2.0 guide', 0); diff --git a/tests/data/oci.sql b/tests/data/oci.sql index 17cc176..bf5e3da 100644 --- a/tests/data/oci.sql +++ b/tests/data/oci.sql @@ -413,7 +413,7 @@ INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subto INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (1, 2, 2, 40.0); INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 4, 1, 10.0); INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (2, 5, 1, 8.0); INSERT INTO "order_item_with_null_fk" ("order_id", "item_id", "quantity", "subtotal") VALUES (3, 2, 1, 40.0); INSERT INTO "document" ("title", "content", "version") VALUES ('Yii 2.0 guide', 'This is Yii 2.0 guide', 0); diff --git a/tests/data/postgres.sql b/tests/data/postgres.sql index 3be9e70..6336a81 100644 --- a/tests/data/postgres.sql +++ b/tests/data/postgres.sql @@ -268,7 +268,7 @@ INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VA INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 8.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); INSERT INTO "document" (title, content, version) VALUES ('Yii 2.0 guide', 'This is Yii 2.0 guide', 0); diff --git a/tests/data/sqlite.sql b/tests/data/sqlite.sql index b39cc7a..dc11e22 100644 --- a/tests/data/sqlite.sql +++ b/tests/data/sqlite.sql @@ -228,7 +228,7 @@ INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VA INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (1, 2, 2, 40.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 4, 1, 10.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 15.0); -INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 3, 1, 8.0); +INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (2, 5, 1, 8.0); INSERT INTO "order_item_with_null_fk" (order_id, item_id, quantity, subtotal) VALUES (3, 2, 1, 40.0); INSERT INTO "document" (title, content, version) VALUES ('Yii 2.0 guide', 'This is Yii 2.0 guide', 0); diff --git a/tests/framework/ar/ActiveRecordTestTrait.php b/tests/framework/ar/ActiveRecordTestTrait.php index 5c189e0..4c34161 100644 --- a/tests/framework/ar/ActiveRecordTestTrait.php +++ b/tests/framework/ar/ActiveRecordTestTrait.php @@ -8,6 +8,7 @@ namespace yiiunit\framework\ar; use yii\base\Event; +use yii\db\ActiveRecordInterface; use yii\db\BaseActiveRecord; use yii\db\Expression; use yiiunit\data\ar\Customer; @@ -62,7 +63,7 @@ trait ActiveRecordTestTrait public function testFind() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ // find one @@ -125,7 +126,7 @@ trait ActiveRecordTestTrait public function testFindAsArray() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); // asArray @@ -161,7 +162,7 @@ trait ActiveRecordTestTrait public function testHasAttribute() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); $customer = new $customerClass(); @@ -181,7 +182,7 @@ trait ActiveRecordTestTrait public function testFindScalar() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -198,7 +199,7 @@ trait ActiveRecordTestTrait public function testFindColumn() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -208,7 +209,7 @@ trait ActiveRecordTestTrait public function testFindIndexBy() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ // indexBy @@ -230,7 +231,7 @@ trait ActiveRecordTestTrait public function testFindIndexByAsArray() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -277,7 +278,7 @@ trait ActiveRecordTestTrait public function testRefresh() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ $customer = new $customerClass(); @@ -291,9 +292,9 @@ trait ActiveRecordTestTrait public function testEquals() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); - /* @var $itemClass \yii\db\ActiveRecordInterface */ + /* @var $itemClass ActiveRecordInterface */ $itemClass = $this->getItemClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -319,7 +320,7 @@ trait ActiveRecordTestTrait public function testFindCount() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -339,7 +340,7 @@ trait ActiveRecordTestTrait public function testFindLimit() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -386,7 +387,7 @@ trait ActiveRecordTestTrait public function testFindComplexCondition() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -402,7 +403,7 @@ trait ActiveRecordTestTrait public function testFindNullValues() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -418,7 +419,7 @@ trait ActiveRecordTestTrait public function testExists() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -434,7 +435,7 @@ trait ActiveRecordTestTrait public function testFindLazy() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -462,9 +463,9 @@ trait ActiveRecordTestTrait public function testFindEager() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -499,7 +500,7 @@ trait ActiveRecordTestTrait public function testFindLazyVia() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -513,7 +514,7 @@ trait ActiveRecordTestTrait public function testFindLazyVia2() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -525,7 +526,7 @@ trait ActiveRecordTestTrait public function testFindEagerViaRelation() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -541,7 +542,7 @@ trait ActiveRecordTestTrait public function testFindNestedRelation() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -578,7 +579,7 @@ trait ActiveRecordTestTrait */ public function testFindEagerViaRelationPreserveOrder() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -641,7 +642,7 @@ trait ActiveRecordTestTrait // different order in via table public function testFindEagerViaRelationPreserveOrderB() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); $orders = $orderClass::find()->with('itemsInOrder2')->orderBy('created_at')->all(); @@ -671,10 +672,10 @@ trait ActiveRecordTestTrait public function testLink() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ - /* @var $itemClass \yii\db\ActiveRecordInterface */ - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ + /* @var $itemClass ActiveRecordInterface */ + /* @var $orderItemClass ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); $orderClass = $this->getOrderClass(); $orderItemClass = $this->getOrderItemClass(); @@ -724,17 +725,15 @@ trait ActiveRecordTestTrait public function testUnlink() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); - /* @var $orderWithNullFKClass \yii\db\ActiveRecordInterface */ + /* @var $orderWithNullFKClass ActiveRecordInterface */ $orderWithNullFKClass = $this->getOrderWithNullFKClass(); - /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemsWithNullFKClass ActiveRecordInterface */ $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); - - /* @var $this TestCase|ActiveRecordTestTrait */ // has many without delete $customer = $customerClass::findOne(2); @@ -767,27 +766,27 @@ trait ActiveRecordTestTrait $this->assertCount(2, $order->orderItems); // via model without delete - $this->assertCount(3, $order->itemsWithNullFK); - $order->unlink('itemsWithNullFK', $order->itemsWithNullFK[2], false); + $this->assertCount(2, $order->itemsWithNullFK); + $order->unlink('itemsWithNullFK', $order->itemsWithNullFK[1], false); $this->afterSave(); - $this->assertCount(2, $order->itemsWithNullFK); + $this->assertCount(1, $order->itemsWithNullFK); $this->assertCount(2, $order->orderItems); } public function testUnlinkAll() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemClass ActiveRecordInterface */ $orderItemClass = $this->getOrderItemClass(); - /* @var $itemClass \yii\db\ActiveRecordInterface */ + /* @var $itemClass ActiveRecordInterface */ $itemClass = $this->getItemClass(); - /* @var $orderWithNullFKClass \yii\db\ActiveRecordInterface */ + /* @var $orderWithNullFKClass ActiveRecordInterface */ $orderWithNullFKClass = $this->getOrderWithNullFKClass(); - /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemsWithNullFKClass ActiveRecordInterface */ $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -898,7 +897,7 @@ trait ActiveRecordTestTrait public function testInsert() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ $customer = new $customerClass(); @@ -922,7 +921,7 @@ trait ActiveRecordTestTrait public function testExplicitPkOnAutoIncrement() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ $customer = new $customerClass(); @@ -941,7 +940,7 @@ trait ActiveRecordTestTrait public function testUpdate() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ // save @@ -984,7 +983,7 @@ trait ActiveRecordTestTrait public function testUpdateAttributes() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ /* @var $customer Customer */ @@ -1019,7 +1018,7 @@ trait ActiveRecordTestTrait public function testUpdateCounters() { - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemClass ActiveRecordInterface */ $orderItemClass = $this->getOrderItemClass(); /* @var $this TestCase|ActiveRecordTestTrait */ // updateCounters @@ -1050,7 +1049,7 @@ trait ActiveRecordTestTrait public function testDelete() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ // delete @@ -1082,7 +1081,7 @@ trait ActiveRecordTestTrait */ public function testBooleanAttribute() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ $customer = new $customerClass(); @@ -1109,7 +1108,7 @@ trait ActiveRecordTestTrait public function testAfterFind() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $orderClass BaseActiveRecord */ $orderClass = $this->getOrderClass(); @@ -1166,7 +1165,7 @@ trait ActiveRecordTestTrait public function testAfterRefresh() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -1187,7 +1186,7 @@ trait ActiveRecordTestTrait public function testFindEmptyInCondition() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ @@ -1208,7 +1207,7 @@ trait ActiveRecordTestTrait { /* @var $this TestCase|ActiveRecordTestTrait */ - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var $order Order */ @@ -1231,7 +1230,7 @@ trait ActiveRecordTestTrait public function testAttributeAccess() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); $model = new $customerClass(); @@ -1274,7 +1273,7 @@ trait ActiveRecordTestTrait $this->assertFalse($customer->canSetProperty('orderItems')); try { - /* @var $itemClass \yii\db\ActiveRecordInterface */ + /* @var $itemClass ActiveRecordInterface */ $itemClass = $this->getItemClass(); $customer->orderItems = [new $itemClass()]; $this->fail('setter call above MUST throw Exception'); @@ -1295,7 +1294,7 @@ trait ActiveRecordTestTrait */ public function testViaWithCallable() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); /* @var Order $order */ diff --git a/tests/framework/db/ActiveRecordTest.php b/tests/framework/db/ActiveRecordTest.php index aeb8d9d..1bf82bc 100644 --- a/tests/framework/db/ActiveRecordTest.php +++ b/tests/framework/db/ActiveRecordTest.php @@ -8,6 +8,7 @@ namespace yiiunit\framework\db; use yii\db\ActiveQuery; +use yii\db\ActiveRecordInterface; use yii\db\Query; use yii\helpers\ArrayHelper; use yiiunit\data\ar\ActiveRecord; @@ -1366,13 +1367,13 @@ abstract class ActiveRecordTest extends DatabaseTestCase public function testUnlinkAllViaTable() { - /* @var $orderClass \yii\db\ActiveRecordInterface */ + /* @var $orderClass ActiveRecordInterface */ $orderClass = $this->getOrderClass(); - /* @var $orderItemClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemClass ActiveRecordInterface */ $orderItemClass = $this->getOrderItemClass(); - /* @var $itemClass \yii\db\ActiveRecordInterface */ + /* @var $itemClass ActiveRecordInterface */ $itemClass = $this->getItemClass(); - /* @var $orderItemsWithNullFKClass \yii\db\ActiveRecordInterface */ + /* @var $orderItemsWithNullFKClass ActiveRecordInterface */ $orderItemsWithNullFKClass = $this->getOrderItemWithNullFKmClass(); // via table with delete @@ -2095,4 +2096,41 @@ abstract class ActiveRecordTest extends DatabaseTestCase } } } + + public function providerForUnlinkDelete() + { + return [ + 'with delete' => [true, 0], + 'without delete' => [false, 1], + ]; + } + + /** + * @dataProvider providerForUnlinkDelete + * @see https://github.com/yiisoft/yii2/issues/17174 + */ + public function testUnlinkWithViaOnCondition($delete, $count) + { + /* @var $orderClass ActiveRecordInterface */ + $orderClass = $this->getOrderClass(); + + $order = $orderClass::findOne(2); + $this->assertCount(1, $order->itemsFor8); + $order->unlink('itemsFor8', $order->itemsFor8[0], $delete); + + $order = $orderClass::findOne(2); + $this->assertCount(0, $order->itemsFor8); + $this->assertCount(2, $order->orderItemsWithNullFK); + + /* @var $orderItemClass ActiveRecordInterface */ + $orderItemClass = $this->getOrderItemWithNullFKmClass(); + $this->assertCount(1, $orderItemClass::findAll([ + 'order_id' => 2, + 'item_id' => 5, + ])); + $this->assertCount($count, $orderItemClass::findAll([ + 'order_id' => null, + 'item_id' => null, + ])); + } } diff --git a/tests/framework/db/pgsql/ActiveRecordTest.php b/tests/framework/db/pgsql/ActiveRecordTest.php index 5aea3e1..175da28 100644 --- a/tests/framework/db/pgsql/ActiveRecordTest.php +++ b/tests/framework/db/pgsql/ActiveRecordTest.php @@ -8,12 +8,11 @@ namespace yiiunit\framework\db\pgsql; use yii\behaviors\TimestampBehavior; +use yii\db\ActiveRecordInterface; use yii\db\ArrayExpression; use yii\db\Expression; -use yii\db\ExpressionInterface; use yii\db\JsonExpression; use yii\db\pgsql\Schema; -use yii\helpers\Json; use yiiunit\data\ar\ActiveRecord; use yiiunit\data\ar\DefaultPk; use yiiunit\framework\ar\ActiveRecordTestTrait; @@ -29,7 +28,7 @@ class ActiveRecordTest extends \yiiunit\framework\db\ActiveRecordTest public function testBooleanAttribute() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); /* @var $this TestCase|ActiveRecordTestTrait */ $customer = new $customerClass(); @@ -56,7 +55,7 @@ class ActiveRecordTest extends \yiiunit\framework\db\ActiveRecordTest public function testFindAsArray() { - /* @var $customerClass \yii\db\ActiveRecordInterface */ + /* @var $customerClass ActiveRecordInterface */ $customerClass = $this->getCustomerClass(); // asArray