Laravel All About Polymorphic Relationships

Hello Artisans, in this tutorial I'll show you polymorphic relationships in Laravel. From today's tutorial, we can understand how we can create many-to-many relationship as well as we can also know the different methods which are related to polymorphic relationships like attach, detach, sync, saveMany, create or get all records etc. Suppose we've the following table schema:

posts
    id - integer
    name - string
 
videos
    id - integer
    name - string
 
tags
    id - integer
    name - string
 
taggables
    tag_id - integer
    taggable_id - integer
    taggable_type - string

Here posts and videos all the table share the same single table of unique tags.

Next, we're ready to define the relationships on the models. The Post and Video models will both contain a tags method that calls the morphToMany method provided by the base Eloquent model class.

The morphToMany method accepts the name of the related model as well as the "relationship name". Here we'll refer to the relationship as "taggable". As in the intermediate table we use taggable_id and taggable_type. So, try to use same name of relationship method and prefix of the column name.

app/Models/Post.php
public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
app/Models/Video.php
public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }

Now we define the inverse relationship in Tag.php for it's possible parent models.

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 call our relationship from our model classes.

Retrieve the Records

If we want to retrieve all the tags of a Post/Video we can do that by following

use App\Models\Post;
use App\Models\Video;
 
//for post
$post = Post::find(1);
 
foreach ($post->tags as $tag) {
    //
}

//for video
$video = Video::find(1);
 
foreach ($video->tags as $tag) {
    //
}

We can also find the posts and videos of a specific tag like below

use App\Models\Tag;
 
//for post
$tag = Tag::find(1);
 
foreach ($tag->posts as $post) {
    //
}

//for video

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

Save Records

If we want to save tags for a specific post/video, we can do the following

use App\Models\Post;
use App\Models\Video;
 
$post = Post::find(1);	
 
$tag = new Tag;
$tag->name = "Laravel";
 
//for posts
$post->tags()->save($tag);

//for videos
$video = Video::find(1);	
$video->tags()->save($tag);

We can also save many tags at once using saveMany().

use App\Models\Post;
use App\Models\Video;
 
$post = Post::find(1);	
 
$tag1 = new Tag;
$tag->name = "Laravel";

$tag2 = new Tag;
$tag->name = "VueJs";
 
//for posts
$post->tags()->saveMany([$tag1,$tag2]);

//for videos
$video = Video::find(1);	
$video->tags()->saveMany([$tag1,$tag2]);

Or we can also save via attach() method

use App\Models\Post;
use App\Models\Video;
 
$post = Post::find(1);	
 
$tag1 = Tag::find(1);

$tag2 = Tag::find(2);
 
//for posts
$post->tags()->attach([$tag1->id,$tag2->id]);

//for videos
$video = Video::find(1);	
$video->tags()->attach([$tag1->id,$tag2->id]);

Delete Records

We can also delete single/multiple records using detach() method.

use App\Models\Post;
use App\Models\Video;
 
$post = Post::find(1);	
 
$tag1 = Tag::find(1);

$tag2 = Tag::find(2);
 
//for posts
$post->tags()->detach([$tag1->id,$tag2->id]);

//for videos
$video = Video::find(1);	
$video->tags()->detach([$tag1->id,$tag2->id]);

Or we wan use sync() which will attach if data is not exist and detach if data is already exists.

use App\Models\Post;
use App\Models\Video;
 
$post = Post::find(1);	
 
$tag1 = Tag::find(1);

$tag2 = Tag::find(2);
 
//for posts
$post->tags()->sync([$tag1->id,$tag2->id]);

//for videos
$video = Video::find(1);	
$video->tags()->sync([$tag1->id,$tag2->id]);

That's it for today. Hope you'll enjoy through this tutorial. Thanks for reading. ๐Ÿ™‚