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

# Struttura dell'applicazione da Laravel 11

> Panoramica completa dello Slim Application Skeleton introdotto in Laravel 11 e implementazione interna da Application::configure() ad ApplicationBuilder.

## Confronto con Laravel 10 e precedenti

Con Laravel 11 la struttura dell'applicazione è stata rinnovata in modo profondo, sotto il nome di "Slim Application Skeleton". Il cambiamento più grande è la fine della dispersione della configurazione: tutto confluisce in un unico `bootstrap/app.php`.

| Elemento          | Prima di Laravel 10               | Da Laravel 11                                |
| ----------------- | --------------------------------- | -------------------------------------------- |
| Kernel HTTP       | `app/Http/Kernel.php`             | Rimosso (integrato nel framework)            |
| Kernel Console    | `app/Console/Kernel.php`          | Rimosso (spostato in `routes/console.php`)   |
| Exception handler | `app/Exceptions/Handler.php`      | Rimosso (concentrato in `bootstrap/app.php`) |
| Service provider  | 5 file                            | Un solo `AppServiceProvider.php`             |
| File delle rotte  | `web.php` / `api.php` di default  | Solo `web.php` di default, `api.php` opt-in  |
| Bootstrap         | Configurazione sparsa su più file | Concentrata in `bootstrap/app.php`           |
| DB di default     | MySQL/PostgreSQL                  | SQLite                                       |

<Info>
  Il cambiamento riguarda i **nuovi progetti**. L'aggiornamento di app Laravel 10 esistenti mantiene funzionante la vecchia struttura.
</Info>

## Nuova struttura di directory e file

### Struttura dello skeleton

```
laravel-app/
├── app/
│   ├── Http/
│   │   └── Controllers/
│   ├── Models/
│   │   └── User.php
│   └── Providers/
│       └── AppServiceProvider.php
├── bootstrap/
│   ├── app.php          ← centro della configurazione dell'applicazione
│   ├── cache/
│   └── providers.php    ← elenco dei service provider
├── config/
├── database/
├── public/
│   └── index.php        ← entry point
├── resources/
├── routes/
│   ├── web.php          ← rotte web (default)
│   └── console.php      ← comandi Artisan e schedule
├── storage/
└── tests/
```

### `bootstrap/app.php` — il centro della configurazione

```php theme={null}
<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        //
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();
```

In questo unico file configuri routing, middleware e gestione delle eccezioni. Ciò che in Laravel 10 era diviso tra `app/Http/Kernel.php`, `app/Console/Kernel.php` e `app/Exceptions/Handler.php` è ora concentrato qui.

### `bootstrap/providers.php` — elenco dei service provider

```php theme={null}
<?php

use App\Providers\AppServiceProvider;

return [
    AppServiceProvider::class,
];
```

Questo è il file dove si registrano i service provider. In Laravel 10 lo indicavi nell'array `providers` di `config/app.php`: ora è stato spostato in `bootstrap/providers.php`. Nel default di Laravel 11 c'è solo `AppServiceProvider`.

<Tip>
  Installando pacchetti con `composer require`, il pacchetto può aggiornare automaticamente `bootstrap/providers.php`. `config/app.php` non è ignorato, ma per nuove registrazioni il posto consigliato è ora `bootstrap/providers.php`.
</Tip>

### Cambiamenti nella directory `routes/`

```
routes/
├── web.php      ← rotte web (caricate di default)
└── console.php  ← comandi Artisan e schedule
```

`api.php` e `channels.php` non ci sono di default. Li generi al bisogno con comandi Artisan.

```shell theme={null}
# aggiunge le rotte API (api.php + installa Sanctum)
php artisan install:api

# aggiunge il broadcasting (channels.php + installazione di Reverb, ecc.)
php artisan install:broadcasting
```

In `routes/console.php` definisci anche lo schedule.

```php theme={null}
<?php

use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;

Artisan::command('inspire', function () {
    $this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');

Schedule::command('emails:send')->daily();
```

### File rimossi

<AccordionGroup>
  <Accordion title="Rimozione di app/Http/Kernel.php">
    Il Kernel HTTP è stato integrato in `Illuminate\Foundation\Http\Kernel`. La personalizzazione dei middleware si fa in `bootstrap/app.php` con `withMiddleware()`.

    ```php theme={null}
    // Laravel 10 e precedenti: app/Http/Kernel.php
    protected $middleware = [
        \Illuminate\Http\Middleware\TrustProxies::class,
        // ...
    ];

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            // ...
        ],
    ];
    ```

    ```php theme={null}
    // da Laravel 11: bootstrap/app.php
    ->withMiddleware(function (Middleware $middleware) {
        $middleware->web(append: [
            EnsureUserIsSubscribed::class,
        ]);

        $middleware->validateCsrfTokens(except: ['stripe/*']);
    })
    ```
  </Accordion>

  <Accordion title="Rimozione di app/Console/Kernel.php">
    I due ruoli del Kernel della console sono stati separati. I comandi Artisan vanno in `app/Console/Commands/` (auto-scoperti), lo schedule si scrive in `routes/console.php`.

    ```php theme={null}
    // Laravel 10 e precedenti: app/Console/Kernel.php
    protected function schedule(Schedule $schedule): void
    {
        $schedule->command('emails:send')->daily();
    }
    ```

    ```php theme={null}
    // da Laravel 11: routes/console.php
    use Illuminate\Support\Facades\Schedule;

    Schedule::command('emails:send')->daily();
    ```
  </Accordion>

  <Accordion title="Rimozione di app/Exceptions/Handler.php">
    L'exception handler è stato integrato in `Illuminate\Foundation\Exceptions\Handler`. La personalizzazione si fa in `bootstrap/app.php` con `withExceptions()`.

    ```php theme={null}
    // Laravel 10 e precedenti: app/Exceptions/Handler.php
    public function register(): void
    {
        $this->reportable(function (InvalidOrderException $e) {
            // ...
        });
    }
    ```

    ```php theme={null}
    // da Laravel 11: bootstrap/app.php
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->report(function (InvalidOrderException $e) {
            // ...
        });
    })
    ```
  </Accordion>
</AccordionGroup>

## Come funziona `Application::configure()`

### Implementazione interna nel framework

`Application::configure()` è un metodo statico di `Illuminate\Foundation\Application`.

```php theme={null}
// da Illuminate\Foundation\Application
public static function configure(?string $basePath = null)
{
    $basePath = match (true) {
        is_string($basePath) => $basePath,
        default => static::inferBasePath(),
    };

    return (new Configuration\ApplicationBuilder(new static($basePath)))
        ->withKernels()
        ->withEvents()
        ->withCommands()
        ->withProviders();
}
```

Il metodo esegue questi passaggi.

1. Determina la root dell'app da `basePath`
2. Crea l'istanza `Application`
3. La avvolge con `ApplicationBuilder` applicando le configurazioni di default
4. Restituisce l'istanza `ApplicationBuilder`

Un dettaglio importante: **`withKernels()` / `withEvents()` / `withCommands()` / `withProviders()` sono già stati chiamati** dentro `configure()`. Non serve richiamarli in `bootstrap/app.php`.

### Flusso di configurazione tramite method chain

```php theme={null}
Application::configure(basePath: dirname(__DIR__))  // restituisce ApplicationBuilder
    ->withRouting(...)       // configura il routing e restituisce $this
    ->withMiddleware(...)    // configura i middleware e restituisce $this
    ->withExceptions(...)    // configura le eccezioni e restituisce $this
    ->create();              // restituisce l'istanza Application
```

Con la chiamata a `create()` viene estratta l'istanza `Application` dal `ApplicationBuilder`: è questa istanza che `bootstrap/app.php` restituisce.

## Dal ricevimento della richiesta all'avvio dell'app

```mermaid theme={null}
flowchart TD
    A["public/index.php<br>entry point"] --> B["require di bootstrap/app.php<br>ottieni Application"]
    B --> C["Application::configure()<br>crea ApplicationBuilder"]
    C --> D["withKernels()<br>registra HTTP/Console Kernel"]
    D --> E["withEvents()<br>configura event discovery"]
    E --> F["withCommands()<br>configura il path dei comandi Artisan"]
    F --> G["withProviders()<br>carica bootstrap/providers.php"]
    G --> H["withRouting()<br>configura il routing"]
    H --> I["withMiddleware()<br>configura i middleware"]
    I --> J["withExceptions()<br>configura la gestione eccezioni"]
    J --> K["create()<br>restituisce l'istanza Application"]
    K --> L["Il Kernel HTTP elabora la richiesta<br>middleware → router → controller"]
    L --> M["Restituisce la response"]
```

`public/index.php` è l'entry point: legge `bootstrap/app.php` e ottiene l'Application. Poi il Kernel HTTP fa passare la richiesta nella pipeline dei middleware e il router la dispatcha al controller.

## Approfondimento sui metodi principali di `ApplicationBuilder`

### `withRouting()` — processo interno di registrazione delle rotte

```php theme={null}
public function withRouting(
    ?Closure $using = null,
    array|string|null $web = null,
    array|string|null $api = null,
    ?string $commands = null,
    ?string $channels = null,
    ?string $pages = null,
    ?string $health = null,
    string $apiPrefix = 'api',
    ?callable $then = null
)
```

Internamente registra una callback in `AppRouteServiceProvider::loadRoutesUsing()` e registra `AppRouteServiceProvider` al booting dell'app.

```php theme={null}
// interno di withRouting() (versione semplificata)
protected function buildRoutingCallback(...)
{
    return function () use ($web, $api, $pages, $health, $apiPrefix, $then) {
        if (is_string($api) || is_array($api)) {
            Route::middleware('api')->prefix($apiPrefix)->group($api);
        }

        if (is_string($health)) {
            Route::get($health, function () {
                Event::dispatch(new DiagnosingHealth);
                return response(View::file(...), status: 200);
            });
        }

        if (is_string($web) || is_array($web)) {
            Route::middleware('web')->group($web);
        }

        if (is_callable($then)) {
            $then($this->app);
        }
    };
}
```

**Punti chiave:**

* Alle rotte `api` vengono applicati automaticamente il gruppo middleware `api` e il prefisso `/api`
* Se passi una stringa a `health`, viene registrato automaticamente l'endpoint di health check (default `/up`)
* Il path di `health` viene escluso anche durante la modalità di manutenzione (configurato in `PreventRequestsDuringMaintenance::except()`)
* Attenzione: `api` viene registrato prima di `web`. Se definisci lo stesso path in web e api, la rotta api ha priorità
* Passando una stringa a `pages` abiliti il routing di [Laravel Folio](https://github.com/laravel/folio)

### `withMiddleware()` — personalizzazione dei middleware

```php theme={null}
public function withMiddleware(?callable $callback = null)
{
    $this->app->afterResolving(HttpKernel::class, function ($kernel) use ($callback) {
        $middleware = (new Middleware)
            ->redirectGuestsTo(fn () => route('login'));

        if (! is_null($callback)) {
            $callback($middleware);
        }

        $kernel->setGlobalMiddleware($middleware->getGlobalMiddleware());
        $kernel->setMiddlewareGroups($middleware->getMiddlewareGroups());
        $kernel->setMiddlewareAliases($middleware->getMiddlewareAliases());
        // ...
    });

    return $this;
}
```

`withMiddleware()` esegue la callback **dopo** che `HttpKernel` è stato risolto: usa infatti l'hook `afterResolving()`. L'oggetto `Middleware` passato alla callback ha molti metodi di personalizzazione.

```php theme={null}
->withMiddleware(function (Middleware $middleware) {
    // aggiungi un middleware globale
    $middleware->append(MyGlobalMiddleware::class);

    // aggiungi al gruppo web
    $middleware->web(append: [EnsureUserIsSubscribed::class]);

    // sostituisci un middleware nel gruppo api
    $middleware->api(replace: [
        OldMiddleware::class => NewMiddleware::class,
    ]);

    // esclusioni CSRF
    $middleware->validateCsrfTokens(except: ['stripe/*', 'webhook/*']);

    // cambia il redirect per gli utenti non autenticati
    $middleware->redirectGuestsTo('/custom-login');

    // priorità dei middleware
    $middleware->priority([
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    ]);
})
```

### `withExceptions()` — configurazione della gestione eccezioni

```php theme={null}
public function withExceptions(?callable $using = null)
{
    $this->app->singleton(
        \Illuminate\Contracts\Debug\ExceptionHandler::class,
        \Illuminate\Foundation\Exceptions\Handler::class
    );

    if ($using !== null) {
        $this->app->afterResolving(
            \Illuminate\Foundation\Exceptions\Handler::class,
            fn ($handler) => $using(new Exceptions($handler)),
        );
    }

    return $this;
}
```

`withExceptions()` registra la classe `Handler` del framework come singleton e imposta la callback tramite `afterResolving()`. Alla callback viene passato un wrapper `Exceptions`.

```php theme={null}
->withExceptions(function (Exceptions $exceptions) {
    // non riportare eccezioni specifiche
    $exceptions->dontReport(MissedFlightException::class);

    // report personalizzato per un'eccezione specifica
    $exceptions->report(function (InvalidOrderException $e) {
        // notifica su Slack, ecc.
    });

    // personalizza la response HTTP per un'eccezione specifica
    $exceptions->render(function (NotFoundHttpException $e, Request $request) {
        if ($request->is('api/*')) {
            return response()->json(['message' => 'Not Found'], 404);
        }
    });

    // throttling (non riportare la stessa eccezione ripetuta)
    $exceptions->throttle(function (Throwable $e) {
        return Limit::perMinute(20);
    });
})
```

### `withProviders()` — registrazione dei service provider

```php theme={null}
public function withProviders(array $providers = [], bool $withBootstrapProviders = true)
{
    RegisterProviders::merge(
        $providers,
        $withBootstrapProviders
            ? $this->app->getBootstrapProvidersPath()
            : null
    );

    return $this;
}
```

`withProviders()` viene chiamato di default dentro `Application::configure()`, quindi `bootstrap/providers.php` viene caricato automaticamente. Se vuoi passare provider aggiuntivi devi chiamarlo esplicitamente in `bootstrap/app.php`.

```php theme={null}
Application::configure(basePath: dirname(__DIR__))
    ->withProviders([
        // aggiungi provider oltre a quelli di bootstrap/providers.php di default
        App\Providers\CustomServiceProvider::class,
    ])
    ->withRouting(...)
    ->create();
```

<Warning>
  Passando `withBootstrapProviders: false` disabiliti il caricamento di `bootstrap/providers.php`. Non farlo se non hai un motivo specifico.
</Warning>

### Altri metodi principali

| Metodo                               | Descrizione                                                                             |
| ------------------------------------ | --------------------------------------------------------------------------------------- |
| `withKernels()`                      | Registra come singleton il Kernel HTTP/Console. Chiamato in automatico da `configure()` |
| `withEvents()`                       | Abilita l'event discovery. Chiamato in automatico da `configure()`                      |
| `withCommands(array $commands)`      | Registra ulteriori classi o directory di comandi Artisan                                |
| `withSchedule(callable $callback)`   | Definisce lo schedule in `bootstrap/app.php`                                            |
| `withBroadcasting(string $channels)` | Registra il file dei channel di broadcasting                                            |
| `withBindings(array $bindings)`      | Registra i binding del container                                                        |
| `withSingletons(array $singletons)`  | Registra binding singleton                                                              |
| `registered(callable $callback)`     | Callback eseguita dopo la registrazione dei service provider                            |
| `booting(callable $callback)`        | Callback eseguita al booting                                                            |
| `booted(callable $callback)`         | Callback eseguita a booted                                                              |
| `create()`                           | Restituisce l'istanza `Application`                                                     |

## Intenti di design: perché è così

### Configurazione "code-first"

In Laravel 10 `app/Http/Kernel.php` elencava i middleware in array. È una scrittura vicina a un file di configurazione, poco supportata dal type system PHP e dagli IDE.

Con Laravel 11 si è passati a uno stile a callback come `withMiddleware(function (Middleware $middleware) { ... })`. In questo modo ottieni autocompletamento dei tipi e puoi scrivere in modo naturale logica dinamica con condizioni e cicli.

### Da "convention over configuration" a "configurazione esplicita"

`api.php` è diventato opt-in: nelle app che non usano API non ha più senso caricare sempre il gruppo `api`. Filosofia: ciò che non usi non è presente di default.

### Uso dell'hook `afterResolving()`

`withMiddleware()` e `withExceptions()` usano `afterResolving()` per evitare problemi d'ordine nella configurazione. I metodi di `ApplicationBuilder` vengono chiamati prima che l'app sia completamente avviata, ma le azioni concrete (applicare le impostazioni al Kernel) vengono differite fino alla prima risoluzione del Kernel.

## Esempi di personalizzazione pratica

### Convivenza di API e Web

```php theme={null}
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
        apiPrefix: 'api/v1',  // cambia dal /api di default
    )
    ->withMiddleware(function (Middleware $middleware): void {
        //
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();
```

### Personalizzazione dei middleware

```php theme={null}
->withMiddleware(function (Middleware $middleware) {
    // aggiungi controllo di verifica alle rotte web
    $middleware->web(append: [
        \App\Http\Middleware\EnsureEmailIsVerified::class,
    ]);

    // rimuovi un middleware nelle rotte api
    $middleware->api(remove: [
        \Illuminate\Session\Middleware\StartSession::class,
    ]);

    // escludi gli endpoint webhook dal CSRF
    $middleware->validateCsrfTokens(except: [
        'webhook/*',
        'stripe/webhook',
    ]);

    // imposta un alias per un middleware specifico
    $middleware->alias([
        'subscribed' => \App\Http\Middleware\EnsureUserIsSubscribed::class,
    ]);
})
```

### Concentrare lo schedule in `bootstrap/app.php`

Lo schedule si può scrivere anche in `routes/console.php`, ma con `withSchedule()` puoi raggrupparlo in `bootstrap/app.php`.

```php theme={null}
use Illuminate\Console\Scheduling\Schedule;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withSchedule(function (Schedule $schedule) {
        $schedule->command('emails:send')->daily();
        $schedule->command('reports:generate')->weeklyOn(1, '8:00');
        $schedule->job(new PruneOldRecords)->daily();
    })
    ->withMiddleware(function (Middleware $middleware): void {
        //
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();
```

### Personalizzare la gestione delle eccezioni

```php theme={null}
->withExceptions(function (Exceptions $exceptions) {
    // restituisci sempre JSON alle richieste API
    $exceptions->render(function (Throwable $e, Request $request) {
        if ($request->is('api/*') || $request->wantsJson()) {
            $status = match (true) {
                $e instanceof NotFoundHttpException => 404,
                $e instanceof AuthenticationException => 401,
                $e instanceof AuthorizationException => 403,
                $e instanceof ValidationException => 422,
                default => 500,
            };

            return response()->json([
                'message' => $e->getMessage(),
            ], $status);
        }
    });

    // notifica Slack solo in produzione
    if (app()->isProduction()) {
        $exceptions->report(function (Throwable $e) {
            app(SlackNotifier::class)->notify($e);
        })->stop();
    }
})
```

### Gestire i binding del container in `bootstrap/app.php`

In app piccole puoi scrivere binding semplici direttamente in `bootstrap/app.php` invece che in `AppServiceProvider`.

```php theme={null}
return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withSingletons([
        \App\Contracts\PaymentGateway::class => \App\Services\StripeGateway::class,
        \App\Contracts\MailService::class => \App\Services\SendgridMailService::class,
    ])
    ->withMiddleware(...)
    ->withExceptions(...)
    ->create();
```

## Ordine di avvio di Laravel

All'avvio dell'app, service provider e hook dell'Application vengono eseguiti in questo ordine.

1. `register()` di tutti i ServiceProvider
2. `registered()` dell'Application
3. `booting()` dell'Application
4. `boot()` di tutti i ServiceProvider
5. `booted()` dell'Application

Aggiungendo il codice seguente a `AppServiceProvider` puoi verificarne l'ordine.

```php theme={null}
class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        info('1. AppServiceProvider register');

        $this->booting(function () {
            info('4. AppServiceProvider booting');
        });

        $this->booted(function () {
            info('5. AppServiceProvider booted');
        });

        $this->app->registered(function () {
            info('2. app registered');
        });

        $this->app->booting(function () {
            info('3. app booting');
        });

        $this->app->booted(function () {
            info('6. AppServiceProvider@register app booted');
        });
    }

    public function boot(): void
    {
        $this->app->booted(function () {
            info('7. AppServiceProvider@boot app booted');
        });
    }
}
```

`registered()`, `booting()` e `booted()` di `ApplicationBuilder` si limitano a registrare callback nell'Application. Di solito non ti servono, ma consentono operazioni particolari, come modificare il Kernel a `booted()` quando i preparativi di avvio sono completi.

```php theme={null}
// bootstrap/app.php

use Illuminate\Contracts\Http\Kernel;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(...)
    ->withMiddleware(...)
    ->withExceptions(...)
    ->booted(function (Application $app) {
        $kernel = $app->make(Kernel::class);

        //

        $app->instance(Kernel::class, $kernel);
    })
    ->create();
```

## Prossimi passi

<Card title="Service container" icon="box" href="/it/service-container">
  Comprendi il meccanismo del service container usato internamente da `ApplicationBuilder`.
</Card>

<Card title="FAQ nuova struttura" icon="circle-question" href="/it/advanced/app-structure-faq">
  Raccolta di dubbi frequenti e risposte sulla nuova struttura dell'applicazione.
</Card>


## Related topics

- [FAQ sulla nuova struttura dell'app da Laravel 11](/it/advanced/app-structure-faq.md)
- [Guida di migrazione dalla vecchia alla nuova struttura](/it/advanced/app-structure-migration.md)
- [Aggiornamento da Laravel 10 a 11](/it/blog/upgrade-10-to-11.md)
- [Struttura delle directory](/it/directory-structure.md)
- [Laravel e lo sviluppo con AI](/it/ai.md)
