$ lexprog.com

// notes from an old coder -- php, databases, and the occasional rant

[April 18, 2026] Eloquent ORM

Eloquent Mass Assignment: Protection Patterns

Eloquent Mass Assignment: Protection Patterns

────────────────────────────────────────────────────────

Eloquent Mass Assignment: Protection Patterns

Tip: Use $fillable Explicitly

protected $fillable = ['title', 'content', 'published'];

Only listed fields can be mass-assigned via create() or update().

Gotcha: $guarded = [] is Dangerous

protected $guarded = []; // All fields are fillable

This allows users to set ANY field, including is_admin or role. Never use with user input.

Tip: fill() vs create()

$post = new Post();
$post->fill($data); // Doesn't save
$post->save();

fill() applies mass assignment rules without persisting.

Gotcha: forceFill() Bypasses Protection

$post->forceFill(['is_admin' => true])->save();

Use only in trusted contexts like seeders or migrations.

Tip: Dynamic Fillable

public function getFillable(): array
{
    return $this->isAdmin() ? ['*'] : ['title', 'content'];
}

Gotcha: update() on Existing Models

$post->update($request->all());

Only updates fillable fields. Non-fillable fields are silently ignored.

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

Mass assignment protection is one of Laravel's best security features, yet I still see $guarded = [] in production codebases. A single missing $fillable or $guarded definition can expose your entire database to mass assignment attacks via API payloads. I've made it a non-negotiable rule in every team I've led: all models must have explicit $fillable arrays, and $guarded = [] is never approved in code review.

Source: Laravel Docs (https://laravel.com/docs/eloquent), Laravel News (https://laravel-news.com/), Freek.dev (https://freek.dev/tags/eloquent)

────────────────────────────────────────────────────────
<-- back to posts