Explain Eloquent morphMany parameters

Polymorphic Relations

Table Structure

Polymorphic relations allow a model to belong to more than one other model on a single association. For example, imagine users of your application can "comment" on both posts and videos. Using polymorphic relationships, you can use a single comments table for both of these scenarios. First, let's examine the table structure required to build this relationship:

posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

Two important columns to note are the commentable_id and commentable_type columns on the comments table. The commentable_id column will contain the ID value of the post or video, while the commentable_type column will contain the class name of the owning model. The commentable_type column is how the ORM determines which "type" of owning model to return when accessing the commentable relation.

Model Structure

Next, let's examine the model definitions needed to build this relationship:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
    /**
     * Get all of the owning commentable models.
     */
    public function commentable()
    {
        return $this->morphTo();
    }
}

class Post extends Model
{
    /**
     * Get all of the post's comments.
     */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

class Video extends Model
{
    /**
     * Get all of the video's comments.
     */
    public function comments()
    {
        return $this->morphMany('App\Comment', 'commentable');
    }
}

Retrieving Polymorphic Relations Once your database table and models are defined, you may access the relationships via your models. For example, to access all of the comments for a post, we can use the comments dynamic property:

$post = App\Post::find(1);

foreach ($post->comments as $comment) {
    //
}

You may also retrieve the owner of a polymorphic relation from the polymorphic model by accessing the name of the method that performs the call to morphTo. In our case, that is the commentable method on the Comment model. So, we will access that method as a dynamic property:

$comment = App\Comment::find(1);

$commentable = $comment->commentable;

The commentable relation on the Comment model will return either a Post or Video instance, depending on which type of model owns the comment. See this link: polymorphic-relations:

You can entry like that:

+---------+----------------+-------------------+
| user_id | commentable_id | commentable_type  |
+---------+----------------+-------------------+
|       1 |       1        | App\Post          |
|       1 |       2        | App\Post          |
|       1 |       3        | App\Post          |
|       1 |       1        | App\Video         |
|       1 |       2        | App\Video         |
|       1 |       3        | App\Video         |
+---------+----------------+-------------------+

The MorphMany relationship has the following function signature:

public function morphMany($related, $name, $type = null, $id = null, $localKey = null)
{
    //
}

Where:

  • $related (required): refers to the related model. e.g: User::class.
  • $name (required): the name of the polymorphic relation, like commentable.
  • $type (optional): customize the {relation}_type field to look up when doing a query.
  • $id (optional): customize the {relation}_id field to look up when doing a query.
  • $localKey (optional): customize the local key (by default id) to search when doing a query.

So -using the example shown in the Laravel documentation- if you want to use a different table structure for the comments table from this:

posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

to this:

posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    foo - integer // the index to look
    bar - string // the type to match

You'd need to define your relationships like this:

Post.php

public function comments()
{
    return $this->morphMany(Comment::class, 'commentable', 'foo', 'bar');
}

Video.php

public function comments()
{
    return $this->morphMany(Comment::class, 'commentable', 'foo', 'bar');
}

Comment.php

public function commentable()
{
    return $this->morphTo('commentable');
}

Check this other answer.