> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Attributi PHP dei controller

> Come usare gli attributi #[Middleware], #[WithoutMiddleware] e #[Authorize] introdotti in Laravel 13 per configurare in modo dichiarativo middleware e autorizzazione dei controller.

## Panoramica

In Laravel 13 puoi dichiarare l'assegnazione dei middleware e i controlli di autorizzazione sui controller tramite attributi PHP. Al posto del tradizionale metodo `middleware()` o del middleware `can`, basta applicare gli attributi direttamente alla classe o al metodo per completare la configurazione.

```php theme={null}
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class PostController
{
    #[Middleware('subscribed')]
    #[Authorize('create', Post::class)]
    public function store(Request $request): Response
    {
        // ...
    }
}
```

<Tip>
  Tutti gli attributi dei controller si trovano nel namespace `Illuminate\Routing\Attributes\Controllers`.
</Tip>

## `#[Middleware]` — assegnare i middleware

### Applicazione alla classe

Applicando `#[Middleware]` a livello di classe, il middleware viene applicato a tutte le action di quel controller.

```php theme={null}
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class UserController
{
    public function index(): View { /* ... */ }
    public function show(User $user): View { /* ... */ }
    public function store(Request $request): Response { /* ... */ }
}
```

Per assegnare più middleware, ripeti l'attributo.

```php theme={null}
#[Middleware('auth')]
#[Middleware('verified')]
class ProfileController
{
    // ...
}
```

### Applicazione al metodo

I middleware applicati a livello di metodo vengono uniti a quelli a livello di classe.

```php theme={null}
#[Middleware('auth')]
class UserController
{
    // solo auth per tutti
    public function index(): View { /* ... */ }

    // viene applicato sia auth che subscribed
    #[Middleware('subscribed')]
    public function create(): View { /* ... */ }
}
```

### Restringere con `only` / `except`

Se specifichi `only` o `except` sull'attributo a livello di classe, puoi restringere i metodi coinvolti.

```php theme={null}
#[Middleware('auth')]
#[Middleware('subscribed', only: ['create', 'store', 'edit', 'update'])]
class ArticleController
{
    // solo auth
    public function index(): View { /* ... */ }
    public function show(Article $article): View { /* ... */ }

    // auth + subscribed
    public function create(): View { /* ... */ }
    public function store(Request $request): Response { /* ... */ }
    public function edit(Article $article): View { /* ... */ }
    public function update(Request $request, Article $article): Response { /* ... */ }

    // solo auth (equivalente a essere escluso da except)
    public function destroy(Article $article): Response { /* ... */ }
}
```

### Middleware come closure

Gli attributi accettano anche le closure. Utile quando vuoi scrivere la logica inline.

```php theme={null}
use Closure;
use Illuminate\Http\Request;
use Illuminate\Routing\Attributes\Controllers\Middleware;

class ReportController
{
    #[Middleware(static function (Request $request, Closure $next) {
        if (! $request->user()->hasRole('analyst')) {
            abort(403);
        }

        return $next($request);
    })]
    public function generate(): Response
    {
        // ...
    }
}
```

### Confronto con il tradizionale metodo `middleware()`

```php theme={null}
// scrittura tradizionale (implementando l'interfaccia HasMiddleware)
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

class UserController implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('log', only: ['index']),
            new Middleware('subscribed', except: ['store']),
        ];
    }
}

// scrittura con attributi
#[Middleware('auth')]
#[Middleware('log', only: ['index'])]
#[Middleware('subscribed', except: ['store'])]
class UserController
{
    // non serve implementare HasMiddleware
}
```

<Info>
  Se usi gli attributi non è necessario implementare l'interfaccia `HasMiddleware`. Tuttavia, mescolare il metodo `middleware()` con gli attributi può portare a comportamenti inattesi, per cui è consigliato scegliere uno solo dei due approcci.
</Info>

## `#[WithoutMiddleware]` — escludere middleware

Esclude un middleware applicato a livello di classe da un metodo specifico o dall'intera classe.

### Applicazione al metodo

```php theme={null}
use App\Http\Middleware\EnsureTokenIsValid;
use Illuminate\Routing\Attributes\Controllers\Middleware;
use Illuminate\Routing\Attributes\Controllers\WithoutMiddleware;

#[Middleware('auth')]
#[Middleware(EnsureTokenIsValid::class)]
class ApiController
{
    // vengono applicati auth e EnsureTokenIsValid
    public function show(Resource $resource): JsonResponse { /* ... */ }

    // auth viene applicato ma EnsureTokenIsValid viene escluso
    #[WithoutMiddleware(EnsureTokenIsValid::class)]
    public function index(): JsonResponse { /* ... */ }
}
```

### Applicazione alla classe e `only` / `except`

Applicando `#[WithoutMiddleware]` a livello di classe, il middleware viene escluso da tutte le action, incluse quelle delle classi figlie. Con `only` / `except` puoi limitare l'ambito dell'esclusione.

```php theme={null}
#[Middleware('auth')]
#[WithoutMiddleware('subscribed', except: ['index'])]
class AdminController
{
    // subscribed viene applicato (non è escluso grazie a except: ['index'])
    public function index(): View { /* ... */ }

    // subscribed viene escluso
    public function dashboard(): View { /* ... */ }
    public function settings(): View { /* ... */ }
}
```

<Warning>
  `#[WithoutMiddleware]` funziona solo con i **middleware di route**. I middleware globali registrati in `app/Http/Kernel.php` non possono essere esclusi.
</Warning>

## `#[Authorize]` — autorizzazione tramite policy

Come sintassi zuccherata per il middleware `can`, puoi dichiarare i controlli di autorizzazione basati su policy tramite attributi.

### Uso di base

```php theme={null}
use App\Models\Post;
use Illuminate\Routing\Attributes\Controllers\Authorize;

class PostController
{
    // verifica la ability 'viewAny' (metodo viewAny della policy Post)
    #[Authorize('viewAny', Post::class)]
    public function index(): View { /* ... */ }

    // verifica la ability 'view' (passa il parametro di route 'post')
    #[Authorize('view', 'post')]
    public function show(Post $post): View { /* ... */ }

    // verifica la ability 'create'
    #[Authorize('create', Post::class)]
    public function create(): View { /* ... */ }

    #[Authorize('create', Post::class)]
    public function store(Request $request): Response { /* ... */ }

    // verifica la ability 'update' (passa il parametro di route)
    #[Authorize('update', 'post')]
    public function edit(Post $post): View { /* ... */ }

    #[Authorize('update', 'post')]
    public function update(Request $request, Post $post): Response { /* ... */ }

    #[Authorize('delete', 'post')]
    public function destroy(Post $post): Response { /* ... */ }
}
```

### Argomenti della policy

Come secondo argomento puoi passare:

| Valore passato             | Descrizione                                                                     |
| -------------------------- | ------------------------------------------------------------------------------- |
| `Post::class`              | Classe del modello (quando non serve un'istanza, come per `viewAny`)            |
| `'post'`                   | Nome del parametro di route (viene passata l'istanza risolta dal model binding) |
| `[Comment::class, 'post']` | Più argomenti (vengono passati al metodo della policy come array)               |

```php theme={null}
use App\Models\Comment;
use App\Models\Post;
use Illuminate\Routing\Attributes\Controllers\Authorize;

class CommentController
{
    // passa $post (parametro di route) e la classe Comment alla policy
    #[Authorize('create', [Comment::class, 'post'])]
    public function store(Post $post, Request $request): Response
    {
        // ...
    }

    #[Authorize('delete', 'comment')]
    public function destroy(Comment $comment): Response
    {
        // ...
    }
}
```

### Confronto con il middleware `can`

```php theme={null}
// scrittura tradizionale (facade Route)
Route::get('/posts', [PostController::class, 'index'])->middleware('can:viewAny,App\Models\Post');
Route::put('/posts/{post}', [PostController::class, 'update'])->middleware('can:update,post');

// scrittura con attributi
class PostController
{
    #[Authorize('viewAny', Post::class)]
    public function index(): View { /* ... */ }

    #[Authorize('update', 'post')]
    public function update(Request $request, Post $post): Response { /* ... */ }
}
```

Non serve più scrivere il middleware nel file di route e la logica di autorizzazione viene centralizzata nel controller.

## Esempi pratici

### Applicazione ai resource controller

```php theme={null}
use App\Models\Article;
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class ArticleController
{
    #[Authorize('viewAny', Article::class)]
    public function index(): View
    {
        return view('articles.index', [
            'articles' => Article::paginate(),
        ]);
    }

    #[Authorize('view', 'article')]
    public function show(Article $article): View
    {
        return view('articles.show', compact('article'));
    }

    #[Authorize('create', Article::class)]
    public function create(): View
    {
        return view('articles.create');
    }

    #[Authorize('create', Article::class)]
    public function store(StoreArticleRequest $request): RedirectResponse
    {
        $article = Article::create($request->validated());

        return redirect()->route('articles.show', $article);
    }

    #[Authorize('update', 'article')]
    public function edit(Article $article): View
    {
        return view('articles.edit', compact('article'));
    }

    #[Authorize('update', 'article')]
    public function update(UpdateArticleRequest $request, Article $article): RedirectResponse
    {
        $article->update($request->validated());

        return redirect()->route('articles.show', $article);
    }

    #[Authorize('delete', 'article')]
    public function destroy(Article $article): RedirectResponse
    {
        $article->delete();

        return redirect()->route('articles.index');
    }
}
```

### Applicazione ai controller API

```php theme={null}
use Illuminate\Routing\Attributes\Controllers\Middleware;
use Illuminate\Routing\Attributes\Controllers\WithoutMiddleware;

#[Middleware('auth:sanctum')]
#[Middleware('throttle:api')]
class ApiPostController
{
    // l'elenco può essere ottenuto senza autenticazione
    #[WithoutMiddleware('auth:sanctum')]
    public function index(): JsonResponse
    {
        return response()->json(Post::paginate());
    }

    public function store(Request $request): JsonResponse
    {
        // solo utenti autenticati
    }
}
```

## Ordine di elaborazione degli attributi

Quando sono applicati più attributi, l'ordine di elaborazione è il seguente.

```mermaid theme={null}
flowchart LR
    A["Richiesta"] --> B["#[Middleware]<br>a livello di classe"]
    B --> C["#[Middleware]<br>a livello di metodo"]
    C --> D["Esclusione tramite<br>#[WithoutMiddleware]"]
    D --> E["Controllo di autorizzazione<br>#[Authorize]"]
    E --> F["Esecuzione del metodo<br>del controller"]
```

<Info>
  `#[Authorize]` funziona internamente come middleware `can`, quindi viene elaborato nella stessa pipeline di `#[Middleware]`.
</Info>

## Riepilogo: quale scegliere?

| Situazione                                       | Approccio consigliato                     |
| ------------------------------------------------ | ----------------------------------------- |
| Nuovo controller (Laravel 13)                    | Usa gli attributi                         |
| Controller esistente con metodo `middleware()`   | Migra gradualmente agli attributi         |
| Configurazione dinamica dei middleware           | Continua a usare il metodo `middleware()` |
| Vuoi la gestione centralizzata nel file di route | Continua a usare `Route::middleware()`    |

## Prossimi passi

<Columns cols={2}>
  <Card title="Attributi PHP (code / Eloquent)" icon="code" href="/it/advanced/php-attributes">
    Guida agli attributi PHP utilizzabili per i job in coda e i modelli Eloquent.
  </Card>

  <Card title="Intermedio: Controller" icon="layer-group" href="/it/controllers">
    Impara l'uso di base dei controller di Laravel.
  </Card>
</Columns>


## Related topics

- [Attributi PHP](/it/advanced/php-attributes.md)
- [Riepilogo delle novità di Laravel 13](/it/blog/laravel-13-new-features.md)
- [Controller](/it/controllers.md)
- [Aggiornamenti Laravel di marzo 2026](/it/blog/changelog/202603.md)
- [Accessor, mutator e cast di Eloquent](/it/eloquent-mutators.md)
