Repository: laravel/framework (php)

Issue:
BelongsToMany#updateOrCreate is not merging arguments before create
<!-- DO NOT THROW THIS AWAY -->
<!-- Fill out the FULL versions with patch versions -->

- Laravel Version: 8.20.1
- PHP Version: 7.4.8
- Database Driver & Version: MariaDB 10.5.8

### Description:
For `Illuminate\Database\Eloquent\Relations\BelongsToMany` relationships, the `updateOrCreate` method is not merging the $attributes and $values arrays. 

This is different from the behaviour of the `updateOrCreate` methods on `Builder`,   `HasOneOrMany` and `HasManyThrough` classes and from the documented behaviour "If no such flight exists, a new flight will be created which has the attributes resulting from merging the first argument array with the second argument array" [eloquent#upserts](https://laravel.com/docs/8.x/eloquent#upserts). 

**Illuminate\Database\Eloquent\Relations\BelongsToMany**
```
    public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
    {
        if (is_null($instance = $this->where($attributes)->first())) {
            return $this->create($values, $joining, $touch);
        }

        $instance->fill($values);

        $instance->save(['touch' => false]);

        return $instance;
    }
```
**Proposed solution**
This solution is based on master (9.x) branch where the fix for [#34083](https://github.com/laravel/framework/issues/34083) is taken into account.
```
    public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
    {
        if (is_null($instance = $this->related->where($attributes)->first())) {
            $instance = $this->create($attributes, $joining, $touch);
        }

        $instance->fill($values);

        $instance->save(['touch' => false]);

        return $instance;
    }
```
### Steps To Reproduce:
```
Schema::create('roles', function (Blueprint $table) {
    $table->increments('id');
    $table->unsignedBigInteger('created_by_id');
    $table->string('name'); // <-- required
    $table->timestamps();
});
```
```
$user = User::factory()->create();
Role::create(['name' => 'existing.role', 'description' => 'foo']);
$user->roles()->updateOrCreate(['name' => 'existing.role'], ['description' => 'bar']);

parent::assertEquals(1, Role::count()); // assertion fails (or is never reached); count equals 2
```
```
$user = User::factory()->create();

// throws: Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1364 Field 'name' doesn't have a default value
$user->roles()->updateOrCreate(['name' => 'existing.role'], ['description' => 'bar']); 

parent::assertEquals(1, Role::count()); // assertion fails (or is never reached); count equals 2
```

When confirmed I'll submit the pull request. 

Pull request description:
[9.x] Fix BelongsToMany#updateOrCreate behaviour merge arguments for new models
This fixes an issue with that the behavior of the `updateOrCreate` method on BelongsToMany relationships is not merging the `$attributes` and `$values` arrays.

This is different from the behaviour of the `updateOrCreate` methods on `Builder`,  `HasOneOrMany` and `HasManyThrough` classes and from the documented behavior "If no such flight exists, a new flight will be created which has the attributes resulting from merging the first argument array with the second argument array" [eloquent#upserts](https://laravel.com/docs/8.x/eloquent#upserts). 


Fixes #35798
<!--
Please only send a pull request to branches which are currently supported: https://laravel.com/docs/releases#support-policy 

If you are unsure which branch your pull request should be sent to, please read: https://laravel.com/docs/contributions#which-branch

Pull requests without a descriptive title, thorough description, or tests will be closed.

In addition, please describe the benefit to end users; the reasons it does not break any existing features; how it makes building web applications easier, etc.
-->


Patch:
diff --git a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
index ab13ef538f..cecb13e915 100755
--- a/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
+++ b/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
@@ -628,7 +628,7 @@ public function firstOrCreate(array $attributes, array $joining = [], $touch = t
     public function updateOrCreate(array $attributes, array $values = [], array $joining = [], $touch = true)
     {
         if (is_null($instance = $this->related->where($attributes)->first())) {
-            return $this->create($values, $joining, $touch);
+            return $this->create(array_merge($attributes, $values), $joining, $touch);
         }
 
         $instance->fill($values);


Test patch:
diff --git a/tests/Integration/Database/EloquentBelongsToManyTest.php b/tests/Integration/Database/EloquentBelongsToManyTest.php
index b66cd3d3f3..2599fdd858 100644
--- a/tests/Integration/Database/EloquentBelongsToManyTest.php
+++ b/tests/Integration/Database/EloquentBelongsToManyTest.php
@@ -39,6 +39,7 @@ protected function setUp(): void
         Schema::create('tags', function (Blueprint $table) {
             $table->increments('id');
             $table->string('name');
+            $table->string('type')->nullable();
             $table->timestamps();
         });
 
@@ -453,6 +454,18 @@ public function testUpdateOrCreateMethod()
         $this->assertNotNull($post->tags()->whereName('dives')->first());
     }
 
+    public function testUpdateOrCreateMethodCreate()
+    {
+        $post = Post::create(['title' => Str::random()]);
+
+        $post->tags()->updateOrCreate(['name' => 'wavez'], ['type' => 'featured']);
+
+        $tag = $post->tags()->whereType('featured')->first();
+
+        $this->assertNotNull($tag);
+        $this->assertSame('wavez', $tag->name);
+    }
+
     public function testSyncMethod()
     {
         $post = Post::create(['title' => Str::random()]);
@@ -647,7 +660,7 @@ public function testCanTouchRelatedModels()
 
     public function testWherePivotOnString()
     {
-        $tag = Tag::create(['name' => Str::random()]);
+        $tag = Tag::create(['name' => Str::random()])->fresh();
         $post = Post::create(['title' => Str::random()]);
 
         DB::table('posts_tags')->insert([
@@ -663,7 +676,7 @@ public function testWherePivotOnString()
 
     public function testFirstWhere()
     {
-        $tag = Tag::create(['name' => 'foo']);
+        $tag = Tag::create(['name' => 'foo'])->fresh();
         $post = Post::create(['title' => Str::random()]);
 
         DB::table('posts_tags')->insert([
@@ -679,7 +692,7 @@ public function testFirstWhere()
 
     public function testWherePivotOnBoolean()
     {
-        $tag = Tag::create(['name' => Str::random()]);
+        $tag = Tag::create(['name' => Str::random()])->fresh();
         $post = Post::create(['title' => Str::random()]);
 
         DB::table('posts_tags')->insert([
@@ -695,7 +708,7 @@ public function testWherePivotOnBoolean()
 
     public function testWherePivotInMethod()
     {
-        $tag = Tag::create(['name' => Str::random()]);
+        $tag = Tag::create(['name' => Str::random()])->fresh();
         $post = Post::create(['title' => Str::random()]);
 
         DB::table('posts_tags')->insert([
@@ -730,7 +743,7 @@ public function testOrWherePivotInMethod()
     public function testWherePivotNotInMethod()
     {
         $tag1 = Tag::create(['name' => Str::random()]);
-        $tag2 = Tag::create(['name' => Str::random()]);
+        $tag2 = Tag::create(['name' => Str::random()])->fresh();
         $post = Post::create(['title' => Str::random()]);
 
         DB::table('posts_tags')->insert([
@@ -768,7 +781,7 @@ public function testOrWherePivotNotInMethod()
     public function testWherePivotNullMethod()
     {
         $tag1 = Tag::create(['name' => Str::random()]);
-        $tag2 = Tag::create(['name' => Str::random()]);
+        $tag2 = Tag::create(['name' => Str::random()])->fresh();
         $post = Post::create(['title' => Str::random()]);
 
         DB::table('posts_tags')->insert([
@@ -784,7 +797,7 @@ public function testWherePivotNullMethod()
 
     public function testWherePivotNotNullMethod()
     {
-        $tag1 = Tag::create(['name' => Str::random()]);
+        $tag1 = Tag::create(['name' => Str::random()])->fresh();
         $tag2 = Tag::create(['name' => Str::random()]);
         $post = Post::create(['title' => Str::random()]);
 
@@ -909,8 +922,8 @@ public function testPivotDoesntHavePrimaryKey()
     public function testOrderByPivotMethod()
     {
         $tag1 = Tag::create(['name' => Str::random()]);
-        $tag2 = Tag::create(['name' => Str::random()]);
-        $tag3 = Tag::create(['name' => Str::random()]);
+        $tag2 = Tag::create(['name' => Str::random()])->fresh();
+        $tag3 = Tag::create(['name' => Str::random()])->fresh();
         $tag4 = Tag::create(['name' => Str::random()]);
         $post = Post::create(['title' => Str::random()]);
 
@@ -1030,7 +1043,7 @@ class Tag extends Model
 {
     public $table = 'tags';
     public $timestamps = true;
-    protected $fillable = ['name'];
+    protected $fillable = ['name', 'type'];
 
     public function posts()
     {