framework icon indicating copy to clipboard operation
framework copied to clipboard

updateOrCreate with Pivot table fails to return id on creation

Open mankowitz opened this issue 3 months ago • 5 comments

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');
    });

mankowitz avatar Aug 29 '25 17:08 mankowitz

Can you please comment this line protected $guarded = ['id']; and retry?

macropay-solutions avatar Aug 29 '25 17:08 macropay-solutions

Commenting out $guarded didn't work.

mankowitz avatar Aug 29 '25 21:08 mankowitz

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);
        }

macropay-solutions avatar Aug 30 '25 05:08 macropay-solutions

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!!

mankowitz avatar Aug 30 '25 16:08 mankowitz

I tested this, but it returns id for me! Has anyone fixed this issue? If it has been fixed, please close this issue. @crynobone

mohammadMghi avatar Oct 02 '25 22:10 mohammadMghi