laraveleloquenteloquent-relationshippolymorphic-relationship

What is the use case of the first argument of the `morphTo` method?


According to this issue, when using custom method name to define a polymorphic relationship on Laravel, the name argument of the morphTo method doesn't work as expected, Let's assume a simple polymorphic table structure:

posts
    id - integer
    name - string

users
    id - integer
    name - string

images
    id - integer
    url - string
    imageable_id - integer
    imageable_type - string

and this model structure:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Image extends Model
{
    // ...

    // It doesn't work as expected
    public function picturable1()
    {
        return $this->morphTo('imageable');
    }

    // It doesn't work as expected
    public function picturable2()
    {
        return $this->morphTo('imageable', 'imageable_type', 'imageable_id');
    }

    // It works unexpectedly
    public function picturable3()
    {
        return $this->morphTo(null, 'imageable_type', 'imageable_id');
    }
}

When loading these relationships:

$image = \App\Image::with('picturable1')->find(1);
$image->picturable1; // exists and returns null but imageable instance was expected
$image->imageable;   // returns imageable instance unexpectedly

$image = \App\Image::with('picturable2')->find(1);
$image->picturable2; // exists and returns null but imageable instance was expected
$image->imageable;   // returns imageable instance unexpectedly

$image = \App\Image::with('picturable3')->find(1);
$image->picturable3; // returns imageable instance as expected
$image->imageable;   // doesn't exists as expected

So the questions are, What is the use case of the name argument of the morphTo method? and What is the right way to customize the name of the relationship like above example?


Solution

  • An explanation is added to Laravel 7.x documentation:

    If you need to specify custom type and id columns for the morphTo relation, always ensure you pass the relationship name (which should exactly match the method name) as the first parameter:

    /**
     * Get the model that the image belongs to.
     */
    public function picturable()
    {
        return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');
    }