From 1411abed0112e5f7c7a1489dd612050bbf805287 Mon Sep 17 00:00:00 2001
From: Peyman Aslani <pia.developer@gmail.com>
Date: Wed, 5 Mar 2025 14:09:45 +0330
Subject: [PATCH 1/4] Fix BelongsToMany relation to support objectId and array
 values

---
 src/Relations/BelongsToMany.php | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/Relations/BelongsToMany.php b/src/Relations/BelongsToMany.php
index a150fccf7..f98680c5c 100644
--- a/src/Relations/BelongsToMany.php
+++ b/src/Relations/BelongsToMany.php
@@ -208,7 +208,12 @@ public function attach($id, array $attributes = [], $touch = true)
 
         // Attach the new ids to the parent model.
         if (\MongoDB\Laravel\Eloquent\Model::isDocumentModel($this->parent)) {
-            $this->parent->push($this->relatedPivotKey, (array) $id, true);
+            if ($id instanceof \MongoDB\BSON\ObjectId) {
+                $id = [$id];
+            } else {
+                $id = (array) $id;
+            }
+            $this->parent->push($this->relatedPivotKey, $id, true);
         } else {
             $instance = new $this->related();
             $instance->forceFill([$this->relatedKey => $id]);
@@ -275,7 +280,8 @@ protected function buildDictionary(Collection $results)
 
         foreach ($results as $result) {
             foreach ($result->$foreign as $item) {
-                $dictionary[$item][] = $result;
+                $key = is_object($item) ? (string) $item : $item;
+                $dictionary[$key][] = $result;
             }
         }
 

From 176d8541c609af1c0b59ace22ddd64d376e56d18 Mon Sep 17 00:00:00 2001
From: Peyman Aslani <pia.developer@gmail.com>
Date: Thu, 6 Mar 2025 13:34:57 +0330
Subject: [PATCH 2/4] add test for BelongsToMany relation with array foreign
 keys

---
 tests/Models/Role.php   |  6 ++++++
 tests/Models/User.php   |  6 ++++++
 tests/RelationsTest.php | 16 ++++++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/tests/Models/Role.php b/tests/Models/Role.php
index 02551971d..32106b419 100644
--- a/tests/Models/Role.php
+++ b/tests/Models/Role.php
@@ -7,6 +7,7 @@
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsTo;
 use MongoDB\Laravel\Eloquent\DocumentModel;
+use MongoDB\Laravel\Relations\BelongsToMany;
 
 class Role extends Model
 {
@@ -22,6 +23,11 @@ public function user(): BelongsTo
         return $this->belongsTo(User::class);
     }
 
+    public function users(): BelongsToMany
+    {
+        return $this->belongsToMany(User::class, null, 'role_id', 'user_id');
+    }
+
     public function sqlUser(): BelongsTo
     {
         return $this->belongsTo(SqlUser::class);
diff --git a/tests/Models/User.php b/tests/Models/User.php
index 5b8ac983a..d256b22bc 100644
--- a/tests/Models/User.php
+++ b/tests/Models/User.php
@@ -17,6 +17,7 @@
 use MongoDB\Laravel\Eloquent\Builder;
 use MongoDB\Laravel\Eloquent\DocumentModel;
 use MongoDB\Laravel\Eloquent\MassPrunable;
+use MongoDB\Laravel\Relations\BelongsToMany;
 
 /**
  * @property string $id
@@ -87,6 +88,11 @@ public function role()
         return $this->hasOne(Role::class);
     }
 
+    public function roles(): BelongsToMany
+    {
+        return $this->belongsToMany(Role::class, null, 'user_id', 'role_id');
+    }
+
     public function sqlRole()
     {
         return $this->hasOne(SqlRole::class);
diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php
index 643e00e6a..8d0b34a2a 100644
--- a/tests/RelationsTest.php
+++ b/tests/RelationsTest.php
@@ -338,6 +338,22 @@ public function testBelongsToManyAttachArray(): void
         $this->assertCount(2, $user->clients);
     }
 
+    public function testBelongsToManyRelationSupportsArrayForeignKeys(): void
+    {
+        $user = User::create(['name' => 'John Doe']);
+        $role1 = Role::create(['name' => 'Admin']);
+        $role2 = Role::create(['name' => 'Editor']);
+
+        $user->roles()->attach([$role1->id, $role2->id]);
+
+        $retrievedUser = User::with('roles')->find($user->id);
+        $this->assertCount(2, $retrievedUser->roles);
+        $this->assertEqualsCanonicalizing(
+            [$role1->id, $role2->id],
+            $retrievedUser->roles->pluck('id')->toArray()
+        );
+    }
+
     public function testBelongsToManyAttachEloquentCollection(): void
     {
         User::create(['name' => 'John Doe']);

From 0518aaa9c41818abb65f80acf3cd65ef3210e2d3 Mon Sep 17 00:00:00 2001
From: Peyman Aslani <pia.developer@gmail.com>
Date: Thu, 6 Mar 2025 13:51:20 +0330
Subject: [PATCH 3/4] Updated documentation for array support in BelongsToMany
 relationships

---
 docs/eloquent-models/relationships.txt | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/docs/eloquent-models/relationships.txt b/docs/eloquent-models/relationships.txt
index a4a2c87a3..cbc3bca68 100644
--- a/docs/eloquent-models/relationships.txt
+++ b/docs/eloquent-models/relationships.txt
@@ -255,6 +255,26 @@ in the Laravel documentation.
 The following section shows an example of how to create a many to many
 relationship between model classes.
 
+.. note::
+
+   In previous versions, the `foreignPivotKey` in a `BelongsToMany` relationship
+   was expected to be a single `ObjectId` or `string`. However, in some MongoDB
+   schemas, it is common to store multiple related IDs as an array. As of this update,
+   `BelongsToMany` now supports array values for the `foreignPivotKey`.
+
+   Example:
+
+   .. code-block:: php
+
+       class User extends Model {
+           public function roles() {
+               return $this->belongsToMany(Role::class, null, 'role_ids', '_id');
+           }
+       }
+
+   Here, `role_ids` can be an array of `ObjectId`s, and the relationship will work correctly.
+
+
 Many to Many Example
 ~~~~~~~~~~~~~~~~~~~~
 

From fb2d848bbff8aef09dbc08535bcba2d181722c9c Mon Sep 17 00:00:00 2001
From: pilo <pilo@pilo.com>
Date: Thu, 6 Mar 2025 19:08:55 +0330
Subject: [PATCH 4/4] run cs:fix for modified files

---
 src/Relations/BelongsToMany.php | 5 ++++-
 tests/RelationsTest.php         | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/Relations/BelongsToMany.php b/src/Relations/BelongsToMany.php
index f98680c5c..e2036919a 100644
--- a/src/Relations/BelongsToMany.php
+++ b/src/Relations/BelongsToMany.php
@@ -9,6 +9,7 @@
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\Relations\BelongsToMany as EloquentBelongsToMany;
 use Illuminate\Support\Arr;
+use MongoDB\BSON\ObjectId;
 use MongoDB\Laravel\Eloquent\Model as DocumentModel;
 
 use function array_diff;
@@ -20,6 +21,7 @@
 use function count;
 use function in_array;
 use function is_numeric;
+use function is_object;
 
 /**
  * @template TRelatedModel of Model
@@ -208,11 +210,12 @@ public function attach($id, array $attributes = [], $touch = true)
 
         // Attach the new ids to the parent model.
         if (\MongoDB\Laravel\Eloquent\Model::isDocumentModel($this->parent)) {
-            if ($id instanceof \MongoDB\BSON\ObjectId) {
+            if ($id instanceof ObjectId) {
                 $id = [$id];
             } else {
                 $id = (array) $id;
             }
+
             $this->parent->push($this->relatedPivotKey, $id, true);
         } else {
             $instance = new $this->related();
diff --git a/tests/RelationsTest.php b/tests/RelationsTest.php
index 8d0b34a2a..f6d2375f2 100644
--- a/tests/RelationsTest.php
+++ b/tests/RelationsTest.php
@@ -350,7 +350,7 @@ public function testBelongsToManyRelationSupportsArrayForeignKeys(): void
         $this->assertCount(2, $retrievedUser->roles);
         $this->assertEqualsCanonicalizing(
             [$role1->id, $role2->id],
-            $retrievedUser->roles->pluck('id')->toArray()
+            $retrievedUser->roles->pluck('id')->toArray(),
         );
     }