updateOrCreate with Pivot table fails to return id on creation
Laravel Version
11.44.2
PHP Version
8.3.0
Database Driver & Version
Mysql 8.2.0 on windows
RELATED
This is probably related to #44882
Description
In a pivot model, the updateOrCreate method fails to return the ID of the newly created model. It works correctly for update, but not create.
Steps To Reproduce
First, I try to create a new model using updateOrCreate. The model is created, but there is no id attribute
$cdg=CommonDiagnosisGroupIcd10::updateOrCreate(['common_diagnosis_group_id' => 4,'icd10_id' => 'A331'], ['name' => 'ur']);
= App\CommonDiagnosisGroupIcd10 {#7424
common_diagnosis_group_id: 4,
icd10_id: "A331",
name: "ur",
}
When I try to get a fresh() version from the DB, I get this:
> $cdg->fresh()
DEPRECATED str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php on line 883.
DEPRECATED str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php on line 883.
DEPRECATED stripos(): Passing null to parameter #1 ($haystack) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 87.
DEPRECATED str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 178.
DEPRECATED explode(): Passing null to parameter #2 ($string) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 98.
DEPRECATED stripos(): Passing null to parameter #1 ($haystack) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 87.
DEPRECATED str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 178.
DEPRECATED explode(): Passing null to parameter #2 ($string) of type string is deprecated in vendor\laravel\framework\src\Illuminate\Database\Grammar.php on line 98.
Illuminate\Database\QueryException SQLSTATE[42S22]: Column not found: 1054 Unknown column '' in 'where clause' (Connection: mysql, SQL: select * from `common_diagnosis_group_icd10` where `` = 4 and `` = 4 limit 1).
Interestingly, if I try to update the model, it works.
> $cdg=CommonDiagnosisGroupIcd10::updateOrCreate(['common_diagnosis_group_id' => 4,'icd10_id' => 'A331'], ['name' => 'ur
']);
[!] Aliasing 'CommonDiagnosisGroupIcd10' to 'App\CommonDiagnosisGroupIcd10' for this Tinker session.
= App\CommonDiagnosisGroupIcd10 {#7260
id: 60,
common_diagnosis_group_id: 4,
icd10_id: "A331",
name: "ur",
}
Model definition
class CommonDiagnosisGroupIcd10 extends Pivot
{
public $table = 'common_diagnosis_group_icd10';
public $timestamps = false;
protected $guarded = ['id'];
// .....
}
DB Schema
Schema::create('common_diagnosis_group_icd10', function (Blueprint $table) {
$table->id();
$table->foreignId('common_diagnosis_group_id')->constrained('common_diagnosis_groups')->onDelete('cascade');
$table->string('icd10_id', 7)->constrained('icd10s', 'id')->onDelete('cascade');
$table->string('name', 100);
$table->unique(['common_diagnosis_group_id', 'icd10_id'], 'common_diagnosis_group_icd10_unique');
});
Can you please comment this line
protected $guarded = ['id'];
and retry?
Commenting out $guarded didn't work.
public $incrementing = false; is on the parent Pivot.
As you need incrementing true on the id, maybe you should put it to true.
if ($this->getIncrementing()) {
$this->insertAndSetId($query, $attributes);
}
// If the table isn't incrementing we'll simply insert these attributes as they
// are. These attribute arrays must contain an "id" column previously placed
// there by the developer as the manually determined key for these models.
else {
if (empty($attributes)) {
return true;
}
$query->insert($attributes);
}
Yes. That worked.
I think the rationale is that pivot tables don't normally have an id column, since rows should be unique based on the two parent tables. The only reason this is confusing is that if you use the artisan command to make a new pivot, the migration includes an id column.
> php artisan make:model horse -m --pivot
generates the following
migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('horse', function (Blueprint $table) {
$table->id();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('horse');
}
};
model
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class horse extends Pivot
{
//
}
The only thing I'd suggest is that when the --pivot flag is supplied to make:model, either we omit $table->id(); or we place public $incrementing = true; in the generated text. An even better fix would be to supply model arguments to the make:model command to handle all of that.
Thanks again!!
I tested this, but it returns id for me! Has anyone fixed this issue?
If it has been fixed, please close this issue.
@crynobone