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.