Register all models in the morph map + lock it with a test

Add the five automation models to Relation::enforceMorphMap(), document the
all-models-must-be-mapped rule in CLAUDE.md, and add MorphMapTest to fail
when any app/Models class is missing from the map.
This commit is contained in:
Paulo Castellano 2026-06-14 16:12:49 -03:00
parent f223cf14ce
commit 65116de859
3 changed files with 37 additions and 0 deletions

View file

@ -297,6 +297,12 @@ ## Array Data Access
- Example: `data_get($data, 'name')` instead of `$data['name']`.
- Use the third parameter for fallback values: `data_get($data, 'username', $sender->username)` instead of `$data['username'] ?? $sender->username`.
## Eloquent Models & Morph Map
- EVERY Eloquent model in `app/Models` MUST be registered in `Relation::enforceMorphMap([...])` inside `AppServiceProvider::configureMorphMap()`, keyed by a camelCase alias (e.g. `'postPlatform' => PostPlatform::class`).
- When you add a new model, add it to the morph map in the same change. `tests/Unit/MorphMapTest.php` fails if any model is missing.
- The alias is persisted in polymorphic columns, so never rename or remove an existing alias for a model that has stored rows.
## Imports
- NEVER use inline class references (e.g., `\DB::listen`, `\Str::uuid()`). ALWAYS import classes at the top of the file with a `use` statement.

View file

@ -8,6 +8,11 @@
use App\Models\AccessToken;
use App\Models\Account;
use App\Models\AiUsageLog;
use App\Models\Automation;
use App\Models\AutomationNodeRun;
use App\Models\AutomationNodeState;
use App\Models\AutomationRun;
use App\Models\AutomationTriggerItem;
use App\Models\Invite;
use App\Models\Media;
use App\Models\Notification;
@ -114,6 +119,11 @@ protected function configureMorphMap(): void
'accessToken' => AccessToken::class,
'account' => Account::class,
'aiUsageLog' => AiUsageLog::class,
'automation' => Automation::class,
'automationNodeRun' => AutomationNodeRun::class,
'automationNodeState' => AutomationNodeState::class,
'automationRun' => AutomationRun::class,
'automationTriggerItem' => AutomationTriggerItem::class,
'invite' => Invite::class,
'media' => Media::class,
'notification' => Notification::class,

View file

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
test('every Eloquent model is registered in the morph map', function () {
$mapped = array_values(Relation::morphMap());
$missing = collect(glob(app_path('Models/*.php')))
->map(fn (string $file): string => 'App\\Models\\'.pathinfo($file, PATHINFO_FILENAME))
->filter(fn (string $class): bool => class_exists($class)
&& is_subclass_of($class, Model::class)
&& ! (new ReflectionClass($class))->isAbstract())
->reject(fn (string $class): bool => in_array($class, $mapped, true))
->values()
->all();
expect($missing)->toBe([]);
});