$ lexprog.com

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

[June 12, 2026] Eloquent ORM

Eloquent Morph Map: Cleaner Type Names

Eloquent Morph Map: Cleaner Type Names

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

Eloquent Morph Map: Cleaner Type Names

Tip: Register Morph Map

Relation::enforceMorphMap([
    'post' => Post::class,
    'video' => Video::class,
    'page' => Page::class,
]);

Stores 'post' instead of 'App\Models\Post' in the database.

Gotcha: Enforce Morph Map

enforceMorphMap() throws an exception if a polymorphic relation is saved without a map entry. Use during development to catch missing mappings.

Tip: Migration Impact

Existing data with full class names won't match the map. Migrate old data or use a transitional approach.

Gotcha: Refactoring Safety

Without a morph map, renaming a class breaks all polymorphic references. With a map, only the map needs updating.

Tip: Querying with Morph Map

Comment::where('commentable_type', 'post')->get();

Use the map key, not the full class name.

Gotcha: Auto-Discovery Doesn't Use Map

When you save a new polymorphic relation, Laravel uses the map if registered. But raw queries bypass this.

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

Morph maps are essential for polymorphic relationships, but I've seen production databases where the morph type is the full class name (e.g., App\Models\User). This breaks when you rename or move models. Always define a morph map in AppServiceProvider::boot() and use short, stable names like 'user' or 'post'. A morph map is like a database migration — once it's in production, changing it is painful.

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

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