This entry is part 7 of 9 in the series Laravel Eloquent Relationships
- How to Use a One-to-One Relationship in Laravel
- How to Use a One-to-Many Relationship in Laravel
- How to Use a Many-to-Many Relationship in Laravel
- Using Extra Fields in Pivot Table With Laravel belongsToMany
- How to Use Has-Many-Through Relationships in Laravel
- How to use One-to-Many Polymorphic Relationship in Laravel
- How to use Many-to-Many Polymorphic Relationship in Laravel
- How to Paginate a Model with Relationship in Laravel
- How to Use `with()` to Eager Load Relationship in Laravel
Laravel provides powerful support for Many-to-Many Polymorphic Relationships, allowing a single table to be associated with multiple models through a pivot table.
What is a Many-to-Many Polymorphic Relationship?
A Many-to-Many Polymorphic Relationship allows a parent model to be associated with multiple instances of different child models through a pivot table, and vice versa.
In this post, we’ll look at an example where you have a “Tag” model that can be applied to both “Post” and “Video” models. Here, “Post” and “Video” are the parent classes, and “Tag” is the child class.
The following diagram illustrates how the database will look like:
tags, taggables, posts and videosLet’s get started!
Step 1: Create and Run the Migrations
First, create the migration files for each entity using the Artisan command:
php artisan make:migration create_tags_table --create=tags
php artisan make:migration create_posts_table --create=posts
php artisan make:migration create_videos_table --create=videos
php artisan make:migration create_taggables_table --create=taggablesModify the migration files as follows:
For the tags table migration:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
// Add other columns as needed
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('tags');
}
};For the posts table migration:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('content')->nullable();
// Add other columns as needed
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};For the videos table migration:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('videos', function (Blueprint $table) {
$table->id();
$table->string('title');
// Add other columns as needed
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('videos');
}
};For the pivot table migration (taggables):
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('taggables', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('tag_id');
$table->unsignedBigInteger('taggable_id');
$table->string('taggable_type');
});
}
public function down(): void
{
Schema::dropIfExists('taggables');
}
};Step 2: Create the Models
Create the models for Tag, Post, and Video using the Artisan command:
php artisan make:model Tag
php artisan make:model Post
php artisan make:model VideoStep 3: Define the Many-to-Many Polymorphic Relationship
A Many-to-Many Polymorphic Relationship is defined by using the morphToMany() method on the models that can have tags (like Post and Video) and the morphedByMany() method on the Tag model.
Define the relationships as follows:
For the Tag model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Tag extends Model
{
protected $fillable = ['name'];
public function posts()
{
return $this->morphedByMany(Post::class, 'taggable');
}
public function videos()
{
return $this->morphedByMany(Video::class, 'taggable');
}
}For the Post model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['title', 'content'];
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}For the Video model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Video extends Model
{
protected $fillable = ['title'];
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable');
}
}Step 4: Creating Records
Now, you can create records while utilizing the Many-to-Many Polymorphic Relationships.
// Creating tags
$tag1 = Tag::create(['name' => 'Laravel']);
$tag2 = Tag::create(['name' => 'PHP']);
$tag3 = Tag::create(['name' => 'Database']);
// Creating posts
$post1 = Post::create([
'title' => 'Introduction to Laravel',
'content' => '...'
]);
$post2 = Post::create([
'title' => 'Laravel Best Practices',
'content' => '...'
]);
// Creating videos
$video1 = Video::create([
'title' => 'Laravel Tutorial'
]);
$video2 = Video::create([
'title' => 'Advanced PHP Concepts'
]);
// Attaching tags to posts and videos
$post1->tags()->attach([$tag1->id, $tag2->id]);
$post2->tags()->attach([$tag1->id, $tag3->id]);
$video1->tags()->attach([$tag1->id, $tag2->id]);
$video2->tags()->attach([$tag2->id, $tag3->id]);After we ran this code our database will contain the following data:
posts, videos, tags and taggablesStep 5: Retrieving Records
To retrieve records attached by Many-to-Many Polymorphic Relationships we can use the following:
// Retrieving tags for a post
$post = Post::find(1);
$tags = $post->tags;
// Retrieving posts for a tag
$tag = Tag::find(1);
$posts = $tag->posts;
// Retrieving tags for a video
$video = Video::find(1);
$tags = $video->tags;
// Retrieving videos for a tag
$tag = Tag::find(2);
$videos = $tag->videos;That’s it! You’ve successfully defined and used Many-to-Many Polymorphic Relationship.
Further Examples of Many-To-Many Polymorphic Relationships
| Parent Model 1 | Parent Model 2 | Child Model | Polymorphic Relationship |
| User | Role | Permission | permissionable |
| Article | Category | Tag | taggable |
| Project | Team | Member | skillable |
| Document | Video | Viewer | viewable |
Conclusion
In this blog post, we explored Many-to-Many Polymorphic Relationships in Laravel, which allow for flexible associations between multiple models using a single pivot table. We discussed how to set up the relationships and perform operations such as creating and retrieving records.
By understanding Many-to-Many Polymorphic Relationships, you can build more versatile and dynamic applications in Laravel. Happy coding!
References

Great article Johan!
I’m glad you’ve found my post useful. Thank you for your kind words!
great job
Thanks Mohammad 🙂
Very very helpful article to understand many to many polymorphism. Thanks!
You’re welcome, I’m glad to help!