$ lexprog.com

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

[June 12, 2025] Eloquent ORM

Eloquent Morph To Many: Polymorphic Relations

Eloquent Morph To Many: Polymorphic Relations

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

Eloquent Morph To Many: Polymorphic Relations

Tip: Define MorphToMany

class Tag extends Model
{
    public function posts(): MorphToMany
    {
        return $this->morphedByMany(Post::class, 'taggable');
    }
}

Gotcha: Inverse Relation

class Post extends Model
{
    public function tags(): MorphToMany
    {
        return $this->morphToMany(Tag::class, 'taggable');
    }
}

Tip: Attach Tags

$post->tags()->attach([1, 2, 3]);

Gotcha: Pivot Table Structure

taggables: tag_id, taggable_id, taggable_type

Tip: Query by Tag

Post::whereHas('tags', fn($q) => $q->where('name', 'laravel'))->get();

Gotcha: Morph Map with Many-to-Many

Register morph map for cleaner type names in the pivot table.

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

Eloquent relationships are elegant, but they hide database queries that can silently destroy performance. I once optimized an API endpoint by replacing 47 lazy-loaded relationship calls with two eager-loaded with() statements — response time dropped from 12 seconds to 200ms. The Laravel ecosystem has Model::preventLazyLoading(), and I always enable it in local and staging environments. If a relationship isn't eager-loaded, you'll know immediately.

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

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