framework: Pivot::original contains incorrect data

  • Laravel Version: 5.8.19
  • PHP Version: 7.1.13
  • Database Driver & Version: MySQL 5.5.5-10.3.8-MariaDB

Description:

After creating a Model, the original array is empty and the attributes array contains all the attributes used to create the Model and optionally the auto-incrementing id. Same is true when a Pivot is created via FooPivot::create().

However after creating a Pivot using the $model->relationship()->attach($id, $attributes) method, the original array contains all of the foreign keys and the pivot attributes passed to the attach() call.

Steps To Reproduce:

Run:

php artisan make:model Invoice -m 
php artisan make:model Product -m 
php artisan make:model InvoiceProduct -m -p

Fill in the migrations: create_invoices_table:

Schema::create('invoices', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('number');
    $table->timestamps();
});

create_invoice_product_table:

Schema::create('invoice_product', function (Blueprint $table) {
    $table->unsignedInteger('invoice_id');
    $table->unsignedInteger('product_id');
    $table->unsignedInteger('count');
});

You can leave the create_products_table migration unchanged.

Update the models: App\Invoice:

class Invoice extends Model
{
    protected $guarded = [];

    public static function boot()
    {
        parent::boot();

        static::created(function (Model $model) {
            dump([
                'attributes' => $model->getAttributes(),
                'original'   => $model->getOriginal(),
                'dirty'      => $model->getDirty(),
            ]);
        });
    }

    public function products()
    {
        return $this->belongsToMany(Product::class)
                    ->using(InvoiceProduct::class)
                    ->withPivot('count');
    }
}

App\InvoiceProduct:

class InvoiceProduct extends Pivot
{
    public static function boot()
    {
        parent::boot();

        static::created(function (Model $model) {
            dump([
                'attributes' => $model->getAttributes(),
                'original'   => $model->getOriginal(),
                'dirty'      => $model->getDirty(),
            ]);
        });
    }
}

You can leave the App\Product model unchanged.

Run:

php artisan migrate

In the Tinker run:

$invoice = \App\Invoice::create(['number' => '123']);

You should see the correct attributes, original and dirty arrays:

array:3 [
  "attributes" => array:4 [
    "number" => "123"
    "updated_at" => "2019-06-01 10:08:57"
    "created_at" => "2019-06-01 10:08:57"
    "id" => 1
  ]
  "original" => []
  "dirty" => array:4 [
    "number" => "123"
    "updated_at" => "2019-06-01 10:08:57"
    "created_at" => "2019-06-01 10:08:57"
    "id" => 1
  ]
]

Then, again in the Tinker, run:

$product = \App\Product::create();
$invoice->products()->attach($product, ['count' => 2]);

You should see the following output:

array:3 [
  "attributes" => array:3 [
    "product_id" => 1
    "invoice_id" => 1
    "count" => 2
  ]
  "original" => array:3 [
    "product_id" => 1
    "invoice_id" => 1
    "count" => 2
  ]
  "dirty" => []
]

Clearly the pivot has just been created, therefore the original array should be empty and the dirty array should contain at least the count field.

One side note: If you add auto-incrementing id to the pivot table and enable it with

public $incrementing = true;

you’re gonna see the id field in the dirty array but not in the original array.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 16 (16 by maintainers)

Most upvoted comments

Fixed in next 6.x / 7.x patch release.