1. Why Eloquent Relationships?
Instead of writing raw SQL JOIN every time, Laravel lets you say:
This magic is done by Eloquent Relationships.
Instead of writing raw SQL JOIN every time, Laravel lets you say:
bash
$posts = User::find(1)->posts; // automatically gets all posts of that user
$author = Post::find(5)->author; // instantly gets the user who wrote the post
2. The 6 Main Relationships You Must Know
Relationship | Meaning (Real Life) | Method in Model | Example |
|---|---|---|---|
One to One | One user → one profile | hasOne() / belongsTo() | User → Profile |
One to Many | One user → many posts | hasMany() / belongsTo() | User → Posts |
Many to Many | One student → many courses, one course → many students | belongsToMany() | Student |
Has One Through | Country → one capital (through capital table) | hasOneThrough() | Country → Capital |
Has Many Through | Country → many citizens (through users table) | hasManyThrough() | Country → Users |
Polymorphic | One image → belongs to Post or Product | morphTo() / morphMany() / morphToMany() | Image → Post/Product |
3. Real-Life Examples with Code (Laravel 12)
1. One to Many (Most Common)
2. One to One
3. Many to Many (Student Course)
4. Polymorphic (One Image for Post or Product)
4. Eager Loading (Very Important for Speed!)
Without eager loading → 1 + N queries (slow!)
With eager loading → only 2 queries
Other useful ones:
1. One to Many (Most Common)
bash
// User.php
class User extends Model
{
public function posts() // A user has many posts
{
return $this->hasMany(Post::class);
}
}
// Post.php
class Post extends Model
{
public function user() // A post belongs to one user
{
return $this->belongsTo(User::class);
}
}
// Usage
$user = User::find(1);
foreach($user->posts as $post) {
echo $post->title;
}
$post = Post::find(10);
echo $post->user->name; // automatically gets the author
bash
// User.php
public function profile()
{
return $this->hasOne(Profile::class);
}
// Profile.php
public function user()
{
return $this->belongsTo(User::class);
}
// Usage
$user->profile->bio;
bash
// Migration (pivot table)
Schema::create('course_student', function (Blueprint $table) {
$table->id();
$table->foreignId('student_id')->constrained();
$table->foreignId('course_id')->constrained();
$table->integer('grade')->nullable();
$table->timestamps();
});
// Student.php
public function courses()
{
return $this->belongsToMany(Course::class)
->withPivot('grade') // extra column
->withTimestamps();
}
// Usage
$student->courses()->attach($courseId, ['grade' => 85]);
$student->courses; // all courses
foreach($student->courses as $course) {
echo $course->pivot->grade; // 85
}
bash
// Migration
$table->morphs('imageable'); // creates imageable_id + imageable_type
// Image.php
public function imageable()
{
return $this->morphTo();
}
// Post.php & Product.php
public function images()
{
return $this->morphMany(Image::class, 'imageable');
}
// Usage
$post->images()->create(['url' => 'post1.jpg']);
$product->images()->create(['url' => 'shoe.jpg']);
Without eager loading → 1 + N queries (slow!)
bash
foreach(User::all() as $user) {
echo $user->posts->count(); // 100 users = 101 queries! Very bad
}
bash
$users = User::with('posts')->get(); // magic!
foreach($users as $user) {
echo $user->posts->count(); // no extra query
}
bash
User::with(['posts.comments'])->get(); // nested
User::withCount('posts')->get(); // posts_count column
User::whereHas('posts', fn($q) => $q->where('published', 1))->get();
5. Quick Cheat Sheet (Save This!)
Relationship | Model A Code | Model B Code |
|---|---|---|
One to Many | hasMany(Post::class) | belongsTo(User::class) |
One to One | hasOne(Profile::class) | belongsTo(User::class) |
Many to Many | belongsToMany(Course::class) | same on both sides |
Polymorphic Many | morphMany(Image::class,’imageable’) | morphTo() |
Final Thought
Best Practice (Bangladeshi Developers Follow This)
- Always use with() when showing lists
- Use withCount() for dashboard numbers
- Use pivot table with withPivot() for grades, roles, etc.
- Never write JOIN manually if relationship exists