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

# Registrazione dei comandi Artisan di un pacchetto e risoluzione delle dipendenze

> Analisi del percorso da commands() all'avvio di Artisan in Laravel 13: separazione tra creazione ed esecuzione dei comandi, dependency injection, provider differiti e aspetti da considerare per la manutenzione a lungo termine.

Quando vuoi aggiungere al pacchetto comandi Artisan per diagnostica, sincronizzazione o installazione, considera separatamente la registrazione del comando, la creazione dell'istanza e l'esecuzione dell'elaborazione. Se risolvi nel costruttore servizi necessari solo in fase di esecuzione, rischi di coinvolgere anche l'avvio di comandi Artisan che non c'entrano nulla.

Questa pagina esamina l'implementazione di Laravel Framework `v13.35.0` e approfondisce l'esempio di registrazione con `commands()` presentato in [Sviluppo di pacchetti Laravel](/it/advanced/package-development). Per l'implementazione della generazione di file consulta [GeneratorCommand](/it/advanced/generator-command), e per la partecipazione ai task di ottimizzazione consulta [Integrazione con optimize](/it/advanced/package-optimization).

## Registrare esplicitamente dal provider

I comandi di un pacchetto si registrano tramite il nome della classe nel metodo `boot()` del service provider. Il rilevamento automatico della directory `app/Console/Commands` dell'applicazione e la registrazione delle classi fornite da un pacchetto sono due punti di ingresso distinti.

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

namespace Acme\Courier;

use Acme\Courier\Console\StatusCommand;
use Illuminate\Support\ServiceProvider;

class CourierServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                StatusCommand::class,
            ]);
        }
    }
}
```

Questo esempio presuppone che il provider venga caricato tramite il [package auto-discovery](/it/advanced/package-discovery) o tramite una registrazione esplicita lato applicazione. Non basta inserire una classe di comando perché il provider del pacchetto venga registrato automaticamente.

`runningInConsole()` verifica se ci si trova in un ambiente console, non se è in esecuzione un comando specifico. Se prevedi anche l'uso tramite `Artisan::call()` all'interno di una richiesta HTTP, tieni conto che questa condizione potrebbe impedire la registrazione e definisci il contratto d'uso valutando anche una registrazione incondizionata. Per l'esecuzione da codice consulta [Artisan](/it/artisan).

## commands() non esegue il comando immediatamente

`ServiceProvider::commands()` registra in `Illuminate\Console\Application::starting()` una closure che utilizza i nomi di classe ricevuti. In questo momento il metodo `handle()` del comando non viene chiamato.

Con il normale Console Kernel, i callback di avvio registrati vengono eseguiti in seguito, quando viene creata l'Artisan Application. A quel punto `resolveCommands()` passa ogni classe a `resolve()` e procede con la registrazione dei comandi.

```mermaid theme={null}
flowchart TD
    A["boot() del provider"] --> B["Registrazione del callback di avvio con commands()"]
    B --> C["Il Console Kernel crea l'Artisan Application"]
    C --> D["Registrazione delle classi con resolveCommands()"]
    D --> E["Le classi normali vengono istanziate dal container"]
    E --> F["Esecuzione del comando selezionato"]
    F --> G["Risoluzione delle dipendenze di handle() e chiamata"]
```

Il punto fondamentale è che **la creazione dell'istanza di un comando non coincide necessariamente con la sua esecuzione**. Per le classi normali che non seguono il percorso di registrazione differita dedicato descritto più avanti, `resolve()` chiama `make()` del container, quindi il costruttore e le sue dipendenze vengono risolti al momento della registrazione.

Di conseguenza, anche solo eseguire `php artisan list` o un altro comando può far partire il costruttore del comando del pacchetto. Collocare `commands()` in `boot()` non garantisce di per sé che la creazione dell'istanza venga rimandata fino all'esecuzione.

## Iniettare le dipendenze di esecuzione in handle()

Come esempio, creiamo un comando che mostra soltanto se la configurazione del pacchetto è abilitata o disabilitata. Come nella documentazione ufficiale di Artisan per Laravel 13, nome e descrizione vengono definiti con gli attributi `Signature` e `Description`.

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

namespace Acme\Courier\Console;

use Illuminate\Console\Attributes\Description;
use Illuminate\Console\Attributes\Signature;
use Illuminate\Console\Command;
use Illuminate\Contracts\Config\Repository;

#[Signature('courier:status')]
#[Description('Display whether the Courier integration is enabled')]
class StatusCommand extends Command
{
    public function handle(Repository $config): int
    {
        $enabled = (bool) $config->get('courier.enabled', false);

        $this->line($enabled ? 'Courier: enabled' : 'Courier: disabled');

        return self::SUCCESS;
    }
}
```

In questo esempio non viene aggiunto un costruttore e il Repository della configurazione viene ricevuto come argomento di `handle()`. Poiché nel percorso di esecuzione del comando `Command::execute()` usa `call()` del container, le dipendenze tipizzate vengono iniettate.

Anche quando usi un client per API esterne o un servizio di sincronizzazione, puoi iniettarlo nella stessa posizione se serve solo in fase di esecuzione. Tuttavia, se la creazione del servizio stesso o il `boot()` di un altro provider hanno effetti collaterali, questi non vengono evitati automaticamente.

| Posizione | Momento di valutazione in un comando normale | Elaborazione adatta |
| - | - | - |
| `boot()` del provider | All'avvio del provider | Registrazione delle classi di comando |
| Costruttore del comando | Alla creazione dell'istanza, non necessariamente subito prima dell'esecuzione | Inizializzazione leggera |
| Argomenti tipizzati di `handle()` | All'esecuzione del comando | Risoluzione dei servizi necessari all'esecuzione |
| Corpo di `handle()` | All'esecuzione del comando | Validazione dell'input, logica di business, visualizzazione dei risultati |

<Warning>
  Nel costruttore non eseguire connessioni ad API esterne, aggiornamenti del database o sovrascritture di file pubblicati. Gli utenti del pacchetto devono poter usare `list` e `help` anche subito dopo l'installazione o quando la configurazione della connessione non è ancora completa.
</Warning>

Se definisci un costruttore personalizzato, chiama anche `parent::__construct()`. Il costruttore padre di Laravel, infatti, configura il comando a partire da attributi, signature, description e così via.

## Signature e registrazione differita sono meccanismi distinti

Il metodo `Application::resolve()` esaminato contiene un ramo che legge il `name` dell'attributo Symfony `AsCommand` e salva la corrispondenza tra nome e classe in una command map. In questo ramo `make()` del container non viene chiamato subito. Il Console Kernel chiama poi `setContainerCommandLoader()` per configurare un loader che usa questa map.

L'attributo Laravel `Signature` usato nell'esempio precedente, invece, è separato da questa verifica di `AsCommand`. **Aggiungere `Signature` non basta perché la classe segua questo percorso di registrazione differita.**

Considera questa differenza come un aspetto a cui prestare attenzione quando leggi l'implementazione interna e, prima di tutto, riduci il costo di creazione e gli effetti collaterali con la definizione ufficiale dei comandi e la dependency injection in `handle()`. Anche in presenza di un loader differito, le informazioni del comando possono essere necessarie per l'elenco, l'aiuto e così via: quindi non progettare partendo dal presupposto che il comando "non venga mai creato se non durante la sua esecuzione".

## Non rimandare la registrazione dei comandi

Caricare in modo differito i binding dei servizi e far conoscere un comando ad Artisan sono due cose diverse. Se un provider implementa `DeferrableProvider`, il suo stesso `boot()` potrebbe non essere eseguito finché il servizio interessato non diventa necessario.

Se la registrazione dei comandi si trova solo in quel `boot()` e il provider non viene caricato prima dell'avvio di Artisan, non viene registrato nemmeno il callback di avvio che segnala l'esistenza del comando. Anche se un servizio spostato nella dependency injection di `handle()` carica il provider differito, questo non risolve il problema che si presenta prima che Artisan trovi il comando.

Per garantire l'esposizione dei comandi, puoi collocare la registrazione in un provider caricato immediatamente e isolare solo i binding dei servizi pesanti in un provider differito separato. Per i requisiti specifici consulta [Service provider differiti](/it/advanced/deferred-provider).

## Cosa verificare negli aggiornamenti

Nome del comando, argomenti, opzioni, output e codice di uscita sono un'interfaccia pubblica usata dagli script shell e dalla CI degli utenti. Non modificarli con la stessa leggerezza con cui modifichi l'implementazione interna di una classe: verifica la compatibilità e la procedura di migrazione.

| Caso | Cosa verificare |
| - | - |
| Installazione in un'applicazione pulita | Il provider viene caricato e il nome del comando viene trovato |
| `php artisan list` | L'elaborazione del pacchetto e le connessioni esterne non partono |
| `php artisan help courier:status` | Descrizione e specifiche dell'input sono consultabili |
| Esecuzione effettiva del comando | Le dipendenze di `handle()` vengono risolte e il codice di uscita è quello previsto |
| Configurazione non pubblicata o non impostata | Elenco e aiuto non si rompono e la configurazione mancante viene gestita correttamente in esecuzione |
| Aggiornamento del pacchetto o di Laravel | I nomi, gli argomenti e le opzioni dei comandi esistenti restano utilizzabili |

Per lo `StatusCommand` precedente, puoi verificare output e codice di uscita come segue in un ambiente di test che carica il provider. Per l'infrastruttura di test consulta [Testare pacchetti Laravel con Orchestra Testbench](/it/advanced/package-testing), e per i dettagli sulle assertion consulta [Test da console](/it/console-tests).

```php theme={null}
public function test_status_command_displays_enabled_state(): void
{
    config()->set('courier.enabled', true);

    $this->artisan('courier:status')
        ->expectsOutput('Courier: enabled')
        ->assertExitCode(0);
}
```

Inoltre, per i comandi che usano servizi pesanti, verifica anche che i metodi di business del servizio non vengano chiamati durante l'esecuzione dell'elenco o dell'aiuto. Verificare soltanto che la registrazione funzioni non permette di rilevare l'impatto su comandi non correlati.

## Fonti primarie consultate

* [Documentazione ufficiale di Laravel: registrazione dei comandi di un pacchetto](https://github.com/laravel/docs/blob/13.x/packages.md#commands)
* [Documentazione ufficiale di Laravel: struttura dei comandi e dependency injection](https://github.com/laravel/docs/blob/13.x/artisan.md#command-structure)
* [ServiceProvider: commands()](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Support/ServiceProvider.php)
* [Console Application: starting(), bootstrap(), resolve()](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Console/Application.php)
* [Console Kernel: getArtisan() e registrazione del loader](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Foundation/Console/Kernel.php)
* [Command: costruttore ed execute()](https://github.com/laravel/framework/blob/v13.35.0/src/Illuminate/Console/Command.php)
* [Test ufficiali: risoluzione dei comandi e registrazione di alias tramite AsCommand](https://github.com/laravel/framework/blob/v13.35.0/tests/Console/ConsoleApplicationTest.php)


## Related topics

- [Hook di risoluzione dei servizi nei pacchetti](/it/advanced/package-service-resolution.md)
- [Argomenti avanzati](/it/advanced/index.md)
- [Registrazione e cache delle route di un pacchetto](/it/advanced/package-routes.md)
- [Sovrascrittura e aggiornamento delle traduzioni di un pacchetto](/it/advanced/package-translations.md)
- [Aggiungere informazioni diagnostiche del pacchetto ad about](/it/advanced/package-about.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.