Eloquent Dynamic Scopes: Reusable Queries
Eloquent Dynamic Scopes: Reusable Queries
Eloquent Dynamic Scopes: Reusable Queries
Tip: Scopes with Parameters
public function scopeOfType(Builder $query, string $type): Builder
{
return $query->where('type', $type);
}
Post::ofType('article')->get();
Gotcha: First Parameter is Always Builder
public function scopeActive(Builder $query, $status = true): Builder
{
return $query->where('active', $status);
}
The builder is injected automatically.
Tip: Chain Multiple Scopes
Post::published()->featured()->recent()->get();
Each scope returns the builder, enabling fluent chaining.
Gotcha: Scopes in Relationships
public function publishedPosts(): HasMany
{
return $this->hasMany(Post::class)->published();
}
Scopes work on relationship queries too.
Tip: Global Scopes for Tenancy
static::addGlobalScope('tenant', function (Builder $builder) {
$builder->where('tenant_id', auth()->user()->tenant_id);
});
Every query automatically filters by tenant.
Gotcha: Removing Global Scopes
Post::withoutGlobalScope('tenant')->get();
Post::withoutGlobalScopes()->get(); // Remove all
Tip: Use cursor() for Memory-Neutral Iteration
When exporting 100K rows, get() loads everything into memory. cursor() uses yield and keeps memory flat regardless of row count. Perfect for artisan commands.
Tip: whereHas() vs load() — Two Different Things
whereHas() filters the parent query by relationship existence. load() eager-loads relationships AFTER the query. Mixing them up is a common source of logic bugs.
Gotcha: withCount() Adds a Subquery
withCount('comments') runs a correlated subquery on every row. On large tables, this can be slower than a separate query. Profile before relying on it.
Senior Insight
Dynamic scopes are a clean way to parameterize query filters, but I've seen them abused as a substitute for proper query builder usage. A scope that accepts five optional parameters with complex default logic is a maintenance burden. If your scope needs more than two parameters, it's probably a method on a repository or a query builder macro. Scopes should make queries more readable, not less.
Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)