Laravel 13 PHP Attributes
Agent Workflow (MANDATORY)
Before ANY implementation, spawn 3 agents in parallel, one Agent call each with a name:
- fuse-ai-pilot:explore-codebase - Scan existing models/jobs/controllers for legacy
protected $fillable / $hidden / $connection properties to convert
- fuse-ai-pilot:research-expert - Verify Laravel 13 release notes for attribute coverage and edge cases
- mcp__context7__query-docs - Pull authoritative examples from
laravel.com/docs/13.x
After implementation, run fuse-ai-pilot:sniper for validation.
Overview
| Category |
Attributes |
| Eloquent |
#[Table] #[Connection] #[Fillable] #[Hidden] #[Visible] #[Guarded] #[Unguarded] #[Appends] #[Touches] |
| Queue / Job |
#[Connection] #[Queue] #[Tries] #[Timeout] #[Backoff] #[MaxExceptions] #[FailOnTimeout] #[UniqueFor] |
| Console |
#[Signature] #[Description] |
| Controllers |
#[Middleware] #[Authorize] |
| Validation |
#[RedirectTo] #[StopOnFirstFailure] |
| API Resources |
#[Collects] #[PreserveKeys] |
| Factories / Seeders |
#[UseModel] #[Seed] #[Seeder] |
Critical Rules
- NEVER mix attributes and legacy properties -
#[Fillable(['name'])] + protected $fillable = [...] causes Laravel to ignore the attribute silently
- Class-level only - All Eloquent / Job / Controller attributes apply to the class, never to private/protected methods
- Single source of truth - Choose attributes OR properties per class; refactor in one pass to avoid drift
- Inheritance is additive - Child class attributes merge with parent attributes; redeclare to override
- Import the right namespace -
Illuminate\Database\Eloquent\Attributes\* for Eloquent, Illuminate\Queue\Attributes\* for Jobs
Architecture
app/
├── Models/
│ └── User.php # #[Table] #[Fillable] #[Hidden] #[Appends]
├── Jobs/
│ └── ProcessPodcast.php # #[Connection] #[Queue] #[Tries] #[Backoff]
├── Console/Commands/
│ └── SendEmails.php # #[Signature] #[Description]
├── Http/
│ ├── Controllers/
│ │ └── PostController.php # #[Middleware] #[Authorize]
│ └── Resources/
│ └── PostCollection.php # #[Collects] #[PreserveKeys]
└── Http/Requests/
└── StoreUserRequest.php # #[RedirectTo] #[StopOnFirstFailure]
→ See Model-with-attributes.php.md for full example
Reference Guide
| Topic |
Reference |
When to Consult |
| Eloquent models |
eloquent.md |
Migrating $fillable / $hidden / $table / $connection |
| Queue jobs |
queue.md |
Replacing $tries / $timeout / $backoff properties |
| Console commands |
console.md |
Refactoring $signature / $description properties |
| Controllers |
controllers.md |
Moving middleware/authorize from constructors |
| Validation |
validation.md |
FormRequest redirect + early-stop config |
| API Resources |
api-resources.md |
Collection wrapping and key preservation |
| Factories / Seeders |
factories-seeders.md |
Model binding and seeder discovery |
Templates
| Template |
When to Use |
| Model-with-attributes.php.md |
Net new Eloquent model |
| Job-with-attributes.php.md |
Net new queue Job |
Quick Reference
Eloquent model
use Illuminate\Database\Eloquent\Attributes\{Table, Fillable, Hidden, Appends};
#[Table('flights')]
#[Fillable(['name', 'origin'])]
#[Hidden(['password'])]
#[Appends(['is_admin'])]
class Flight extends Model {}
Queue job
use Illuminate\Queue\Attributes\{Connection, Queue, Tries, Backoff};
#[Connection('redis')]
#[Queue('podcasts')]
#[Tries(5)]
#[Backoff([10, 30, 60])]
class ProcessPodcast implements ShouldQueue {}
→ See Job-with-attributes.php.md for complete example
Best Practices
DO
- Convert one class at a time and run tests between commits
- Keep attribute imports grouped at the top via PHP 8.1 grouped
use syntax
- Use
#[Fillable] for mass-assigned models and #[Unguarded] only on trusted internal models
- Combine
#[Connection] + #[Queue] on Jobs to centralize routing intent
DON'T
- Don't mix
#[Fillable(['x'])] with protected $fillable = ['y'] - the property silently wins on some setups, the attribute on others
- Don't place Eloquent/Job attributes on methods - they target the class only
- Don't put
#[Authorize] on a controller without an underlying Policy registered in AuthServiceProvider
- Don't forget to drop the legacy
$tries, $backoff, $timeout properties after adding the attributes - duplication is a red flag for code review
1---2name: laravel-attributes3description: Use when migrating Eloquent models, Jobs, Console commands, Controllers, API Resources, Validation, Factories or Seeders to Laravel 13 PHP attributes.4---56<objective>7Covers all 7 categories of Laravel 13 first-party PHP 8.3 attributes that8replace legacy class properties: Eloquent (#[Table], #[Fillable], #[Hidden],9#[Guarded], #[Appends], #[Touches], #[Connection]), Queue/Job (#[Connection],10#[Queue], #[Tries], #[Timeout], #[Backoff], #[MaxExceptions],11#[FailOnTimeout], #[UniqueFor]), Console (#[Signature], #[Description]),12Controllers (#[Middleware], #[Authorize]), Validation (#[RedirectTo],13#[StopOnFirstFailure]), API Resources (#[Collects], #[PreserveKeys]), and14Factories/Seeders (#[UseModel], #[Seed], #[Seeder]).15</objective>1617# Laravel 13 PHP Attributes1819## Agent Workflow (MANDATORY)2021Before ANY implementation, spawn 3 agents in parallel, one `Agent` call each with a `name`:22231. **fuse-ai-pilot:explore-codebase** - Scan existing models/jobs/controllers for legacy `protected $fillable / $hidden / $connection` properties to convert242. **fuse-ai-pilot:research-expert** - Verify Laravel 13 release notes for attribute coverage and edge cases253. **mcp__context7__query-docs** - Pull authoritative examples from `laravel.com/docs/13.x`2627After implementation, run **fuse-ai-pilot:sniper** for validation.2829---3031## Overview3233| Category | Attributes |34|---------|-------------|35| **Eloquent** | `#[Table]` `#[Connection]` `#[Fillable]` `#[Hidden]` `#[Visible]` `#[Guarded]` `#[Unguarded]` `#[Appends]` `#[Touches]` |36| **Queue / Job** | `#[Connection]` `#[Queue]` `#[Tries]` `#[Timeout]` `#[Backoff]` `#[MaxExceptions]` `#[FailOnTimeout]` `#[UniqueFor]` |37| **Console** | `#[Signature]` `#[Description]` |38| **Controllers** | `#[Middleware]` `#[Authorize]` |39| **Validation** | `#[RedirectTo]` `#[StopOnFirstFailure]` |40| **API Resources** | `#[Collects]` `#[PreserveKeys]` |41| **Factories / Seeders** | `#[UseModel]` `#[Seed]` `#[Seeder]` |4243---4445## Critical Rules46471. **NEVER mix attributes and legacy properties** - `#[Fillable(['name'])]` + `protected $fillable = [...]` causes Laravel to ignore the attribute silently482. **Class-level only** - All Eloquent / Job / Controller attributes apply to the class, never to private/protected methods493. **Single source of truth** - Choose attributes OR properties per class; refactor in one pass to avoid drift504. **Inheritance is additive** - Child class attributes merge with parent attributes; redeclare to override515. **Import the right namespace** - `Illuminate\Database\Eloquent\Attributes\*` for Eloquent, `Illuminate\Queue\Attributes\*` for Jobs5253---5455## Architecture5657```58app/59├── Models/60│ └── User.php # #[Table] #[Fillable] #[Hidden] #[Appends]61├── Jobs/62│ └── ProcessPodcast.php # #[Connection] #[Queue] #[Tries] #[Backoff]63├── Console/Commands/64│ └── SendEmails.php # #[Signature] #[Description]65├── Http/66│ ├── Controllers/67│ │ └── PostController.php # #[Middleware] #[Authorize]68│ └── Resources/69│ └── PostCollection.php # #[Collects] #[PreserveKeys]70└── Http/Requests/71 └── StoreUserRequest.php # #[RedirectTo] #[StopOnFirstFailure]72```7374→ See [Model-with-attributes.php.md](references/templates/Model-with-attributes.php.md) for full example7576---7778## Reference Guide7980| Topic | Reference | When to Consult |81|-------|-----------|-----------------|82| **Eloquent models** | [eloquent.md](references/eloquent.md) | Migrating `$fillable / $hidden / $table / $connection` |83| **Queue jobs** | [queue.md](references/queue.md) | Replacing `$tries / $timeout / $backoff` properties |84| **Console commands** | [console.md](references/console.md) | Refactoring `$signature / $description` properties |85| **Controllers** | [controllers.md](references/controllers.md) | Moving middleware/authorize from constructors |86| **Validation** | [validation.md](references/validation.md) | FormRequest redirect + early-stop config |87| **API Resources** | [api-resources.md](references/api-resources.md) | Collection wrapping and key preservation |88| **Factories / Seeders** | [factories-seeders.md](references/factories-seeders.md) | Model binding and seeder discovery |8990### Templates9192| Template | When to Use |93|----------|-------------|94| [Model-with-attributes.php.md](references/templates/Model-with-attributes.php.md) | Net new Eloquent model |95| [Job-with-attributes.php.md](references/templates/Job-with-attributes.php.md) | Net new queue Job |9697---9899## Quick Reference100101### Eloquent model102103```php104use Illuminate\Database\Eloquent\Attributes\{Table, Fillable, Hidden, Appends};105106#[Table('flights')]107#[Fillable(['name', 'origin'])]108#[Hidden(['password'])]109#[Appends(['is_admin'])]110class Flight extends Model {}111```112113### Queue job114115```php116use Illuminate\Queue\Attributes\{Connection, Queue, Tries, Backoff};117118#[Connection('redis')]119#[Queue('podcasts')]120#[Tries(5)]121#[Backoff([10, 30, 60])]122class ProcessPodcast implements ShouldQueue {}123```124125→ See [Job-with-attributes.php.md](references/templates/Job-with-attributes.php.md) for complete example126127---128129## Best Practices130131### DO132- Convert one class at a time and run tests between commits133- Keep attribute imports grouped at the top via PHP 8.1 grouped `use` syntax134- Use `#[Fillable]` for mass-assigned models and `#[Unguarded]` only on trusted internal models135- Combine `#[Connection]` + `#[Queue]` on Jobs to centralize routing intent136137### DON'T138- Don't mix `#[Fillable(['x'])]` with `protected $fillable = ['y']` - the property silently wins on some setups, the attribute on others139- Don't place Eloquent/Job attributes on methods - they target the class only140- Don't put `#[Authorize]` on a controller without an underlying Policy registered in `AuthServiceProvider`141- Don't forget to drop the legacy `$tries`, `$backoff`, `$timeout` properties after adding the attributes - duplication is a red flag for code review