Many-to-many relationships let you connect two types of data where each item can relate to many items of the other type. It helps organize complex connections easily.
When a user can have many roles, and each role can belong to many users.
When a student can enroll in many courses, and each course has many students.
When a product can have many tags, and each tag can apply to many products.
Syntax
Laravel
public function roles() {
return $this->belongsToMany(Role::class);
}
Use belongsToMany() inside your Eloquent model to define the many-to-many link.
Laravel expects a pivot table named alphabetically by the two related tables, e.g., role_user.
Examples
This example shows a User model linked to Role model with a many-to-many relationship.
Laravel
class User extends Model {
public function roles() {
return $this->belongsToMany(Role::class);
}
}
The Role model also defines the inverse many-to-many relationship back to User.
Laravel
class Role extends Model {
public function users() {
return $this->belongsToMany(User::class);
}
}
Attach a role to a user by adding a record in the pivot table.
Laravel
return $user->roles()->attach($roleId);
Remove a role from a user by deleting the pivot table record.
Laravel
return $user->roles()->detach($roleId);
Sample Program
This example shows how a User model defines a many-to-many relationship to Role. We simulate a user with two roles and print their names.
Laravel
<?php
use Illuminate\Database\Eloquent\Model;
class User extends Model {
public function roles() {
return $this->belongsToMany(Role::class);
}
}
class Role extends Model {
public function users() {
return $this->belongsToMany(User::class);
}
}
// Simulate fetching a user and listing their roles
$user = new User();
// Assume roles() returns a collection of Role objects with'name' property
$user->setRelation('roles', \Illuminate\Support\Collection::make([
(object)["name" => "Admin"],
(object)["name" => "Editor"]
]));
foreach ($user->roles as $role) {
echo $role->name . "\n";
}
OutputSuccess
Important Notes
The pivot table must have the two foreign keys named by default as singular model names with _id, e.g., user_id and role_id.
You can customize the pivot table name and keys by passing arguments to belongsToMany().
Use attach(), detach(), and sync() methods to manage pivot table records easily.
Summary
Many-to-many relationships connect two models where each can have many of the other.
Use belongsToMany() in both models to define the link.
Laravel uses a pivot table to store the connections between the two models.
Practice
(1/5)
1. What does the belongsToMany() method define in a Laravel model?
easy
A. A polymorphic relationship between models
B. A one-to-one relationship between two models
C. A one-to-many relationship from one model to another
D. A many-to-many relationship between two models
Solution
Step 1: Understand relationship types in Laravel
Laravel provides different methods to define relationships: one-to-one, one-to-many, many-to-many, and polymorphic.
Step 2: Identify the purpose of belongsToMany()
The belongsToMany() method specifically defines a many-to-many relationship where both models can have multiple related models.
Final Answer:
A many-to-many relationship between two models -> Option D
Quick Check:
belongsToMany() = many-to-many [OK]
Hint: belongsToMany means many-to-many link between models [OK]
Common Mistakes:
Confusing belongsToMany with hasOne or hasMany
Thinking it defines one-to-one relationships
Assuming it creates a polymorphic relation
2. Which of the following is the correct syntax to define a many-to-many relationship in a Laravel model named Post related to Tag?
easy
A. public function tags() { return $this->belongsToMany(Tag::class); }
B. public function tags() { return $this->hasMany(Tag::class); }
C. public function tags() { return $this->hasOne(Tag::class); }
D. public function tags() { return $this->morphToMany(Tag::class); }
Solution
Step 1: Recall the method for many-to-many relationships
In Laravel, many-to-many relationships use the belongsToMany() method inside the model.
Step 2: Match the syntax to the correct method
The correct syntax is public function tags() { return $this->belongsToMany(Tag::class); } to link Post and Tag models.
Final Answer:
public function tags() { return $this->belongsToMany(Tag::class); } -> Option A
Quick Check:
belongsToMany() syntax = public function tags() { return $this->belongsToMany(Tag::class); } [OK]
Hint: Use belongsToMany() for many-to-many syntax [OK]
Common Mistakes:
Using hasMany instead of belongsToMany
Using hasOne which is one-to-one
Confusing morphToMany with belongsToMany
3. Given the following code in a Laravel model User:
public function roles() {
return $this->belongsToMany(Role::class);
}
$user = User::find(1);
$roles = $user->roles()->pluck('name');
echo $roles->toJson();
What will be the output if user 1 has roles named "admin" and "editor"?
medium
A. Syntax error
B. ["1","2"]
C. ["admin","editor"]
D. null
Solution
Step 1: Understand the belongsToMany relationship usage
The roles() method returns all roles related to the user via the pivot table.
Step 2: Analyze the pluck and toJson methods
The pluck('name') extracts the 'name' field from each related role, returning a collection of role names. toJson() converts this collection to a JSON string.
5. You have two models, Student and Course, linked by a many-to-many relationship using a pivot table course_student. You want to attach a course with ID 5 to a student with ID 3 and also store the enrollment date in the pivot. Which code snippet correctly does this?
hard
A. $student = Student::find(3);
$student->courses()->attach(5, ['enrolled_at' => now()]);
B. $student = Student::find(3);
$student->courses()->save(5, ['enrolled_at' => now()]);
C. $student = Student::find(3);
$student->courses()->sync(5, ['enrolled_at' => now()]);
D. $student = Student::find(3);
$student->courses()->attach([5]);
Solution
Step 1: Understand attaching in many-to-many with pivot data
The attach() method adds a record to the pivot table and accepts the related model ID plus an array of extra pivot data.
Step 2: Analyze each option
$student = Student::find(3);
$student->courses()->attach(5, ['enrolled_at' => now()]); correctly uses attach(5, ['enrolled_at' => now()]). $student = Student::find(3);
$student->courses()->save(5, ['enrolled_at' => now()]); uses save() which expects a model instance, not an ID. $student = Student::find(3);
$student->courses()->sync(5, ['enrolled_at' => now()]); uses sync() incorrectly with extra data. $student = Student::find(3);
$student->courses()->attach([5]); attaches without pivot data.
Final Answer:
$student = Student::find(3);
$student->courses()->attach(5, ['enrolled_at' => now()]); -> Option A