Closed
Description
- 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.
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 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.
Metadata
Metadata
Assignees
Labels
No labels