From ebc193fdbd76fec9b2b196d29b97c0ce3670c732 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 11:18:24 +0330 Subject: [PATCH 01/18] Add hybrid support to MorphToMany; --- src/Relations/MorphToMany.php | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index a2c55969f..cc2283c56 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -78,7 +78,11 @@ protected function setWhere() $this->query->whereIn($this->relatedKey, $ids); } else { - $this->query->whereIn($this->relatedKey, (array) $this->parent->{$this->relatedPivotKey}); + match ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + true => $this->query->whereIn($this->relatedKey, (array) $this->parent->{$this->relatedPivotKey}), + false => $this->query + ->whereIn($this->getQualifiedForeignPivotKeyName(), (array) $this->parent->{$this->parentKey}), + }; } return $this; @@ -130,7 +134,13 @@ public function sync($ids, $detaching = true) if ($this->getInverse()) { $current = $this->extractIds($this->parent->{$this->table} ?: []); } else { - $current = $this->parent->{$this->relatedPivotKey} ?: []; + $current = match($this->parent instanceof \MongoDB\Laravel\Eloquent\Model){ + true => $this->parent->{$this->relatedPivotKey} ?: [], + false => $this->parent->{$this->relationName} ?: [], + }; + if ($current instanceof Collection) { + $current = collect($this->parseIds($current))->flatten()->toArray(); + } } $records = $this->formatRecordsList($ids); @@ -239,7 +249,13 @@ public function attach($id, array $attributes = [], $touch = true) ], true); // Attach the new ids to the parent model. - $this->parent->push($this->relatedPivotKey, $id, true); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + $this->parent->push($this->relatedPivotKey, $id, true); + }else{ + $instance = new $this->related; + $instance->forceFill([$this->relatedKey => $id]); + $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + } } } @@ -287,7 +303,9 @@ public function detach($ids = [], $touch = true) $query->pull($this->foreignPivotKey, $this->parent->{$this->parentKey}); } else { // Remove the relation from the parent. - $this->parent->pull($this->relatedPivotKey, $ids); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + $this->parent->pull($this->relatedPivotKey, $ids); + } // Prepare the query to select all related objects. if (count($ids) > 0) { From 7983a59e2ee3804ca691467a4ddd85417674c9d6 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 11:20:58 +0330 Subject: [PATCH 02/18] Add test for hybrid MorphToMany; --- tests/HybridRelationsTest.php | 40 +++++++++++++++++++++++++++++++++++ tests/Models/Skill.php | 11 ++++++++++ tests/Models/SqlBook.php | 6 ++++++ tests/Models/SqlUser.php | 15 +++++++++++++ 4 files changed, 72 insertions(+) diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 9ff6264e5..6857a22a3 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\DB; use MongoDB\Laravel\Tests\Models\Book; use MongoDB\Laravel\Tests\Models\Role; +use MongoDB\Laravel\Tests\Models\Skill; use MongoDB\Laravel\Tests\Models\SqlBook; use MongoDB\Laravel\Tests\Models\SqlRole; use MongoDB\Laravel\Tests\Models\SqlUser; @@ -36,6 +37,7 @@ public function tearDown(): void SqlUser::truncate(); SqlBook::truncate(); SqlRole::truncate(); + Skill::truncate(); } public function testSqlRelations() @@ -210,4 +212,42 @@ public function testHybridWith() $this->assertEquals($user->id, $user->books->count()); }); } + + public function testHybridMorphToMany() + { + $user = new SqlUser(); + $user2 = new SqlUser(); + $this->assertInstanceOf(SqlUser::class, $user); + $this->assertInstanceOf(SQLiteConnection::class, $user->getConnection()); + $this->assertInstanceOf(SqlUser::class, $user2); + $this->assertInstanceOf(SQLiteConnection::class, $user2->getConnection()); + + $book = new SqlBook(); + $book2 = new SqlBook(); + $this->assertInstanceOf(SqlBook::class, $book); + $this->assertInstanceOf(SQLiteConnection::class, $user->getConnection()); + $this->assertInstanceOf(SqlBook::class, $book2); + $this->assertInstanceOf(SQLiteConnection::class, $user2->getConnection()); + + // Create Mysql Users + $user->fill(['name' => 'John Doe'])->save(); + $user = SqlUser::query()->find($user->id); + + $user2->fill(['name' => 'Maria Doe'])->save(); + $user2 = SqlUser::query()->find($user2->id); + + // Create Mongodb Clients + $skill = Skill::query()->create(['name' => 'Laravel']); + $skill2 = Skill::query()->create(['name' => 'MongoDB']); + + // MorphToMany (pivot is empty) + $user->skills()->sync([$skill->_id, $skill2->_id]); + $check = SqlUser::query()->find($user->id); + self::assertEquals(2,$check->skills->count()); + + // MorphToMany (pivot is not empty) + $user->skills()->sync($skill); + $check = SqlUser::query()->find($user->id); + self::assertEquals(1,$check->skills->count()); + } } diff --git a/tests/Models/Skill.php b/tests/Models/Skill.php index c4c1dbd0a..8ef5a094a 100644 --- a/tests/Models/Skill.php +++ b/tests/Models/Skill.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Tests\Models; +use Illuminate\Database\Eloquent\Relations\MorphToMany; use MongoDB\Laravel\Eloquent\Model as Eloquent; class Skill extends Eloquent @@ -11,4 +12,14 @@ class Skill extends Eloquent protected $connection = 'mongodb'; protected $collection = 'skills'; protected static $unguarded = true; + + public function sqlUsers(): MorphToMany + { + return $this->morphedByMany(SqlUser::class, 'skilled'); + } + + public function sqlBooks(): MorphToMany + { + return $this->morphedByMany(SqlBook::class, 'skilled'); + } } diff --git a/tests/Models/SqlBook.php b/tests/Models/SqlBook.php index babc984eb..316213011 100644 --- a/tests/Models/SqlBook.php +++ b/tests/Models/SqlBook.php @@ -11,6 +11,7 @@ use Illuminate\Support\Facades\Schema; use MongoDB\Laravel\Eloquent\HybridRelations; +use MongoDB\Laravel\Relations\MorphToMany; use function assert; class SqlBook extends EloquentModel @@ -27,6 +28,11 @@ public function author(): BelongsTo return $this->belongsTo(User::class, 'author_id'); } + public function skills(): MorphToMany + { + return $this->morphToMany(Skill::class, 'skilled'); + } + /** * Check if we need to run the schema. */ diff --git a/tests/Models/SqlUser.php b/tests/Models/SqlUser.php index 1fe11276a..06fc01fd2 100644 --- a/tests/Models/SqlUser.php +++ b/tests/Models/SqlUser.php @@ -11,6 +11,7 @@ use Illuminate\Database\Schema\SQLiteBuilder; use Illuminate\Support\Facades\Schema; use MongoDB\Laravel\Eloquent\HybridRelations; +use MongoDB\Laravel\Relations\MorphToMany; use function assert; @@ -22,6 +23,15 @@ class SqlUser extends EloquentModel protected $table = 'users'; protected static $unguarded = true; + public function push() + { + return parent::push(); // TODO: Change the autogenerated stub + } + + public function unsetRelation($relation) + { + } + public function books(): HasMany { return $this->hasMany(Book::class, 'author_id'); @@ -37,6 +47,11 @@ public function sqlBooks(): HasMany return $this->hasMany(SqlBook::class); } + public function skills(): MorphToMany + { + return $this->morphToMany(Skill::class, 'skilled'); + } + /** * Check if we need to run the schema. */ From 95f35d73775410b36e2d8b33d2ef17fbd6d5b66e Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 13:59:36 +0330 Subject: [PATCH 03/18] Add support for hybrid MorphedByMany; --- src/Eloquent/HybridRelations.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Eloquent/HybridRelations.php b/src/Eloquent/HybridRelations.php index 9551a6c43..c78c836a4 100644 --- a/src/Eloquent/HybridRelations.php +++ b/src/Eloquent/HybridRelations.php @@ -432,12 +432,17 @@ public function morphedByMany( $relatedKey = null, $relation = null, ) { - $foreignPivotKey = $foreignPivotKey ?: Str::plural($this->getForeignKey()); + // If the related model is an instance of eloquent model class, leave pivot keys + // as default. It's necessary for supporting hybrid relationship + if ( is_subclass_of($related, Model::class)) { + // For the inverse of the polymorphic many-to-many relations, we will change + // the way we determine the foreign and other keys, as it is the opposite + // of the morph-to-many method since we're figuring out these inverses. + $foreignPivotKey = $foreignPivotKey ?: Str::plural($this->getForeignKey()); - // For the inverse of the polymorphic many-to-many relations, we will change - // the way we determine the foreign and other keys, as it is the opposite - // of the morph-to-many method since we're figuring out these inverses. - $relatedPivotKey = $relatedPivotKey ?: $name . '_id'; + $relatedPivotKey = $relatedPivotKey ?: $name . '_id'; + + } return $this->morphToMany( $related, From f3d8cd3528884bfe5bdcc626067056fa6459e61e Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 14:00:00 +0330 Subject: [PATCH 04/18] Add test for hybrid MorphedByMany; --- tests/HybridRelationsTest.php | 21 ++++++++++++--------- tests/Models/SqlUser.php | 6 ++++++ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 6857a22a3..3c6f2e1c4 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -222,13 +222,6 @@ public function testHybridMorphToMany() $this->assertInstanceOf(SqlUser::class, $user2); $this->assertInstanceOf(SQLiteConnection::class, $user2->getConnection()); - $book = new SqlBook(); - $book2 = new SqlBook(); - $this->assertInstanceOf(SqlBook::class, $book); - $this->assertInstanceOf(SQLiteConnection::class, $user->getConnection()); - $this->assertInstanceOf(SqlBook::class, $book2); - $this->assertInstanceOf(SQLiteConnection::class, $user2->getConnection()); - // Create Mysql Users $user->fill(['name' => 'John Doe'])->save(); $user = SqlUser::query()->find($user->id); @@ -243,11 +236,21 @@ public function testHybridMorphToMany() // MorphToMany (pivot is empty) $user->skills()->sync([$skill->_id, $skill2->_id]); $check = SqlUser::query()->find($user->id); - self::assertEquals(2,$check->skills->count()); + $this->assertEquals(2,$check->skills->count()); // MorphToMany (pivot is not empty) $user->skills()->sync($skill); $check = SqlUser::query()->find($user->id); - self::assertEquals(1,$check->skills->count()); + $this->assertEquals(1,$check->skills->count()); + + // Inverse MorphToMany (pivot is empty) + $skill->sqlUsers()->sync([$user->id, $user2->id]); + $check = Skill::query()->find($skill->_id); + $this->assertEquals(2,$check->sqlUsers->count()); + + // Inverse MorphToMany (pivot is empty) + $skill->sqlUsers()->sync([$user->id, $user2->id]); + $check = Skill::query()->find($skill->_id); + $this->assertEquals(2,$check->sqlUsers->count()); } } diff --git a/tests/Models/SqlUser.php b/tests/Models/SqlUser.php index 06fc01fd2..74cc297fe 100644 --- a/tests/Models/SqlUser.php +++ b/tests/Models/SqlUser.php @@ -66,5 +66,11 @@ public static function executeSchema(): void $table->string('name'); $table->timestamps(); }); + if (!$schema->hasTable('skilleds')){ + $schema->create('skilleds',function (Blueprint $table){ + $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete(); + $table->morphs('skilled'); + }); + } } } From 030979180be21e2e8fcb2de409024b7fbc5c8057 Mon Sep 17 00:00:00 2001 From: hans-thomas Date: Tue, 28 Nov 2023 10:37:46 +0000 Subject: [PATCH 05/18] apply phpcbf formatting --- src/Eloquent/HybridRelations.php | 3 +-- src/Relations/MorphToMany.php | 7 ++++--- tests/HybridRelationsTest.php | 8 ++++---- tests/Models/SqlBook.php | 2 +- tests/Models/SqlUser.php | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Eloquent/HybridRelations.php b/src/Eloquent/HybridRelations.php index c78c836a4..5c058f50f 100644 --- a/src/Eloquent/HybridRelations.php +++ b/src/Eloquent/HybridRelations.php @@ -434,14 +434,13 @@ public function morphedByMany( ) { // If the related model is an instance of eloquent model class, leave pivot keys // as default. It's necessary for supporting hybrid relationship - if ( is_subclass_of($related, Model::class)) { + if (is_subclass_of($related, Model::class)) { // For the inverse of the polymorphic many-to-many relations, we will change // the way we determine the foreign and other keys, as it is the opposite // of the morph-to-many method since we're figuring out these inverses. $foreignPivotKey = $foreignPivotKey ?: Str::plural($this->getForeignKey()); $relatedPivotKey = $relatedPivotKey ?: $name . '_id'; - } return $this->morphToMany( diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index cc2283c56..61757318e 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -17,6 +17,7 @@ use function array_merge; use function array_reduce; use function array_values; +use function collect; use function count; use function is_array; use function is_numeric; @@ -134,7 +135,7 @@ public function sync($ids, $detaching = true) if ($this->getInverse()) { $current = $this->extractIds($this->parent->{$this->table} ?: []); } else { - $current = match($this->parent instanceof \MongoDB\Laravel\Eloquent\Model){ + $current = match ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { true => $this->parent->{$this->relatedPivotKey} ?: [], false => $this->parent->{$this->relationName} ?: [], }; @@ -251,8 +252,8 @@ public function attach($id, array $attributes = [], $touch = true) // Attach the new ids to the parent model. if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->push($this->relatedPivotKey, $id, true); - }else{ - $instance = new $this->related; + } else { + $instance = new $this->related(); $instance->forceFill([$this->relatedKey => $id]); $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); } diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 3c6f2e1c4..ba3eb90c7 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -236,21 +236,21 @@ public function testHybridMorphToMany() // MorphToMany (pivot is empty) $user->skills()->sync([$skill->_id, $skill2->_id]); $check = SqlUser::query()->find($user->id); - $this->assertEquals(2,$check->skills->count()); + $this->assertEquals(2, $check->skills->count()); // MorphToMany (pivot is not empty) $user->skills()->sync($skill); $check = SqlUser::query()->find($user->id); - $this->assertEquals(1,$check->skills->count()); + $this->assertEquals(1, $check->skills->count()); // Inverse MorphToMany (pivot is empty) $skill->sqlUsers()->sync([$user->id, $user2->id]); $check = Skill::query()->find($skill->_id); - $this->assertEquals(2,$check->sqlUsers->count()); + $this->assertEquals(2, $check->sqlUsers->count()); // Inverse MorphToMany (pivot is empty) $skill->sqlUsers()->sync([$user->id, $user2->id]); $check = Skill::query()->find($skill->_id); - $this->assertEquals(2,$check->sqlUsers->count()); + $this->assertEquals(2, $check->sqlUsers->count()); } } diff --git a/tests/Models/SqlBook.php b/tests/Models/SqlBook.php index 316213011..cc1333d35 100644 --- a/tests/Models/SqlBook.php +++ b/tests/Models/SqlBook.php @@ -10,8 +10,8 @@ use Illuminate\Database\Schema\SQLiteBuilder; use Illuminate\Support\Facades\Schema; use MongoDB\Laravel\Eloquent\HybridRelations; - use MongoDB\Laravel\Relations\MorphToMany; + use function assert; class SqlBook extends EloquentModel diff --git a/tests/Models/SqlUser.php b/tests/Models/SqlUser.php index 74cc297fe..7005cf598 100644 --- a/tests/Models/SqlUser.php +++ b/tests/Models/SqlUser.php @@ -66,8 +66,8 @@ public static function executeSchema(): void $table->string('name'); $table->timestamps(); }); - if (!$schema->hasTable('skilleds')){ - $schema->create('skilleds',function (Blueprint $table){ + if (! $schema->hasTable('skilleds')) { + $schema->create('skilleds', function (Blueprint $table) { $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete(); $table->morphs('skilled'); }); From 3432981dc3aac551a077ad3ed1aea99747d1fc21 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 14:13:15 +0330 Subject: [PATCH 06/18] WIP --- tests/HybridRelationsTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 3c6f2e1c4..a55e9a0a4 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -213,8 +213,9 @@ public function testHybridWith() }); } - public function testHybridMorphToMany() + public function testHybridMorphToManySqlModelToMongoModel() { + // SqlModel -> MorphToMany -> MongoModel $user = new SqlUser(); $user2 = new SqlUser(); $this->assertInstanceOf(SqlUser::class, $user); @@ -229,7 +230,7 @@ public function testHybridMorphToMany() $user2->fill(['name' => 'Maria Doe'])->save(); $user2 = SqlUser::query()->find($user2->id); - // Create Mongodb Clients + // Create Mongodb skills $skill = Skill::query()->create(['name' => 'Laravel']); $skill2 = Skill::query()->create(['name' => 'MongoDB']); From 33716b5ac826817c0094116bbef94858734dc400 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 15:43:04 +0330 Subject: [PATCH 07/18] Add hybrid MorphToMany support; MongoModel -> MorphToMany -> SqlModel --- src/Relations/MorphToMany.php | 66 +++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index cc2283c56..d8e2832c0 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -74,9 +74,14 @@ public function addEagerConstraints(array $models) protected function setWhere() { if ($this->getInverse()) { - $ids = $this->extractIds((array) $this->parent->{$this->table}); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + $ids = $this->extractIds((array) $this->parent->{$this->table}); - $this->query->whereIn($this->relatedKey, $ids); + $this->query->whereIn($this->relatedKey, $ids); + }else{ + $this->query + ->whereIn($this->foreignPivotKey, (array) $this->parent->{$this->parentKey}); + } } else { match ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { true => $this->query->whereIn($this->relatedKey, (array) $this->parent->{$this->relatedPivotKey}), @@ -132,7 +137,19 @@ public function sync($ids, $detaching = true) // in this joining table. We'll spin through the given IDs, checking to see // if they exist in the array of current ones, and if not we will insert. if ($this->getInverse()) { - $current = $this->extractIds($this->parent->{$this->table} ?: []); +// $current = $this->extractIds($this->parent->{$this->table} ?: []); + + $current = match($this->parent instanceof \MongoDB\Laravel\Eloquent\Model){ + true => $this->parent->{$this->table} ?: [], + false => $this->parent->{$this->relationName} ?: [], + }; + + if ($current instanceof Collection) { + $current = collect($this->parseIds($current))->flatten()->toArray(); + }else{ + $current = $this->extractIds($current); + } + } else { $current = match($this->parent instanceof \MongoDB\Laravel\Eloquent\Model){ true => $this->parent->{$this->relatedPivotKey} ?: [], @@ -231,14 +248,23 @@ public function attach($id, array $attributes = [], $touch = true) $query->push($this->foreignPivotKey, $this->parent->{$this->parentKey}); // Attach the new ids to the parent model. - foreach ($id as $item) { - $this->parent->push($this->table, [ - [ - $this->relatedPivotKey => $item, - $this->morphType => $this->related instanceof Model ? $this->related->getMorphClass() : null, - ], - ], true); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + foreach ($id as $item) { + $this->parent->push($this->table, [ + [ + $this->relatedPivotKey => $item, + $this->morphType => $this->related instanceof Model ? $this->related->getMorphClass() : null, + ], + ], true); + } + }else{ + foreach ($id as $item) { + $instance = new $this->related; + $instance->forceFill([$this->relatedKey => $item]); + $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + } } + } else { // Attach the new parent id to the related model. $query->push($this->table, [ @@ -252,9 +278,11 @@ public function attach($id, array $attributes = [], $touch = true) if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->push($this->relatedPivotKey, $id, true); }else{ - $instance = new $this->related; - $instance->forceFill([$this->relatedKey => $id]); - $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + foreach ($id as $item) { + $instance = new $this->related; + $instance->forceFill([$this->relatedKey => $item]); + $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + } } } } @@ -292,7 +320,13 @@ public function detach($ids = [], $touch = true) ]; } - $this->parent->pull($this->table, $data); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + $this->parent->pull($this->table, $data); + }else{ + $value = $this->parent->{$this->relationName} + ->filter(fn ($rel) => !in_array($rel->{$this->relatedKey},$this->extractIds($data))); + $this->parent->setRelation($this->relationName, $value); + } // Prepare the query to select all related objects. if (count($ids) > 0) { @@ -305,6 +339,10 @@ public function detach($ids = [], $touch = true) // Remove the relation from the parent. if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->pull($this->relatedPivotKey, $ids); + }else{ + $value = $this->parent->{$this->relationName} + ->filter(fn ($rel) => !in_array($rel->{$this->relatedKey},$ids)); + $this->parent->setRelation($this->relationName, $value); } // Prepare the query to select all related objects. From 77f56b71d1930fa5342db1e44ad4dfacb98c69a0 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 15:43:42 +0330 Subject: [PATCH 08/18] Add test for hybrid MorphToMany; MongoModel -> MorphToMany -> SqlModel --- tests/HybridRelationsTest.php | 44 +++++++++++++++++++++++++++++++++++ tests/Models/Experience.php | 6 +++++ tests/Models/Skill.php | 5 ---- tests/Models/SqlBook.php | 6 ----- tests/Models/SqlUser.php | 20 +++++++++------- 5 files changed, 61 insertions(+), 20 deletions(-) diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index a55e9a0a4..a3a0c434b 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -7,6 +7,7 @@ use Illuminate\Database\SQLiteConnection; use Illuminate\Support\Facades\DB; use MongoDB\Laravel\Tests\Models\Book; +use MongoDB\Laravel\Tests\Models\Experience; use MongoDB\Laravel\Tests\Models\Role; use MongoDB\Laravel\Tests\Models\Skill; use MongoDB\Laravel\Tests\Models\SqlBook; @@ -38,6 +39,7 @@ public function tearDown(): void SqlBook::truncate(); SqlRole::truncate(); Skill::truncate(); + Experience::truncate(); } public function testSqlRelations() @@ -254,4 +256,46 @@ public function testHybridMorphToManySqlModelToMongoModel() $check = Skill::query()->find($skill->_id); $this->assertEquals(2,$check->sqlUsers->count()); } + + public function testHybridMorphToManyMongoModelToSqlModel() + { + // MongoModel -> MorphToMany -> SqlModel + $user = new SqlUser(); + $user2 = new SqlUser(); + $this->assertInstanceOf(SqlUser::class, $user); + $this->assertInstanceOf(SQLiteConnection::class, $user->getConnection()); + $this->assertInstanceOf(SqlUser::class, $user2); + $this->assertInstanceOf(SQLiteConnection::class, $user2->getConnection()); + + // Create Mysql Users + $user->fill(['name' => 'John Doe'])->save(); + $user = SqlUser::query()->find($user->id); + + $user2->fill(['name' => 'Maria Doe'])->save(); + $user2 = SqlUser::query()->find($user2->id); + + // Create Mongodb experiences + $experience = Experience::query()->create(['title' => 'DB expert']); + $experience2 = Experience::query()->create(['title' => 'MongoDB']); + + // MorphToMany (pivot is empty) + $experience->sqlUsers()->sync([$user->id, $user2->id]); + $check = Experience::query()->find($experience->_id); + $this->assertEquals(2,$check->sqlUsers->count()); + + // MorphToMany (pivot is not empty) + $experience->sqlUsers()->sync([$user->id]); + $check = Experience::query()->find($experience->_id); + $this->assertEquals(1,$check->sqlUsers->count()); + + // Inverse MorphToMany (pivot is empty) + $user->experiences()->sync([$experience->_id, $experience2->_id]); + $check = SqlUser::query()->find($user->id); + $this->assertEquals(2,$check->experiences->count()); + + // Inverse MorphToMany (pivot is not empty) + $user->experiences()->sync([$experience->_id]); + $check = SqlUser::query()->find($user->id); + $this->assertEquals(1,$check->experiences->count()); + } } diff --git a/tests/Models/Experience.php b/tests/Models/Experience.php index 617073c79..4c2869d9e 100644 --- a/tests/Models/Experience.php +++ b/tests/Models/Experience.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Tests\Models; +use Illuminate\Database\Eloquent\Relations\MorphToMany; use MongoDB\Laravel\Eloquent\Model as Eloquent; class Experience extends Eloquent @@ -23,4 +24,9 @@ public function skillsWithCustomParentKey() { return $this->belongsToMany(Skill::class, parentKey: 'cexperience_id'); } + + public function sqlUsers(): MorphToMany + { + return $this->morphToMany(SqlUser::class, 'experienced'); + } } diff --git a/tests/Models/Skill.php b/tests/Models/Skill.php index 8ef5a094a..c19f25f08 100644 --- a/tests/Models/Skill.php +++ b/tests/Models/Skill.php @@ -17,9 +17,4 @@ public function sqlUsers(): MorphToMany { return $this->morphedByMany(SqlUser::class, 'skilled'); } - - public function sqlBooks(): MorphToMany - { - return $this->morphedByMany(SqlBook::class, 'skilled'); - } } diff --git a/tests/Models/SqlBook.php b/tests/Models/SqlBook.php index 316213011..babc984eb 100644 --- a/tests/Models/SqlBook.php +++ b/tests/Models/SqlBook.php @@ -11,7 +11,6 @@ use Illuminate\Support\Facades\Schema; use MongoDB\Laravel\Eloquent\HybridRelations; -use MongoDB\Laravel\Relations\MorphToMany; use function assert; class SqlBook extends EloquentModel @@ -28,11 +27,6 @@ public function author(): BelongsTo return $this->belongsTo(User::class, 'author_id'); } - public function skills(): MorphToMany - { - return $this->morphToMany(Skill::class, 'skilled'); - } - /** * Check if we need to run the schema. */ diff --git a/tests/Models/SqlUser.php b/tests/Models/SqlUser.php index 74cc297fe..7089b8c89 100644 --- a/tests/Models/SqlUser.php +++ b/tests/Models/SqlUser.php @@ -23,15 +23,6 @@ class SqlUser extends EloquentModel protected $table = 'users'; protected static $unguarded = true; - public function push() - { - return parent::push(); // TODO: Change the autogenerated stub - } - - public function unsetRelation($relation) - { - } - public function books(): HasMany { return $this->hasMany(Book::class, 'author_id'); @@ -52,6 +43,11 @@ public function skills(): MorphToMany return $this->morphToMany(Skill::class, 'skilled'); } + public function experiences(): MorphToMany + { + return $this->morphedByMany(Experience::class, 'experienced'); + } + /** * Check if we need to run the schema. */ @@ -72,5 +68,11 @@ public static function executeSchema(): void $table->morphs('skilled'); }); } + if (!$schema->hasTable('experienceds')){ + $schema->create('experienceds',function (Blueprint $table){ + $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete(); + $table->morphs('experienced'); + }); + } } } From 065d14a0bff11f5a9d83a63d5e6a95c5d3c00a15 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Tue, 28 Nov 2023 15:48:46 +0330 Subject: [PATCH 09/18] WIP --- src/Relations/MorphToMany.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index 244e80151..7fbb12c3f 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -138,8 +138,6 @@ public function sync($ids, $detaching = true) // in this joining table. We'll spin through the given IDs, checking to see // if they exist in the array of current ones, and if not we will insert. if ($this->getInverse()) { -// $current = $this->extractIds($this->parent->{$this->table} ?: []); - $current = match($this->parent instanceof \MongoDB\Laravel\Eloquent\Model){ true => $this->parent->{$this->table} ?: [], false => $this->parent->{$this->relationName} ?: [], From aad84cce287f18965a044f0f024b7b7ebd312e00 Mon Sep 17 00:00:00 2001 From: hans-thomas Date: Tue, 28 Nov 2023 12:19:50 +0000 Subject: [PATCH 10/18] apply phpcbf formatting --- src/Relations/MorphToMany.php | 20 ++++++++++---------- tests/HybridRelationsTest.php | 8 ++++---- tests/Models/SqlUser.php | 5 +++-- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index 7fbb12c3f..ce4ccd03d 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -19,6 +19,7 @@ use function array_values; use function collect; use function count; +use function in_array; use function is_array; use function is_numeric; @@ -79,7 +80,7 @@ protected function setWhere() $ids = $this->extractIds((array) $this->parent->{$this->table}); $this->query->whereIn($this->relatedKey, $ids); - }else{ + } else { $this->query ->whereIn($this->foreignPivotKey, (array) $this->parent->{$this->parentKey}); } @@ -138,17 +139,16 @@ public function sync($ids, $detaching = true) // in this joining table. We'll spin through the given IDs, checking to see // if they exist in the array of current ones, and if not we will insert. if ($this->getInverse()) { - $current = match($this->parent instanceof \MongoDB\Laravel\Eloquent\Model){ + $current = match ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { true => $this->parent->{$this->table} ?: [], false => $this->parent->{$this->relationName} ?: [], }; if ($current instanceof Collection) { $current = collect($this->parseIds($current))->flatten()->toArray(); - }else{ + } else { $current = $this->extractIds($current); } - } else { $current = match ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { true => $this->parent->{$this->relatedPivotKey} ?: [], @@ -256,9 +256,9 @@ public function attach($id, array $attributes = [], $touch = true) ], ], true); } - }else{ + } else { foreach ($id as $item) { - $instance = new $this->related; + $instance = new $this->related(); $instance->forceFill([$this->relatedKey => $item]); $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); } @@ -320,9 +320,9 @@ public function detach($ids = [], $touch = true) if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->pull($this->table, $data); - }else{ + } else { $value = $this->parent->{$this->relationName} - ->filter(fn ($rel) => !in_array($rel->{$this->relatedKey},$this->extractIds($data))); + ->filter(fn ($rel) => ! in_array($rel->{$this->relatedKey}, $this->extractIds($data))); $this->parent->setRelation($this->relationName, $value); } @@ -337,9 +337,9 @@ public function detach($ids = [], $touch = true) // Remove the relation from the parent. if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->pull($this->relatedPivotKey, $ids); - }else{ + } else { $value = $this->parent->{$this->relationName} - ->filter(fn ($rel) => !in_array($rel->{$this->relatedKey},$ids)); + ->filter(fn ($rel) => ! in_array($rel->{$this->relatedKey}, $ids)); $this->parent->setRelation($this->relationName, $value); } diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index a3594146a..00dd18652 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -281,21 +281,21 @@ public function testHybridMorphToManyMongoModelToSqlModel() // MorphToMany (pivot is empty) $experience->sqlUsers()->sync([$user->id, $user2->id]); $check = Experience::query()->find($experience->_id); - $this->assertEquals(2,$check->sqlUsers->count()); + $this->assertEquals(2, $check->sqlUsers->count()); // MorphToMany (pivot is not empty) $experience->sqlUsers()->sync([$user->id]); $check = Experience::query()->find($experience->_id); - $this->assertEquals(1,$check->sqlUsers->count()); + $this->assertEquals(1, $check->sqlUsers->count()); // Inverse MorphToMany (pivot is empty) $user->experiences()->sync([$experience->_id, $experience2->_id]); $check = SqlUser::query()->find($user->id); - $this->assertEquals(2,$check->experiences->count()); + $this->assertEquals(2, $check->experiences->count()); // Inverse MorphToMany (pivot is not empty) $user->experiences()->sync([$experience->_id]); $check = SqlUser::query()->find($user->id); - $this->assertEquals(1,$check->experiences->count()); + $this->assertEquals(1, $check->experiences->count()); } } diff --git a/tests/Models/SqlUser.php b/tests/Models/SqlUser.php index f3b8a5880..43cb4ead3 100644 --- a/tests/Models/SqlUser.php +++ b/tests/Models/SqlUser.php @@ -68,8 +68,9 @@ public static function executeSchema(): void $table->morphs('skilled'); }); } - if (!$schema->hasTable('experienceds')){ - $schema->create('experienceds',function (Blueprint $table){ + + if (! $schema->hasTable('experienceds')) { + $schema->create('experienceds', function (Blueprint $table) { $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete(); $table->morphs('experienced'); }); From 108ac9b9c8ae2d5f71006232e7a8ab7231fbfccd Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 29 Nov 2023 11:19:04 +0330 Subject: [PATCH 11/18] Update instance in attaching a model in MorphToMany; --- src/Relations/MorphToMany.php | 8 +++++++- tests/HybridRelationsTest.php | 8 ++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index ce4ccd03d..fd9bd196a 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -230,7 +230,13 @@ public function attach($id, array $attributes = [], $touch = true) ], true); // Attach the new ids to the parent model. - $this->parent->push($this->relatedPivotKey, (array) $id, true); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + $this->parent->push($this->relatedPivotKey, (array) $id, true); + }else{ + $instance = new $this->related(); + $instance->forceFill([$this->relatedKey => $id]); + $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + } } } else { if ($id instanceof Collection) { diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 00dd18652..89b5c079e 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -246,6 +246,14 @@ public function testHybridMorphToManySqlModelToMongoModel() $check = SqlUser::query()->find($user->id); $this->assertEquals(1, $check->skills->count()); + // Attach MorphToMany + $user->skills()->sync([]); + $check = SqlUser::query()->find($user->id); + $this->assertEquals(0, $check->skills->count()); + $user->skills()->attach($skill); + $check = SqlUser::query()->find($user->id); + $this->assertEquals(1, $check->skills->count()); + // Inverse MorphToMany (pivot is empty) $skill->sqlUsers()->sync([$user->id, $user2->id]); $check = Skill::query()->find($skill->_id); From f27556038bd5d5129699949c8ff1cf377fa02b8e Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 29 Nov 2023 11:39:51 +0330 Subject: [PATCH 12/18] Update instance in attaching a model in Inverse MorphToMany; --- src/Relations/MorphToMany.php | 20 +++++++++++++------- tests/HybridRelationsTest.php | 10 ++++++++++ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index fd9bd196a..a20048db2 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -211,15 +211,21 @@ public function attach($id, array $attributes = [], $touch = true) if ($this->getInverse()) { // Attach the new ids to the parent model. - $this->parent->push($this->table, [ - [ - $this->relatedPivotKey => $model->{$this->relatedKey}, - $this->morphType => $model->getMorphClass(), - ], - ], true); + if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { + $this->parent->push($this->table, [ + [ + $this->relatedPivotKey => $model->{$this->relatedKey}, + $this->morphType => $model->getMorphClass(), + ], + ], true); + }else{ + $instance = new $this->related(); + $instance->forceFill([$this->relatedKey => $id]); + $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)->unique($this->relatedKey)); + } // Attach the new parent id to the related model. - $model->push($this->foreignPivotKey, $this->parseIds($this->parent), true); + $model->push($this->foreignPivotKey, (array) $this->parent->{$this->parentKey}, true); } else { // Attach the new parent id to the related model. $model->push($this->table, [ diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index 89b5c079e..45f39df60 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -251,6 +251,7 @@ public function testHybridMorphToManySqlModelToMongoModel() $check = SqlUser::query()->find($user->id); $this->assertEquals(0, $check->skills->count()); $user->skills()->attach($skill); + $user->skills()->attach($skill); // ignore duplicates $check = SqlUser::query()->find($user->id); $this->assertEquals(1, $check->skills->count()); @@ -305,5 +306,14 @@ public function testHybridMorphToManyMongoModelToSqlModel() $user->experiences()->sync([$experience->_id]); $check = SqlUser::query()->find($user->id); $this->assertEquals(1, $check->experiences->count()); + + // Inverse MorphToMany (pivot is not empty) + $user->experiences()->sync([]); + $check = SqlUser::query()->find($user->id); + $this->assertEquals(0, $check->experiences->count()); + $user->experiences()->attach($experience); + $user->experiences()->attach($experience); // ignore duplicates + $check = SqlUser::query()->find($user->id); + $this->assertEquals(1, $check->experiences->count()); } } From cb5778e9f59c1047cf2fe451e7e60a9eb6556032 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 29 Nov 2023 11:47:55 +0330 Subject: [PATCH 13/18] Create addIdToParentRelationData method to prevent repeating code; --- src/Relations/MorphToMany.php | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index a20048db2..3ed33d4ab 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany as EloquentMorphToMany; use Illuminate\Support\Arr; +use MongoDB\BSON\ObjectId; use function array_diff; use function array_key_exists; use function array_keys; @@ -219,9 +220,7 @@ public function attach($id, array $attributes = [], $touch = true) ], ], true); }else{ - $instance = new $this->related(); - $instance->forceFill([$this->relatedKey => $id]); - $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)->unique($this->relatedKey)); + $this->addIdToParentRelationData($id); } // Attach the new parent id to the related model. @@ -239,9 +238,7 @@ public function attach($id, array $attributes = [], $touch = true) if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->push($this->relatedPivotKey, (array) $id, true); }else{ - $instance = new $this->related(); - $instance->forceFill([$this->relatedKey => $id]); - $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + $this->addIdToParentRelationData($id); } } } else { @@ -270,9 +267,7 @@ public function attach($id, array $attributes = [], $touch = true) } } else { foreach ($id as $item) { - $instance = new $this->related(); - $instance->forceFill([$this->relatedKey => $item]); - $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + $this->addIdToParentRelationData($item); } } } else { @@ -289,9 +284,7 @@ public function attach($id, array $attributes = [], $touch = true) $this->parent->push($this->relatedPivotKey, $id, true); } else { foreach ($id as $item) { - $instance = new $this->related(); - $instance->forceFill([$this->relatedKey => $item]); - $this->parent->setRelation($this->relationName, $this->parent->{$this->relationName}->push($instance)); + $this->addIdToParentRelationData($item); } } } @@ -456,4 +449,21 @@ public function extractIds(array $data, ?string $relatedPivotKey = null) return $carry; }, []); } + + + /** + * Add the given id to the relation's data of the current parent instance. + * It helps to keep up-to-date the sql model instances in hybrid relationships. + * + * @param ObjectId|string|int $id + * + * @return void + */ + private function addIdToParentRelationData($id) + { + $instance = new $this->related(); + $instance->forceFill([$this->relatedKey => $id]); + $relationData = $this->parent->{$this->relationName}->push($instance)->unique($this->relatedKey); + $this->parent->setRelation($this->relationName, $relationData); + } } From 8ed310451edc71ecb3f77ba449dfedfb952adcc2 Mon Sep 17 00:00:00 2001 From: hans-thomas Date: Wed, 29 Nov 2023 08:18:32 +0000 Subject: [PATCH 14/18] apply phpcbf formatting --- src/Relations/MorphToMany.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index 3ed33d4ab..14ddeafc1 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -9,8 +9,8 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphToMany as EloquentMorphToMany; use Illuminate\Support\Arr; - use MongoDB\BSON\ObjectId; + use function array_diff; use function array_key_exists; use function array_keys; @@ -219,7 +219,7 @@ public function attach($id, array $attributes = [], $touch = true) $this->morphType => $model->getMorphClass(), ], ], true); - }else{ + } else { $this->addIdToParentRelationData($id); } @@ -237,7 +237,7 @@ public function attach($id, array $attributes = [], $touch = true) // Attach the new ids to the parent model. if ($this->parent instanceof \MongoDB\Laravel\Eloquent\Model) { $this->parent->push($this->relatedPivotKey, (array) $id, true); - }else{ + } else { $this->addIdToParentRelationData($id); } } @@ -450,7 +450,6 @@ public function extractIds(array $data, ?string $relatedPivotKey = null) }, []); } - /** * Add the given id to the relation's data of the current parent instance. * It helps to keep up-to-date the sql model instances in hybrid relationships. From b5137a0c2a73beda5030ec7923bb3e3c001da144 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 29 Nov 2023 11:57:52 +0330 Subject: [PATCH 15/18] Update phpstan-baseline.neon --- phpstan-baseline.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 71a44a395..94ba4d7a0 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7,7 +7,7 @@ parameters: - message: "#^Method Illuminate\\\\Database\\\\Eloquent\\\\Model\\:\\:push\\(\\) invoked with 3 parameters, 0 required\\.$#" - count: 6 + count: 2 path: src/Relations/MorphToMany.php - From 94688d491714ff6ae559eb4464491222e01b6fca Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 29 Nov 2023 15:24:39 +0330 Subject: [PATCH 16/18] WIP --- src/Relations/MorphToMany.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index 14ddeafc1..46ae1ccb7 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -155,8 +155,9 @@ public function sync($ids, $detaching = true) true => $this->parent->{$this->relatedPivotKey} ?: [], false => $this->parent->{$this->relationName} ?: [], }; + if ($current instanceof Collection) { - $current = collect($this->parseIds($current))->flatten()->toArray(); + $current = $this->parseIds($current); } } From e561201e9417e2e3a547f429d08ab0a593bced75 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Wed, 29 Nov 2023 15:37:53 +0330 Subject: [PATCH 17/18] Fix CS; --- src/Relations/MorphToMany.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Relations/MorphToMany.php b/src/Relations/MorphToMany.php index 46ae1ccb7..163e7e67f 100644 --- a/src/Relations/MorphToMany.php +++ b/src/Relations/MorphToMany.php @@ -155,7 +155,7 @@ public function sync($ids, $detaching = true) true => $this->parent->{$this->relatedPivotKey} ?: [], false => $this->parent->{$this->relationName} ?: [], }; - + if ($current instanceof Collection) { $current = $this->parseIds($current); } From 8440c57244c1bc363abf1ba7755dccc13649e8d1 Mon Sep 17 00:00:00 2001 From: Mohammad Mortazavi Date: Mon, 11 Dec 2023 15:24:29 +0330 Subject: [PATCH 18/18] Fix tests; --- tests/HybridRelationsTest.php | 32 +++++++++++++++++--------------- tests/Models/Label.php | 9 ++++++--- tests/Models/Skill.php | 6 ------ tests/Models/SqlUser.php | 15 ++++++++++----- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/tests/HybridRelationsTest.php b/tests/HybridRelationsTest.php index c7f782e97..5253784c9 100644 --- a/tests/HybridRelationsTest.php +++ b/tests/HybridRelationsTest.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\DB; use MongoDB\Laravel\Tests\Models\Book; use MongoDB\Laravel\Tests\Models\Experience; +use MongoDB\Laravel\Tests\Models\Label; use MongoDB\Laravel\Tests\Models\Role; use MongoDB\Laravel\Tests\Models\Skill; use MongoDB\Laravel\Tests\Models\SqlBook; @@ -40,6 +41,7 @@ public function tearDown(): void SqlRole::truncate(); Skill::truncate(); Experience::truncate(); + Label::truncate(); } public function testSqlRelations() @@ -282,36 +284,36 @@ public function testHybridMorphToManySqlModelToMongoModel() $user2 = SqlUser::query()->find($user2->id); // Create Mongodb skills - $skill = Skill::query()->create(['name' => 'Laravel']); - $skill2 = Skill::query()->create(['name' => 'MongoDB']); + $label = Label::query()->create(['name' => 'Laravel']); + $label2 = Label::query()->create(['name' => 'MongoDB']); // MorphToMany (pivot is empty) - $user->skills()->sync([$skill->_id, $skill2->_id]); + $user->labels()->sync([$label->_id, $label2->_id]); $check = SqlUser::query()->find($user->id); - $this->assertEquals(2, $check->skills->count()); + $this->assertEquals(2, $check->labels->count()); // MorphToMany (pivot is not empty) - $user->skills()->sync($skill); + $user->labels()->sync($label); $check = SqlUser::query()->find($user->id); - $this->assertEquals(1, $check->skills->count()); + $this->assertEquals(1, $check->labels->count()); // Attach MorphToMany - $user->skills()->sync([]); + $user->labels()->sync([]); $check = SqlUser::query()->find($user->id); - $this->assertEquals(0, $check->skills->count()); - $user->skills()->attach($skill); - $user->skills()->attach($skill); // ignore duplicates + $this->assertEquals(0, $check->labels->count()); + $user->labels()->attach($label); + $user->labels()->attach($label); // ignore duplicates $check = SqlUser::query()->find($user->id); - $this->assertEquals(1, $check->skills->count()); + $this->assertEquals(1, $check->labels->count()); // Inverse MorphToMany (pivot is empty) - $skill->sqlUsers()->sync([$user->id, $user2->id]); - $check = Skill::query()->find($skill->_id); + $label->sqlUsers()->sync([$user->id, $user2->id]); + $check = Label::query()->find($label->_id); $this->assertEquals(2, $check->sqlUsers->count()); // Inverse MorphToMany (pivot is empty) - $skill->sqlUsers()->sync([$user->id, $user2->id]); - $check = Skill::query()->find($skill->_id); + $label->sqlUsers()->sync([$user->id, $user2->id]); + $check = Label::query()->find($label->_id); $this->assertEquals(2, $check->sqlUsers->count()); } diff --git a/tests/Models/Label.php b/tests/Models/Label.php index 179503ce1..5bd1cf4da 100644 --- a/tests/Models/Label.php +++ b/tests/Models/Label.php @@ -4,6 +4,7 @@ namespace MongoDB\Laravel\Tests\Models; +use Illuminate\Database\Eloquent\Relations\MorphToMany; use MongoDB\Laravel\Eloquent\Model as Eloquent; /** @@ -23,14 +24,16 @@ class Label extends Eloquent 'chapters', ]; - /** - * Get all the posts that are assigned this tag. - */ public function users() { return $this->morphedByMany(User::class, 'labelled'); } + public function sqlUsers(): MorphToMany + { + return $this->morphedByMany(SqlUser::class, 'labeled'); + } + public function clients() { return $this->morphedByMany(Client::class, 'labelled'); diff --git a/tests/Models/Skill.php b/tests/Models/Skill.php index dcb629339..3b9a434ee 100644 --- a/tests/Models/Skill.php +++ b/tests/Models/Skill.php @@ -5,7 +5,6 @@ namespace MongoDB\Laravel\Tests\Models; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Database\Eloquent\Relations\MorphToMany; use MongoDB\Laravel\Eloquent\Model as Eloquent; class Skill extends Eloquent @@ -18,9 +17,4 @@ public function sqlUsers(): BelongsToMany { return $this->belongsToMany(SqlUser::class); } - - public function sqlUsers(): MorphToMany - { - return $this->morphedByMany(SqlUser::class, 'skilled'); - } } diff --git a/tests/Models/SqlUser.php b/tests/Models/SqlUser.php index 911b2d46f..4cb77faa5 100644 --- a/tests/Models/SqlUser.php +++ b/tests/Models/SqlUser.php @@ -44,9 +44,9 @@ public function sqlBooks(): HasMany return $this->hasMany(SqlBook::class); } - public function skills(): MorphToMany + public function labels(): MorphToMany { - return $this->morphToMany(Skill::class, 'skilled'); + return $this->morphToMany(Label::class, 'labeled'); } public function experiences(): MorphToMany @@ -68,6 +68,8 @@ public static function executeSchema(): void $table->string('name'); $table->timestamps(); }); + + // Pivot table for BelongsToMany relationship with Skill if (! $schema->hasTable('skill_sql_user')) { $schema->create('skill_sql_user', function (Blueprint $table) { $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete(); @@ -75,13 +77,16 @@ public static function executeSchema(): void $table->primary([(new self())->getForeignKey(), (new Skill())->getForeignKey()]); }); } - if (! $schema->hasTable('skilleds')) { - $schema->create('skilleds', function (Blueprint $table) { + + // Pivot table for MorphToMany relationship with Label + if (! $schema->hasTable('labeleds')) { + $schema->create('labeleds', function (Blueprint $table) { $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete(); - $table->morphs('skilled'); + $table->morphs('labeled'); }); } + // Pivot table for MorphedByMany relationship with Experience if (! $schema->hasTable('experienceds')) { $schema->create('experienceds', function (Blueprint $table) { $table->foreignIdFor(self::class)->constrained()->cascadeOnDelete();