Thomas.Yu
Thomas.Yu

Reputation: 185

Laravel 8 - can not set morphOne id when using Polymorphic Relationships

I use Polymorphic Relationships of Laravel 8 to declare Models like following:

Item:

class Item extends Model
{
    protected $table = 'items';
    
    public function costs()
    {
        return $this->belongsToMany(Receive::class, 'cost_item', 'cost_id', 'item_id')
            ->withPivot([
                'id',
                'cost_id',
                'item_id',             
                'sku_id',
                'qty',              
                'price',
            ])
            ->withTimestamps()
            ->using(CostItem::class);
    }
}

Movement:

class Movement extends Model
{
    protected $table = 'movements';
    
    public function movable()
    {
        return $this->morphTo();
    }
}

Cost:

class Cost extends Model
{
    protected $table = 'costs';
    
    public function items()
    {
        return $this->belongsToMany(Item::class, 'cost_item', 'cost_id', 'item_id')
            ->withPivot([
                'id',
                'cost_id',
                'item_id',             
                'sku_id',
                'qty',              
                'price',
            ])
            ->withTimestamps()
            ->using(CostItem::class);
    }
}

CostItem:

class CostItem extends Pivot
{
    protected $table = 'cost_item';
    
    public function movement()
    {
        return $this->morphOne(Movement::class, 'movable');
    }
    
    public function syncMovement()
    {
        $this->movement()->updateOrCreate([], [
            'sku_id' => $this->sku_id,
            'qty' => $this->qty,
            'price' => $this->cost, 
        ]);
    }
    
    protected static function booted()
    {
        static::created(function ($model) {
            $model->syncMovement();
        });
    }
}

I use the created event in the CostItem, I want to sync CostItem data to Movement when CostItem was created. But when I create the Cost and CostItem like following:

$cost = new Cost;
$cost->number = 'A00001';
$cost->note = 'test';
$cost->save();

$cost->items()->attach($item, [
    'sku_id' => 1,
    'qty' => 10,
    'price' => 100,
]);

I always got the error:

Next Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'movable_id' cannot be null (SQL: insert into `movements` (`movable_id`, `movable_type`, `sku_id`, `quantity`, `price`, `remaining`, `updated_at`, `created_at`) values (?, App\Models\ReceiveItem, 1, ?, 100, ?, 2020-12-01 10:27:03, 2020-12-01 10:27:03)) 

How do I fix this issue ? Or I wrote something wrong ? Any help is appreciated. Thanks.

Upvotes: 1

Views: 961

Answers (1)

Donkarnash
Donkarnash

Reputation: 12845

In the below code snippet from your question, $cost = new Cost is a new instance which doesn't represent an existing record in the database hence it doesn't have id value id=null.

So when you try to update or create a related record via relationship, it will give error.

Since it doesn't have an id any call to create a related record via the relationship will fail.

Get a fresh record from the database for $cost and then make the call to update or create a related record via relationship.

$cost = new Cost;
$cost->number = 'A00001';
$cost->note = 'test';
$cost->save();

$cost->fresh()->items()->attach($item, [
    'sku_id' => 1,
    'qty' => 10,
    'price' => 100,
]);

Upvotes: 1

Related Questions