'How to pass type and id to laravel polymorphic relation

I have a navigation model that can have many items associated with it:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;

class Navigation extends Model
{
  use HasFactory;
  use Searchable;

  protected $guarded = [];

  public function navigation_items(): HasMany
  {
    return $this->hasMany(NavigationItem::class);
  }
}

The navigation item model looks like this

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;

class NavigationItem extends Model
{
  use HasFactory;

  protected $guarded = [];

  public function navigation(): BelongsTo
  {
    return $this->belongsTo(Navigation::class);
  }

  public function navigatable(): MorphTo
  {
    return $this->morphTo();
  }
}

Now an item can either be of type Page or Blog, in this case the Page model looks like this:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;

use Illuminate\Database\Eloquent\Relations\MorphOne;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;

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

  public function navigatable(): MorphOne
  {
    return $this->morphOne(NavigationItem::class, 'navigatable');
  }
}

When I try to save a navigation model and associate it with a item, the following error appears:

SQLSTATE[HY000]: General error: 1364 Field 'navigatable_type' doesn't have a default value

I save the model like this:

    foreach ($this->selected as $id) {
      $this->navigation->navigation_items()->create([
        'navigation_id' => $this->navigation->id,
      ]);

Where $this->selected is the navigation id, it should automatically get the correct navigatable_type and navigatable_id, but this doesn't seem to be working.

passing in the type and id manually works, but this kinda defeats the point of a polymorphic relationship.

any ideas?



Solution 1:[1]

On NavigationItem model, since you defined polymorphic relation as 'navigatable' it is expected that NavigationItem model's table contains navigatable_type and navigatable_id. First please ensure this checks out.

Creating records through relation's base function is not a valid method. It is not clear what you are trying to achieve there but when you want to set relation there is two standard way of achieving it:

1- Associate

When a relation is defined as belongsTo, you may use associate() function. Like so:

$account = Account::find(10);
 
$user->account()->associate($account);

2- Attach

Attach is used when relation is defined belongsToMany (pivot). It allows you to attach multiple records to a model instance/record.

$user = User::find(1);
 
$user->roles()->attach($roleId);

So if you want to set a 'navigatable' to a Navigation instance, you may:

$somePageInstance=Page::find(55);
$nagivation->navigatable()->associate($somePageInstance)
$nagivation->save();//remember to save, otherwise it won't be

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Skywarth