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

# Guida di migrazione dalla vecchia alla nuova struttura

> Procedura per migrare dalla struttura applicativa di Laravel 10 allo Slim Application Skeleton di Laravel 11 e successivi.

## Introduzione

Questa guida illustra come migrare dalla vecchia struttura applicativa di Laravel 10 e precedenti (con classi `Kernel` e più service provider) allo Slim Application Skeleton di Laravel 11 e successivi.

<Warning>
  **La documentazione ufficiale non raccomanda questa migrazione.**

  * La vecchia struttura di Laravel 10 **continua a funzionare** anche su Laravel 11 e versioni successive. Fino alle versioni attuali (Laravel 13 compreso) non c'è alcun piano di dismissione.
  * La migrazione è **del tutto opzionale**. Non è obbligatoria né raccomandata.
  * Se non conosci a fondo le differenze tra vecchia e nuova struttura, ti sconsigliamo caldamente di migrare. È un'operazione per sviluppatori che conoscono bene il framework internamente.
  * Prima di migrare, **fai sempre un backup** e verifica che tutti i test siano verdi.
</Warning>

## Quando serve migrare

Puoi valutare la migrazione nei casi seguenti.

* Vuoi allineare il progetto alla struttura standard più recente per facilitare l'onboarding di nuovi membri con la documentazione ufficiale
* Vuoi mantenere coerenza con pacchetti o starter kit creati in Laravel 11+
* Vuoi ridurre file e classi ereditati dalla vecchia struttura e semplificare la codebase

## Prerequisiti

La guida presuppone questa situazione.

* **L'upgrade di Laravel è già stato completato** (`laravel/framework ^11.0` o successivi)
* Tutti i test esistenti passano
* Hai compreso la struttura applicativa di Laravel 11+ (vedi [Struttura dell'applicazione da Laravel 11](/it/advanced/app-structure))

## Esempio di migrazione

Ecco la procedura per un progetto creato con Laravel 10 + Breeze (stack Blade) in cui vuoi mantenere Breeze ma migrare solo la struttura applicativa.

<Steps>
  <Step title="Sostituire bootstrap/app.php">
    Il vecchio `bootstrap/app.php` creava l'istanza `$app` e registrava i kernel. Sostituiscilo con la chain `Application::configure()`.

    **Vecchio (Laravel 10):**

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

    $app = new Illuminate\Foundation\Application(
        $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
    );

    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );

    $app->singleton(
        Illuminate\Contracts\Console\Kernel::class,
        App\Console\Kernel::class
    );

    $app->singleton(
        Illuminate\Contracts\Debug\ExceptionHandler::class,
        App\Exceptions\Handler::class
    );

    return $app;
    ```

    **Nuovo (Laravel 11+):**

    ```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) {
            //
        })
        ->withExceptions(function (Exceptions $exceptions) {
            //
        })->create();
    ```

    <Info>
      Le callback di `withMiddleware()` e `withExceptions()` sono i posti in cui trasferirai le impostazioni dei file kernel che eliminerai nei prossimi step. Lasciale vuote per ora e le compileremo dopo.
    </Info>
  </Step>

  <Step title="Eliminare il kernel HTTP (app/Http/Kernel.php)">
    In `app/Http/Kernel.php` erano definiti middleware globali, gruppi di middleware e alias.

    **Vecchio (app/Http/Kernel.php):**

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

    namespace App\Http;

    use Illuminate\Foundation\Http\Kernel as HttpKernel;

    class Kernel extends HttpKernel
    {
        protected $middleware = [
            \App\Http\Middleware\TrustProxies::class,
            \Illuminate\Http\Middleware\HandleCors::class,
            \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
            \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
            \App\Http\Middleware\TrimStrings::class,
            \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        ];

        protected $middlewareGroups = [
            'web' => [
                \App\Http\Middleware\EncryptCookies::class,
                \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
                \Illuminate\Session\Middleware\StartSession::class,
                \Illuminate\View\Middleware\ShareErrorsFromSession::class,
                \App\Http\Middleware\VerifyCsrfToken::class,
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
            'api' => [
                \Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
        ];

        protected $middlewareAliases = [
            'auth' => \App\Http\Middleware\Authenticate::class,
            // ...
        ];
    }
    ```

    In Laravel 11 i middleware qui sopra sono incorporati nel framework come default. Se **non hai personalizzazioni**, puoi eliminare direttamente `app/Http/Kernel.php`.

    **In caso di personalizzazioni** (middleware aggiunti o rimossi), trasferisci il tutto in `withMiddleware()` di `bootstrap/app.php` prima di eliminare.

    ```php theme={null}
    ->withMiddleware(function (Middleware $middleware) {
        // aggiunta di un middleware globale
        $middleware->append(\App\Http\Middleware\MyCustomMiddleware::class);

        // aggiungi al gruppo web
        $middleware->web(append: [
            \App\Http\Middleware\HandleInertiaRequests::class,
        ]);

        // aggiungi alias
        $middleware->alias([
            'role' => \App\Http\Middleware\CheckRole::class,
        ]);
    })
    ```

    Completato il trasferimento, elimina `app/Http/Kernel.php`.

    <Info>
      In Laravel 11 puoi rimuovere anche le classi middleware di default (`TrustProxies`, `EncryptCookies`, `VerifyCsrfToken`, ecc.) da `app/Http/Middleware/`. Sono integrate nel framework: se non le personalizzi, il file non serve.
    </Info>
  </Step>

  <Step title="Eliminare il kernel della console (app/Console/Kernel.php)">
    `app/Console/Kernel.php` gestiva schedule e auto-load dei comandi.

    **Vecchio (app/Console/Kernel.php):**

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

    namespace App\Console;

    use Illuminate\Console\Scheduling\Schedule;
    use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

    class Kernel extends ConsoleKernel
    {
        protected function schedule(Schedule $schedule): void
        {
            // $schedule->command('inspire')->hourly();
        }

        protected function commands(): void
        {
            $this->load(__DIR__.'/Commands');
            require base_path('routes/console.php');
        }
    }
    ```

    **Auto-load dei comandi**: da Laravel 11 la directory `app/Console/Commands/` viene scansionata automaticamente, quindi `$this->load()` non serve.

    **Definizione dello schedule**: spostala in `routes/console.php` o in `withSchedule()` di `bootstrap/app.php`.

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

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

    Dopo la migrazione elimina `app/Console/Kernel.php`.

    <Info>
      Non eliminare i file dei comandi Artisan custom nella directory `app/Console/`. Lascia i comandi al loro posto ed elimina solo il file della classe Kernel.
    </Info>
  </Step>

  <Step title="Eliminare l'exception handler (app/Exceptions/Handler.php)">
    `app/Exceptions/Handler.php` gestiva le impostazioni di report e rendering delle eccezioni.

    **Vecchio (app/Exceptions/Handler.php):**

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

    namespace App\Exceptions;

    use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
    use Throwable;

    class Handler extends ExceptionHandler
    {
        protected $dontFlash = [
            'current_password',
            'password',
            'password_confirmation',
        ];

        public function register(): void
        {
            $this->reportable(function (Throwable $e) {
                //
            });
        }
    }
    ```

    Se hai personalizzazioni, trasferiscile in `withExceptions()` di `bootstrap/app.php` prima di eliminare.

    ```php theme={null}
    use Throwable;
    use Illuminate\Http\Request;

    ->withExceptions(function (Exceptions $exceptions) {
        // personalizza il report
        $exceptions->report(function (Throwable $e) {
            // ...
        });

        // personalizza il rendering
        $exceptions->render(function (\App\Exceptions\InvalidOrderException $e, Request $request) {
            return response()->view('errors.invalid-order', status: 500);
        });
    })
    ```

    Se avevi aggiunto voci proprie in `$dontFlash`, puoi trasferirle in modo analogo.

    ```php theme={null}
    ->withExceptions(function (Exceptions $exceptions) {
        $exceptions->dontFlash([
            'my_sensitive_field',
        ]);
    })
    ```

    Completato il trasferimento, elimina `app/Exceptions/Handler.php`.
  </Step>

  <Step title="Eliminare RouteServiceProvider e migrare la registrazione delle rotte">
    `app/Providers/RouteServiceProvider.php` caricava i file delle rotte e configurava il rate limit.

    **Vecchio (app/Providers/RouteServiceProvider.php):**

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

    namespace App\Providers;

    use Illuminate\Cache\RateLimiting\Limit;
    use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\RateLimiter;
    use Illuminate\Support\Facades\Route;

    class RouteServiceProvider extends ServiceProvider
    {
        public const HOME = '/home';

        public function boot(): void
        {
            RateLimiter::for('api', function (Request $request) {
                return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
            });

            $this->routes(function () {
                Route::middleware('api')
                    ->prefix('api')
                    ->group(base_path('routes/api.php'));

                Route::middleware('web')
                    ->group(base_path('routes/web.php'));
            });
        }
    }
    ```

    **Registrazione delle rotte**: sposta in `withRouting()` di `bootstrap/app.php`.

    ```php theme={null}
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        api: __DIR__.'/../routes/api.php', // se usi le rotte API
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ```

    **Rate limit**: sposta in `AppServiceProvider::boot()`.

    ```php theme={null}
    // app/Providers/AppServiceProvider.php
    use Illuminate\Cache\RateLimiting\Limit;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\RateLimiter;

    public function boot(): void
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
        });
    }
    ```

    Se utilizzi la costante `HOME`, sostituiscila con la stringa URL diretta o spostala in `AppServiceProvider`.

    Dopo la migrazione elimina `app/Providers/RouteServiceProvider.php`.
  </Step>

  <Step title="Riordinare i service provider">
    In Laravel 10 c'erano 5 service provider di default. Uniscili in `AppServiceProvider.php`.

    **Provider da eliminare (dopo aver trasferito i contenuti in AppServiceProvider):**

    | File                                         | Destinazione                                                        |
    | -------------------------------------------- | ------------------------------------------------------------------- |
    | `app/Providers/AuthServiceProvider.php`      | `Gate::policy()` ecc. in `AppServiceProvider::boot()`               |
    | `app/Providers/BroadcastServiceProvider.php` | Se usi il broadcasting: `withBroadcasting()` in `bootstrap/app.php` |
    | `app/Providers/EventServiceProvider.php`     | `Event::listen()` ecc. in `AppServiceProvider::boot()`              |
    | `app/Providers/RouteServiceProvider.php`     | Già gestito nello step precedente                                   |

    **Esempio di migrazione del contenuto di `app/Providers/AuthServiceProvider.php`:**

    ```php theme={null}
    // vecchio: app/Providers/AuthServiceProvider.php
    use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

    class AuthServiceProvider extends ServiceProvider
    {
        protected $policies = [
            Post::class => PostPolicy::class,
        ];

        public function boot(): void
        {
            $this->registerPolicies();
        }
    }
    ```

    ```php theme={null}
    // nuovo: app/Providers/AppServiceProvider.php
    // Se segui la convenzione di naming standard di Laravel, l'auto-detection basta e non serve altro
    use Illuminate\Support\Facades\Gate;

    class AppServiceProvider extends ServiceProvider
    {
        public function boot(): void
        {
            Gate::policy(Post::class, PostPolicy::class);
        }
    }
    ```

    Dopo aver eliminato i file dei provider non più necessari, rimuovi anche l'array `providers` da `config/app.php`.

    ```php theme={null}
    // array providers in config/app.php
    // puoi eliminarlo del tutto
    'providers' => ServiceProvider::defaultProviders()->merge([
    App\Providers\AppServiceProvider::class,
    // rimuovi anche le voci dei provider eliminati
    // App\Providers\AuthServiceProvider::class, // rimuovere
    // App\Providers\EventServiceProvider::class, // rimuovere
    // App\Providers\RouteServiceProvider::class, // rimuovere
    ])->toArray(),
    ```

    Inoltre crea `bootstrap/providers.php` per la nuova struttura.

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

    // bootstrap/providers.php
    return [
        App\Providers\AppServiceProvider::class,
    ];
    ```

    <Info>
      Se `bootstrap/providers.php` è presente, Laravel privilegia questo file come elenco dei provider.
    </Info>
  </Step>

  <Step title="Aggiornare la classe base Controller">
    In Laravel 10 la classe base `Controller` usava i trait `AuthorizesRequests` e `ValidatesRequests`. La nuova classe base di Laravel 11 è una classe astratta semplice senza questi trait.

    **Vecchio (Laravel 10):**

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

    namespace App\Http\Controllers;

    use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
    use Illuminate\Foundation\Validation\ValidatesRequests;
    use Illuminate\Routing\Controller as BaseController;

    class Controller extends BaseController
    {
        use AuthorizesRequests, ValidatesRequests;
    }
    ```

    **Nuovo (Laravel 11+):**

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

    namespace App\Http\Controllers;

    abstract class Controller
    {
        //
    }
    ```

    Sostituzioni per le funzionalità dei trait:

    | Vecchio metodo (tramite trait)          | Nuovo metodo                                                                                                |
    | --------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
    | `$this->validate($request, $rules)`     | `$request->validate($rules)`                                                                                |
    | `$this->authorize('update', $post)`     | `Gate::authorize('update', $post)`                                                                          |
    | `$this->authorizeResource(Post::class)` | In Laravel 11 non c'è un'alternativa immediata: lascia `App\Http\Controllers\Controller` come in Laravel 10 |

    Se i controller esistenti usano i metodi dei trait, puoi correggerli uno a uno oppure mantenere i trait sulla classe base `Controller`. Non è obbligatorio cambiare tutto insieme.

    <Warning>
      Se i controller di autenticazione generati da Breeze o Jetstream chiamano `$this->validate()` o `$this->authorize()`, verifica il funzionamento prima di modificare la classe base.
    </Warning>
  </Step>

  <Step title="Eliminare i file di config non necessari">
    File come `config/cors.php`, `config/hashing.php`, `config/view.php` che non hai modificato rispetto al default si possono eliminare. Mantieni quelli che hai personalizzato.
  </Step>

  <Step title="Aggiornare public/index.php">
    Cambia in modo profondo per adeguarsi alla nuova struttura.

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

    use Illuminate\Foundation\Application;
    use Illuminate\Http\Request;

    define('LARAVEL_START', microtime(true));

    // Determine if the application is in maintenance mode...
    if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
    require $maintenance;
    }

    // Register the Composer autoloader...
    require __DIR__.'/../vendor/autoload.php';

    // Bootstrap Laravel and handle the request...
    /** @var Application $app */
    $app = require_once __DIR__.'/../bootstrap/app.php';

    $app->handleRequest(Request::capture());
    ```
  </Step>

  <Step title="Aggiornare artisan">
    Riscrivi anche il file `artisan`.

    ```php theme={null}
    #!/usr/bin/env php
    <?php

    use Illuminate\Foundation\Application;
    use Symfony\Component\Console\Input\ArgvInput;

    define('LARAVEL_START', microtime(true));

    // Register the Composer autoloader...
    require __DIR__.'/vendor/autoload.php';

    // Bootstrap Laravel and handle the command...
    /** @var Application $app */
    $app = require_once __DIR__.'/bootstrap/app.php';

    $status = $app->handleCommand(new ArgvInput);

    exit($status);
    ```
  </Step>

  <Step title="Aggiornare tests/TestCase.php">
    Il trait `CreatesApplication` non serve più, quindi modifica il file.
    Puoi eliminare `tests/CreatesApplication.php`.

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

    namespace Tests;

    use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

    abstract class TestCase extends BaseTestCase
    {
        //
    }
    ```
  </Step>

  <Step title="Aggiornare .env, .env.example, phpunit.xml">
    `CACHE_DRIVER` è diventato `CACHE_STORE` e sono state aggiunte voci: modificale se necessario.
    Queste modifiche toccano file di config e ambienti di produzione, quindi procedi con cautela.
    Non è obbligatorio adeguarsi a tutti i costi.
  </Step>

  <Step title="Verifica del funzionamento">
    Terminata la migrazione, verifica nell'ordine seguente.

    ```shell theme={null}
    # pulizia delle cache
    php artisan config:clear
    php artisan route:clear
    php artisan cache:clear

    # verifica che le rotte siano registrate correttamente
    php artisan route:list

    # esegui i test
    php artisan test
    ```

    In caso di problemi, ripristina i file eliminati dal backup e leggi i messaggi di errore.
  </Step>
</Steps>

## Struttura dei file dopo la migrazione

Dopo la migrazione la struttura del progetto risulta come segue (i punti di cambiamento rispetto alla vecchia struttura sono indicati).

```
app/
├── Console/
│   └── Commands/          ← i comandi custom restano al loro posto
│   (Kernel.php è stato eliminato)
├── Exceptions/
│   (Handler.php è stato eliminato)
├── Http/
│   ├── Controllers/
│   │   └── Controller.php ← modificata come classe astratta semplice
│   └── Middleware/        ← i middleware custom restano
│   (Kernel.php è stato eliminato)
├── Models/
└── Providers/
    └── AppServiceProvider.php ← unica classe
    (AuthServiceProvider.php eliminato)
    (BroadcastServiceProvider.php eliminato)
    (EventServiceProvider.php eliminato)
    (RouteServiceProvider.php eliminato)
bootstrap/
├── app.php                ← sostituito con Application::configure()
└── providers.php          ← nuovo file
routes/
├── web.php
├── api.php                ← solo se serve
└── console.php            ← anche la definizione dello schedule qui
```

## Riepilogo

| Elemento migrato        | Vecchia posizione                        | Nuova posizione                                             |
| ----------------------- | ---------------------------------------- | ----------------------------------------------------------- |
| Middleware HTTP         | `app/Http/Kernel.php`                    | `withMiddleware()` in `bootstrap/app.php`                   |
| Gestione eccezioni      | `app/Exceptions/Handler.php`             | `withExceptions()` in `bootstrap/app.php`                   |
| Definizione schedule    | `app/Console/Kernel.php`                 | `routes/console.php`                                        |
| Registrazione rotte     | `app/Providers/RouteServiceProvider.php` | `withRouting()` in `bootstrap/app.php`                      |
| Elenco service provider | Array `providers` in `config/app.php`    | `bootstrap/providers.php`                                   |
| Registrazione policy    | `app/Providers/AuthServiceProvider.php`  | Auto-registrazione. Manuale in `AppServiceProvider::boot()` |
| Listener di eventi      | `app/Providers/EventServiceProvider.php` | Auto-registrazione. Manuale in `AppServiceProvider::boot()` |

## Link di riferimento

* [Struttura dell'applicazione da Laravel 11](/it/advanced/app-structure)
* [FAQ nuova struttura](/it/advanced/app-structure-faq)
* [Guida ufficiale di upgrade (11.x)](https://github.com/laravel/docs/blob/11.x/upgrade.md)
* [Diff laravel/laravel 10.x → 11.x](https://github.com/laravel/laravel/compare/10.x...11.x)
* [Controller.php di Laravel 10](https://github.com/laravel/laravel/blob/10.x/app/Http/Controllers/Controller.php)
* [Controller.php di Laravel 11](https://github.com/laravel/laravel/blob/11.x/app/Http/Controllers/Controller.php)


## Related topics

- [FAQ sulla nuova struttura dell'app da Laravel 11](/it/advanced/app-structure-faq.md)
- [Guida alla migrazione da laravel/ui a Fortify](/it/blog/ui-to-fortify.md)
- [Gestire la compatibilità tra versioni dei pacchetti](/it/advanced/package-versioning.md)
- [Hashing](/it/hashing.md)
- [Struttura dell'applicazione da Laravel 11](/it/advanced/app-structure.md)
