LARAVEL

Advanced Laravel Eloquent ORM Techniques

February 10, 2024 20 min read

Introduction

Laravel's Eloquent ORM is a powerful tool for database interactions. This guide covers advanced techniques that will help you write cleaner, more efficient database code.

Advanced Relationships

Has One Through

// Get user's passport through country
class User extends Model
{
    public function passport()
    {
        return $this->hasOneThrough(
            Passport::class,
            Country::class
        );
    }
}

// Usage
$user->passport;

Has Many Through

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

Many-to-Many with Pivot Data

class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class)
            ->withPivot('assigned_at', 'expires_at')
            ->withTimestamps();
    }
}

// Usage
$user->roles()->attach($roleId, ['assigned_at' => now()]);

Query Scopes

Local Scopes

class User extends Model
{
    // Local scope
    public function scopeActive($query)
    {
        return $query->where('active', true);
    }
    
    // Scope with parameters
    public function scopeWhereRole($query, $role)
    {
        return $query->where('role', $role);
    }
    
    // Scope combining
    public function scopeActiveAdmins($query)
    {
        return $query->active()->whereRole('admin');
    }
}

// Usage
User::active()->get();
User::activeAdmins()->get();

Global Scopes

class User extends Model
{
    protected static function booted()
    {
        static::addGlobalScope('active', function ($builder) {
            $builder->where('active', true);
        });
    }
}

// Remove global scope
User::withoutGlobalScope('active')->get();

Accessors & Mutators

Attribute Accessors

class User extends Model
{
    // Get full name accessor
    public function getFullNameAttribute(): string
    {
        return "{$this->first_name} {$this->last_name}";
    }
    
    // Get age from birth_date
    public function getAgeAttribute(): int
    {
        return Carbon::parse($this->birth_date)->age;
    }
}

// Usage
$user->full_name; // "John Doe"
$user->age; // 30

Attribute Mutators

class User extends Model
{
    // Set email to lowercase
    public function setEmailAttribute($value): void
    {
        $this->attributes['email'] = strtolower($value);
    }
    
    // Hash password on set
    public function setPasswordAttribute($value): void
    {
        $this->attributes['password'] = bcrypt($value);
    }
}

Polymorphic Relationships

One-to-One Polymorphic

class Image extends Model
{
    public function imageable()
    {
        return $this->morphTo();
    }
}

class User extends Model
{
    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

class Product extends Model
{
    public function image()
    {
        return $this->morphOne(Image::class, 'imageable');
    }
}

// Usage
$user->image()->create(['url' => 'avatar.jpg']);
$product->image->url;

Many-to-Many Polymorphic

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

Eloquent Collections

Custom Collections

class UserCollection extends Collection
{
    public function sumVotes(): int
    {
        return $this->sum('votes');
    }
    
    public function active(): self
    {
        return $this->filter(fn ($user) => $user->is_active);
    }
}

class User extends Model
{
    public function newCollection(array $models = [])
    {
        return new UserCollection($models);
    }
}

Collection Methods

// Transform
$users = User::all()->map(fn($u) => [
    'name' => $u->name,
    'email' => $u->email
]);

// Filter and pluck
$activeEmails = User::all()
    ->filter(fn($u) => $u->active)
    ->pluck('email');

// Group by
$grouped = User::all()->groupBy('role');

// Key by
$keyed = User::all()->keyBy('id');

Model Events

Event Hooks

class User extends Model
{
    protected static function booted()
    {
        // Creating
        static::creating(function ($user) {
            $user->slug = Str::slug($user->name);
        });
        
        // Created
        static::created(function ($user) {
            // Send welcome email
        });
        
        // Updating
        static::updating(function ($user) {
            $user->updated_by = auth()->id();
        });
        
        // Deleting
        static::deleting(function ($user) {
            // Soft delete related
            $user->posts()->delete();
        });
    }
}

Summary

Advanced Eloquent features enable you to build complex data models with elegant, readable code. Master these techniques to take your Laravel applications to the next level.

For more Laravel tutorials, check out Laravel Database Migrations and Laravel API Authentication.