Using Eloquent ORM for Database Relationships in Laravel

By Maulik Paghdal

19 Oct, 2024

Using Eloquent ORM for Database Relationships in Laravel

Introduction

Eloquent ORM is one of Laravel's most powerful features, enabling developers to interact with databases using an elegant and expressive syntax. By understanding how to define and use database relationships in Eloquent, you can simplify your application logic and reduce boilerplate code. This article explores the core relationships supported by Eloquent and how to implement them.

Why Use Eloquent ORM?

Eloquent ORM provides:

  • Readable Syntax: Intuitive methods to interact with your database.
  • Relationship Support: Built-in support for defining relationships like one-to-many, many-to-many, and more.
  • Query Building: Easy-to-read queries without writing raw SQL.

Types of Relationships in Eloquent

Eloquent supports several types of relationships:

  1. One-to-One
  2. One-to-Many
  3. Many-to-Many
  4. Has Many Through
  5. Polymorphic Relationships
  6. Many-to-Many Polymorphic Relationships

Defining Relationships

1. One-to-One Relationship

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

Example:

A User has one Profile.

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

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

Usage:

$user = User::find(1);
$profile = $user->profile;

$profileUser = Profile::find(1)->user;

2. One-to-Many Relationship

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

Example:

A Post has many Comments.

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

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

Usage:

$post = Post::find(1);
$comments = $post->comments;

$commentPost = Comment::find(1)->post;

3. Many-to-Many Relationship

A many-to-many relationship involves a pivot table to link records between two tables.

Example:

A User belongs to many Roles.

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

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

Usage:

$user = User::find(1);
$roles = $user->roles;

$roleUsers = Role::find(1)->users;

4. Has Many Through Relationship

A "has many through" relationship provides a shortcut for accessing a distant relationship.

Example:

A Country has many Posts through a User.

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

Usage:

$country = Country::find(1);
$posts = $country->posts;

5. Polymorphic Relationships

Polymorphic relationships allow a model to belong to more than one other model on a single association.

Example:

A Post and Video can share a Tag.

// Tag.php
public function taggable()
{
    return $this->morphTo();
}

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

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

6. Many-to-Many Polymorphic Relationships

This relationship type allows multiple models to share many of the same associated models.

Example:

A Post and a Video can both be associated with Tags, and each tag can belong to multiple Posts or Videos.

Database Setup:

You need three tables: posts, videos, and tags, along with a pivot table taggables.

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

Model Definitions:

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

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

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

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

Usage:

// Attach a tag to a post
$post = Post::find(1);
$tag = Tag::find(1);
$post->tags()->attach($tag->id);

// Attach a tag to a video
$video = Video::find(1);
$video->tags()->attach($tag->id);

// Retrieve tags for a post
$tags = $post->tags;

// Retrieve posts for a tag
$posts = $tag->posts;

// Retrieve videos for a tag
$videos = $tag->videos;

Querying Relationships

You can query relationships with Eloquent's lazy loading, eager loading, or constrained eager loading:

Lazy Loading:

$user = User::find(1);
$posts = $user->posts;

Eager Loading:

$users = User::with('posts')->get();

Constrained Eager Loading:

$users = User::with(['posts' => function ($query) {
    $query->where('published', true);
}])->get();

Practical Example: Blog Application

Here’s an example setup for a blog application:

  1. User: Creates posts.
  2. Post: Has multiple comments.
  3. Comment: Belongs to a post.

Models:

// User.php
public function posts()
{
    return $this->hasMany(Post::class);
}

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

Usage:

// Fetch posts by a user
$user = User::find(1);
$posts = $user->posts;

// Fetch comments for a post
$post = Post::find(1);
$comments = $post->comments;

Best Practices

  • Use Eager Loading: Avoid N+1 query problems by preloading relationships.
  • Define Foreign Keys in Migrations: Use foreignId and constrained for better database integrity.
  • Leverage Relationship Methods: Use Eloquent relationship methods like create, associate, and detach.

Conclusion

Mastering Eloquent ORM relationships is crucial for developing scalable and maintainable Laravel applications. By defining and querying relationships effectively, you can streamline database interactions and build robust data-driven systems.

Happy coding!

Topics Covered