| name | laravel-expert |
| description | Laravel/PHP gotchas and decision criteria. Covers N+1 prevention, Eloquent traps, and migration safety. |
| autoInvoke | false |
| priority | high |
| triggers | ["laravel","php","eloquent","artisan"] |
| paths | ["**/*.php","composer.json","artisan","config/*.php"] |
| allowed-tools | Read, Grep, Glob, Edit, Write |
| user-invocable | false |
AI-consumed reference. Optimized for Claude to read during execution.
Human-readable explanation: see docs/architecture/HIERARCHICAL_PLANNING.md
or docs/getting-started/ depending on topic.
Laravel Expert — Gotchas & Decisions
Use Context7 for full Laravel docs.
Key Decisions
decisions[4]{choice,use_when}:
Form Request vs inline,"Form Request for reusable validation. Inline for one-off simple checks"
Service vs Action class,"Service for stateless business logic. Action (single __invoke) for discrete operations"
Event/Listener vs direct,"Events for decoupling (notifications/logging). Direct for tightly coupled ops"
Eloquent vs Query Builder,"Eloquent for domain models with relationships. Query Builder for reports/bulk ops"
Gotchas
- N+1: always
with() eager load. Use preventLazyLoading() in AppServiceProvider to catch in dev
readonly DTOs (PHP 8.2+): readonly class UserData { public function __construct(public string $name) {} }
updateOrCreate is NOT atomic — race condition possible. Use DB transaction for critical ops
$model->save() returns bool, not the model — don't chain. Model::create() returns the model
- Mass assignment:
$fillable whitelist or $guarded = [] (never use $guarded = [] with user input)
firstOrFail() throws ModelNotFoundException (404). first() returns null silently
- Queue jobs: always implement
ShouldQueue. Without it, runs synchronously despite dispatch()
Carbon::now() in tests: use $this->travel() or Carbon::setTestNow() for deterministic tests
- Migrations: never edit a deployed migration. Create new migration for changes