phplaraveleloquentpolymorphismlaravel-10

Automatically set timestamps on polymorphic relation table


I have a ProductLandedCost model with a morphToMany relationship to various other models: Warehouse, for example:

class Warehouse extends Model
{
    // ...

    public function productLandedCosts(): MorphToMany
    {
        return $this->morphToMany(
            ProductLandedCost::class,
            'product_landed_costable'
        );
    }
}

The polymorphic relationship is mediated by the product_landed_costables table. Within this table, I wish to record some metadata about each relationship, so there are a few more columns than a typical polymorphic table, including timestamps (updated_at and created_at). The table is defined by this migration:

public function up(): void
    {
        Schema::create('product_landed_costables', function (Blueprint $table) {
            $table->id();
            $table->timestamps();
            $table->unsignedBigInteger("product_landed_cost_id");
            $table->string("product_landed_costable_type", 255);
            $table->unsignedBigInteger("product_landed_costable_id");
            $table->foreign('product_landed_cost_id')
                ->references('id')
                ->on('product_landed_costs');
            $table->string("source", 255);
            $table->string("action", 255);
        });
    }

So, when I attach a ProductLandedCost to a Warehouse, I do something like this:

$warehouse->productLandedCosts()->save($product_landed_cost, [
  "action" => "action",
  "source" => "source",
]);

This correctly adds an entry in my product_landed_costables table. However, it does not populate the timestamp columns (created_at and updated_at)--they are set to null. The same is true if I use attach() in place of save().

Is there a way to instruct Eloquent to automatically set those timestamps in this situation?

This question and this question are similar to mine, but they both seek to put timestamps on the table of the related model, whereas I would like to put it on the polymorphic table itself.

I realize I can add the timestamps manually (as below), but since Eloquent adds them automatically in most other situations, I'm wondering if I'm missing something here.

$now = Carbon::now();
$warehouse->productLandedCosts()->save(
  $product_landed_cost,
  [
    "action" => "action",
    "source" => "source"
    "created_at" => $now,
    "updated_at" => $now
  ]
);

Solution

  • Add ->withTimestamps() will solve this

    class Warehouse extends Model
    {
        public function productLandedCosts(): \Illuminate\Database\Eloquent\Relations\MorphToMany
        {
            return $this
                ->morphToMany(ProductLandedCost::class, 'product_landed_costable')
                ->withPivot(['source', 'action'])
                ->withTimestamps();
        }
    }
    

    in your migration already has created_at and updated_at. So migration is fine.


    Now when you save , Laravel should populate created_at and updated_at on product_landed_costables.

    $warehouse->productLandedCosts()->attach($product_landed_cost->id, [
        'source' => 'source',
        'action' => 'action',
    ]);
    

    Reference: Retrieving Intermediate Table Columns