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, likecommentable
.$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 defaultid
) 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.