eloquent
When to use
Use when creating/modifying Eloquent models, relationships, scopes, or writing database queries.
Do NOT use when:
- Schema design or query optimization (use
databaseskill) - Creating migrations only (use
laravel-migrationskill)
Procedure: Create or modify a model
Step 0: Inspect
- Check existing models — match property declarations, cast patterns, relationship style, scope naming.
- Check for repositories — some projects use repository interfaces.
- Understand the schema — check migrations for column names, types, constraints.
- Check for multi-tenancy — which
$connectionto use?
Step 1: Read attribute access style
Read eloquent.access_style from .agent-settings.yml. Default: getters_setters.
| Value | Inside model | Outside model |
|---|---|---|
getters_setters |
getAttribute() / setAttribute() |
Typed getters/setters |
get_attribute |
getAttribute() / setAttribute() |
Same |
magic_properties |
$this->column |
$model->column |
→ See guideline php/eloquent.md and php-coding rule for full conventions.
Step 2: Build the model
- Set
$connection,$table,$fillable/$guarded,$casts,$attributes(defaults). - Add typed getters + fluent setters for each attribute (if
getters_settersstyle). - Add relationship getter above each relationship method.
- Add scopes for reusable query constraints.
- Register Observer via
#[ObservedBy]— never usebooted().
Step 3: Write queries
- Always eager load relationships accessed in loops:
->with(['customer']). - Always paginate list queries:
->paginate(15). - Use
exists()overcount() > 0. - Use
chunk()/lazy()for large datasets. - Constrain eager loads when only a subset is needed.
Conventions
→ See guideline php/eloquent.md for getter/setter examples, relationship getters, observers, casts.
→ See guideline php/database.md for indexing, transactions, migrations.
Validate
- Run PHPStan on model — must pass.
- Verify no N+1: check that all relationship access in loops uses eager loading.
- Confirm typed getters exist for every relationship.
- Run affected tests — must pass.
Output format
- Model class with typed getters/setters, relationships, and observer
- Migration file if schema changes are needed
Gotcha
- Never access relationships via magic properties — always use typed getter.
- N+1 queries are the #1 performance issue — always eager load.
getAttribute()returnsmixed— cast or type-check the result.$model->save()can silently fail without fillable/guarded config.
Do NOT
- Do NOT put business logic in models — delegate to services.
- Do NOT access relationships in loops without eager loading.
- Do NOT use
Model::all()without pagination on list endpoints. - Do NOT use
booted()for lifecycle hooks — use Observers with#[ObservedBy].
Auto-trigger keywords
- Eloquent
- model
- relationship
- scope
- accessor
- mutator