Laravel Eloquent ORM Deep — Advanced Active Record Patterns
In this tutorial, you will learn about Laravel Eloquent ORM Deep. We cover key concepts, practical examples, and best practices to help you master this topic.
Laravel Eloquent ORM implements the Active Record pattern with a fluent query builder, model relationships, mutators, accessors, events, and API resource Serialization.
What You'll Learn
By the end of this tutorial, you'll master Eloquent's internals, use model events, implement global scopes, build API resources, and apply advanced patterns.
Why Eloquent Matters
Eloquent is Laravel's ORM with expressive syntax. Understanding its internals helps optimize queries, build clean APIs, and avoid common pitfalls.
Real-World Use
A Laravel API uses Eloquent models with API resources for JSON transformation, global scopes for multi-tenant filtering, and model events for cache invalidation.
Eloquent Path
flowchart LR
A[Eloquent ORM] --> B[Model Pattern]
B --> C[Relations]
B --> D[Scopes]
B --> E[Events]
B --> F[API Resources]
B --> G{You Are Here}
style G fill:#f90,color:#fff
Model Boot Method
Tap into Eloquent's boot lifecycle for global behavior.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model {
protected static function booted(): void {
static::creating(function ($post) {
$post->slug = str($post->title)->slug();
$post->author_id = auth()->id();
});
static::created(function ($post) {
Cache::tags(["posts"])->flush();
});
static::retrieved(function ($post) {
$post->increment("views");
});
}
}
Global Scopes
Apply constraints to all queries on a model.
<?php
namespace App\Models\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class TenantScope implements Scope {
public function apply(Builder $builder, Model $model): void {
$builder->where("tenant_id", tenant()->id);
}
}
// In model
use App\Models\Scopes\TenantScope;
class Project extends Model {
protected static function booted(): void {
static::addGlobalScope(new TenantScope());
}
}
API Resources
Transform Eloquent models for JSON APIs.
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource {
public function toArray(Request $request): array {
return [
"id" => $this->id,
"name" => $this->name,
"email" => $this->email,
"joined_at" => $this->created_at->diffForHumans(),
"posts_count" => $this->whenCounted("posts"),
"recent_posts" => PostResource::collection($this->whenLoaded("posts")),
];
}
}
Model Events and Observers
Observers group event handlers for cleaner models.
<?php
namespace App\Observers;
use App\Models\Post;
use App\Services\SearchIndexer;
class PostObserver {
public function __construct(private SearchIndexer $search) {}
public function created(Post $post): void {
$this->search->index("posts", $post->id, $post->toSearchableArray());
Cache::tags(["posts"])->flush();
}
public function updated(Post $post): void {
$this->search->update("posts", $post->id, $post->toSearchableArray());
}
public function deleted(Post $post): void {
$this->search->delete("posts", $post->id);
}
}
Common Mistakes
1. Overusing Lazy Loading
N+1 queries happen with lazy loaded relationships. Always eager load with with().
2. Not Using Query Builder for Complex Queries
Using Collection methods for filtering loads all rows into memory. Use the query builder.
3. Mass Assignment Without Fillable
Forgetting $fillable in models allows mass assignment. Always whitelist fields.
4. Ignoring Model Events for Side Effects
Putting side effects in controllers leads to duplication. Use model events.
5. Nested API Resources Without whenLoaded
Without whenLoaded, serializing relations without loading them causes N+1.
Practice Questions
1. What is the booted() method for?
Registering model events and global scopes that apply to every instance.
2. How do global scopes work?
They add query constraints automatically to every query on the model.
3. What is an API resource?
A transformation layer that converts models to JSON with selective attribute inclusion.
4. How do you create a model Observer?
Create an observer class and register it in the AppServiceProvider.
5. Challenge: Create an Eloquent model with a global scope and observer.
<?php
class Post extends Model {
protected static function booted(): void {
static::addGlobalScope("published", fn(Builder $q) => $q->where("status", "published"));
}
}
class PostObserver {
public function creating(Post $post): void {
$post->uuid = (string) Str::uuid();
}
}
FAQ
Mini Project: Eloquent Model Layer
Build a complete Eloquent model layer for a blog.
<?php
namespace App\Models;
use App\Observers\PostObserver;
use App\Http\Resources\PostResource;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
#[ObservedBy([PostObserver::class])]
class Post extends Model {
protected $fillable = ["title", "content", "status"];
protected $casts = ["published_at" => "datetime", "meta" => "array"];
protected static function booted(): void {
static::addGlobalScope("published", fn(Builder $q) => $q->where("status", "published"));
}
public function scopeRecent($query): void {
$query->orderBy("created_at", "desc")->limit(10);
}
}
What's Next
Eloquent Relations Deep Eloquent Query Scopes Eloquent Serialization
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro