Laravel 12 Eloquent: Relationships - A Complete Guide

Author

Kritim Yantra

Mar 25, 2025

Laravel 12 Eloquent: Relationships - A Complete Guide

Eloquent ORM (Object-Relational Mapping) is one of Laravel's most powerful features, allowing developers to interact with databases using an expressive, fluent syntax. One of the key strengths of Eloquent is its ability to define and manage relationships between database tables effortlessly.

In this blog post, we'll explore Laravel 12 Eloquent Relationships in detail, covering all types of relationships with practical examples.


Table of Contents

  1. Introduction to Eloquent Relationships
  2. Types of Eloquent Relationships
  3. Defining Relationships
  4. Querying Relationships
  5. Eager Loading
  6. Inserting Related Models
  7. Conclusion

1. Introduction to Eloquent Relationships

Database relationships define how tables interact with each other. In Laravel, Eloquent provides a simple way to define these relationships using model classes.

Relationships allow you to:

  • Retrieve related data efficiently.
  • Maintain data integrity.
  • Simplify complex queries.

2. Types of Eloquent Relationships

Laravel supports several types of relationships:

🔹 One-to-One

A one-to-one relationship links one record in a table to exactly one record in another table.

Example: A User has one Profile.

Migration Setup

Schema::create('profiles', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    $table->string('bio');
    $table->timestamps();
});

Defining the Relationship

// User Model
public function profile() {
    return $this->hasOne(Profile::class);
}

// Profile Model
public function user() {
    return $this->belongsTo(User::class);
}

Retrieving the Relationship

$user = User::find(1);
$profile = $user->profile; // Gets the user's profile

🔹 One-to-Many

A one-to-many relationship links one record to multiple records in another table.

Example: A Post has many Comments.

Migration Setup

Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->foreignId('post_id')->constrained();
    $table->text('content');
    $table->timestamps();
});

Defining the Relationship

// Post Model
public function comments() {
    return $this->hasMany(Comment::class);
}

// Comment Model
public function post() {
    return $this->belongsTo(Post::class);
}

Retrieving the Relationship

$post = Post::find(1);
$comments = $post->comments; // Gets all comments for the post

🔹 Many-to-Many

A many-to-many relationship requires an intermediate pivot table.

Example: A User can belong to many Roles, and a Role can have many Users.

Migration Setup

Schema::create('role_user', function (Blueprint $table) {
    $table->foreignId('user_id')->constrained();
    $table->foreignId('role_id')->constrained();
    $table->primary(['user_id', 'role_id']);
});

Defining the Relationship

// User Model
public function roles() {
    return $this->belongsToMany(Role::class);
}

// Role Model
public function users() {
    return $this->belongsToMany(User::class);
}

Retrieving the Relationship

$user = User::find(1);
$roles = $user->roles; // Gets all roles of the user

🔹 Has-One-Through

This relationship allows accessing a distant relation via an intermediate model.

Example: A Supplier has one History through a User.

Migration Setup

Schema::create('suppliers', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->foreignId('supplier_id')->constrained();
    $table->string('name');
    $table->timestamps();
});

Schema::create('histories', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    $table->string('details');
    $table->timestamps();
});

Defining the Relationship

// Supplier Model
public function history() {
    return $this->hasOneThrough(History::class, User::class);
}

Retrieving the Relationship

$supplier = Supplier::find(1);
$history = $supplier->history; // Gets the supplier's history via user

🔹 Has-Many-Through

Similar to hasOneThrough, but retrieves multiple records.

Example: A Country has many Posts through Users.

Migration Setup

Schema::create('countries', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->foreignId('country_id')->constrained();
    $table->string('name');
    $table->timestamps();
});

Schema::create('posts', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained();
    $table->string('title');
    $table->timestamps();
});

Defining the Relationship

// Country Model
public function posts() {
    return $this->hasManyThrough(Post::class, User::class);
}

Retrieving the Relationship

$country = Country::find(1);
$posts = $country->posts; // Gets all posts from users in the country

🔹 Polymorphic Relationships

A polymorphic relationship allows a model to belong to multiple other models on a single association.

Example: Comments can belong to Posts or Videos.

Migration Setup

Schema::create('comments', function (Blueprint $table) {
    $table->id();
    $table->text('content');
    $table->morphs('commentable'); // Adds commentable_id and commentable_type
    $table->timestamps();
});

Defining the Relationship

// Comment Model
public function commentable() {
    return $this->morphTo();
}

// Post Model
public function comments() {
    return $this->morphMany(Comment::class, 'commentable');
}

// Video Model
public function comments() {
    return $this->morphMany(Comment::class, 'commentable');
}

Retrieving the Relationship

$post = Post::find(1);
$comments = $post->comments; // Gets all comments for the post

🔹 Many-to-Many Polymorphic Relationships

A more advanced polymorphic relationship where multiple models can have many related models.

Example: Posts and Videos can have many Tags.

Migration Setup

Schema::create('taggables', function (Blueprint $table) {
    $table->foreignId('tag_id')->constrained();
    $table->morphs('taggable'); // taggable_id, taggable_type
});

Defining the Relationship

// Tag Model
public function posts() {
    return $this->morphedByMany(Post::class, 'taggable');
}

public function videos() {
    return $this->morphedByMany(Video::class, 'taggable');
}

// Post Model
public function tags() {
    return $this->morphToMany(Tag::class, 'taggable');
}

// Video Model
public function tags() {
    return $this->morphToMany(Tag::class, 'taggable');
}

Retrieving the Relationship

$post = Post::find(1);
$tags = $post->tags; // Gets all tags for the post

3. Defining Relationships

All relationships in Laravel are defined as methods in Eloquent models. The method names should be descriptive (e.g., posts(), comments()).


4. Querying Relationships

You can query relationships like regular methods:

// Get all posts with at least one comment
$posts = Post::has('comments')->get();

// Get posts with more than 5 comments
$posts = Post::has('comments', '>', 5)->get();

// Filter using whereHas
$posts = Post::whereHas('comments', function ($query) {
    $query->where('content', 'like', '%awesome%');
})->get();

5. Eager Loading

Eager loading prevents the N+1 query problem by loading relationships in advance.

// Without Eager Loading (N+1 Problem)
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->comments->count(); // Queries the DB each time
}

// With Eager Loading (Optimized)
$posts = Post::with('comments')->get();
foreach ($posts as $post) {
    echo $post->comments->count(); // No additional queries
}

6. Inserting Related Models

You can attach related models easily:

// One-to-Many
$post = Post::find(1);
$comment = $post->comments()->create(['content' => 'Great post!']);

// Many-to-Many
$user = User::find(1);
$user->roles()->attach([1, 2]); // Attach role IDs

7. Conclusion

Laravel Eloquent Relationships provide a clean, expressive way to handle database associations. Whether you're working with one-to-one, one-to-many, many-to-many, or polymorphic relationships, Eloquent makes it easy to define, query, and manage them efficiently.

By mastering these relationships, you can build complex database interactions with minimal effort while keeping your code clean and maintainable.

🚀 Happy Coding with Laravel 12! 🚀

Let me know in the comments if you have any questions! 👇😊

Tags

Laravel Php

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Continue with Google

Related Posts