DEV Community

Jeroen van Rensen
Jeroen van Rensen

Posted on • Originally published at jeroenvanrensen.nl

Eloquent polymorphic relationships explained (with examples)

In my opinion, Eloquent is one of the most powerful features of Laravel. It is an API for interacting with your database, and it has a very nice and easy-to-remember syntax. For example:

$post->author->name; 
Enter fullscreen mode Exit fullscreen mode

Will give you the name of the post's author.

This is an example of an Eloquent relationship. Relationships define how your models (tables) are connected. Although most are easy to understand, there are a few more complicated ones.

In this post, I'm going to show how every relationship works.

One to one

In this example, we have three models: a Post, a Video, and an Image.

  • A Post has one Image
  • A Video has one Image
  • An Image belongs to a Post or Video

And we have this table structure:

posts id - integer title - string videos id - integer name - string images id - integer path - string imageable_id - integer imageable_type - string 
Enter fullscreen mode Exit fullscreen mode

We can define these relationships like this:

// app/Models/Post.php public function image() { return $this->morphOne(Image::class, 'imageable'); } 
Enter fullscreen mode Exit fullscreen mode
// app/Models/Video.php public function image() { return $this->morphOne(Image::class, 'imageable'); } 
Enter fullscreen mode Exit fullscreen mode
// app/Models/Image.php public function imageable() { return $this->morphTo(); } 
Enter fullscreen mode Exit fullscreen mode

Now we can access the image like this:

$post->image->path; $video->image->path; 
Enter fullscreen mode Exit fullscreen mode

And if we have the $image, we can get the object where it belongs to (a Post or a Video) like this:

$image->imageable; 
Enter fullscreen mode Exit fullscreen mode

One to many

In this example, we have three models: a Post, a Video, and a Comment.

  • A Post has many Comments
  • A Video has many Comments
  • A Comment belongs to a Post or a Video

And we have this table structure:

posts id - integer title - string videos id - integer name - string comments id - integer body - string commentable_id - integer commentable_type - string 
Enter fullscreen mode Exit fullscreen mode

We can define the relationships like this:

// app/Models/Post.php public function comments() { return $this->morphMany(Comment::class, 'commentable'); } 
Enter fullscreen mode Exit fullscreen mode
// app/Models/Video.php public function comments() { return $this->morphMany(Comment::class, 'commentable'); } 
Enter fullscreen mode Exit fullscreen mode
// app/Models/Comment.php public function commentable() { return $this->morphTo(); } 
Enter fullscreen mode Exit fullscreen mode

Now we can access the comments like this:

foreach($post->comments as $comment) { // } foreach($video->comments as $comment) { // } 
Enter fullscreen mode Exit fullscreen mode

And if we have a $comment, we can get the corresponding model (a Post or a Video) like this:

$comment->commentable; 
Enter fullscreen mode Exit fullscreen mode

Many to many

In this example, we have three models: a Post, a Video, and a Tag.

  • A Post has many Tags
  • A Video has many Tags
  • A Tag belongs to many Posts or Videos

For example, a Tag called "personal" can belong to a `Post and a Video.

We may have this table structure:

`
posts
id - integer
title - string

videos
id - integer
name - string

tags
id - integer
name - string

taggables
tag_id - integer
taggable_id - integer
taggable_type - string
`

We can define the relationships like this:

`php
// app/Models/Post.php

public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
`

`php
// app/Models/Video.php

public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
`

`php
// app/Models/Tag.php

public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}

public function videos()
{
return $this->morphedByMany(Video::class, 'taggable');
}
`

Now we can access the tags like this:

`php
foreach($post->tags as $tag) {
//
}

foreach($video->tags as $tag) {
//
}
`

And if we have a $tag, we can access the posts and videos like this:

`php
foreach($tag->posts as $post) {
//
}

foreach($tag->videos as $video) {
//
}
`

Top comments (0)