Kritim Yantra
Apr 06, 2025
Many-to-many relationships are common in web applications when multiple records in one table are associated with multiple records in another table. Laravel 12 makes working with these relationships simple through its Eloquent ORM.
In this comprehensive guide, we'll cover:
A many-to-many relationship requires a pivot table (junction table) that connects the two related tables.
posts
table: id
, title
, content
tags
table: id
, name
post_tag
pivot table: post_id
, tag_id
Each post can have multiple tags, and each tag can be assigned to multiple posts.
composer create-project laravel/laravel many-to-many-demo
cd many-to-many-demo
Edit your .env
file with database credentials.
php artisan make:migration create_posts_table
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->timestamps();
});
php artisan make:migration create_tags_table
Schema::create('tags', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
php artisan make:migration create_post_tag_table
Schema::create('post_tag', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('post_id');
$table->unsignedBigInteger('tag_id');
$table->timestamps();
$table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
});
Run migrations:
php artisan migrate
php artisan make:model Post
php artisan make:model Tag
public function tags()
{
return $this->belongsToMany(Tag::class);
}
public function posts()
{
return $this->belongsToMany(Post::class);
}
$post = Post::find(1);
$post->tags()->attach([1, 2, 3]); // Attach tags with IDs 1, 2, and 3
$post->tags()->detach(2); // Detach tag with ID 2
$post->tags()->detach(); // Detach all tags
$post->tags()->sync([1, 3]); // Only tags 1 and 3 will remain attached
$post->tags()->toggle([1, 2]); // Toggles attachment status
$post->tags()->attach(1, ['created_by' => Auth::id()]);
$post = Post::with('tags')->find(1);
foreach ($post->tags as $tag) {
echo $tag->name;
}
$tag = Tag::with('posts')->find(1);
foreach ($tag->posts as $post) {
echo $post->title;
}
// Without eager loading (N+1 problem)
$posts = Post::all();
foreach ($posts as $post) {
foreach ($post->tags as $tag) {
// ...
}
}
// With eager loading
$posts = Post::with('tags')->get();
php artisan tinker
// Create posts
Post::create(['title' => 'First Post', 'content' => 'Content...']);
Post::create(['title' => 'Second Post', 'content' => 'Content...']);
// Create tags
Tag::create(['name' => 'Laravel']);
Tag::create(['name' => 'PHP']);
Tag::create(['name' => 'Web Development']);
// Attach tags
$post = Post::first();
$post->tags()->attach([1, 2]);
Route::get('/posts', function () {
$posts = Post::with('tags')->get();
return view('posts.index', compact('posts'));
});
<!-- resources/views/posts/index.blade.php -->
@foreach ($posts as $post)
<h2>{{ $post->title }}</h2>
<p>Tags:
@foreach ($post->tags as $tag)
<span class="badge bg-primary">{{ $tag->name }}</span>
@endforeach
</p>
@endforeach
php artisan serve
Visit http://localhost:8000/posts
to see posts with their tags.
✅ Key Takeaways:
belongsToMany()
in both modelsattach()
, detach()
, and sync()
manage relationships🚀 Happy Coding!
📌 Questions? Drop them in the comments below!
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google