Eloquent Accessors and Mutators
Eloquent Accessors & Mutators: Tips & Tricks
Eloquent Accessors & Mutators: Tips & Tricks
Tip: Use the New Attribute Syntax
protected function name(): Attribute
{
return Attribute::make(
get: fn($value) => ucfirst($value),
set: fn($value) => strtolower($value),
);
}
Replaces the old getNameAttribute() / setNameAttribute() methods.
Gotcha: Accessors Run on Every Access
$post->title; // Accessor runs
$post->title; // Accessor runs again (not cached)
For expensive computations, cache the result.
Tip: Computed (Virtual) Attributes
protected function fullName(): Attribute
{
return Attribute::make(
get: fn() => "{$this->first_name} {$this->last_name}",
);
}
No database column needed.
Gotcha: Accessors Break where() Clauses
// Accessor makes name uppercase
$post->name; // "John"
// But this searches the raw DB value
User::where('name', 'John')->get(); // Won't find "john" in DB
Tip: Cast to Custom Classes
protected $casts = [
'address' => AddressCast::class,
];
Tip: Date Casting
protected $casts = [
'published_at' => 'datetime',
'birthday' => 'date',
];
Automatically converts to Carbon instances.
Gotcha: toArray() Includes Accessors
When you call $model->toArray(), accessors are applied. This can be surprising if the accessor transforms data.
Tip: Encrypted Casting
protected $casts = [
'ssn' => 'encrypted',
'secrets' => 'encrypted:array',
];
Data is encrypted at rest, decrypted on access.
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
Accessors and mutators are where the line between Eloquent model and business logic blurs dangerously. I've seen accessors that make database queries, call external APIs, and even send emails — all triggered by simply accessing a property. My rule: an accessor should format data, not fetch it. If you need computed data that requires database lookups, use a dedicated method or a repository. Properties should feel like properties, not method calls.
Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)