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

# GeneratorCommand — implementare comandi `make:` personalizzati

> Come creare i propri comandi `make:` estendendo Illuminate\Console\GeneratorCommand. Dalla creazione dei file stub al controllo del namespace.

## Cos'è GeneratorCommand

`Illuminate\Console\GeneratorCommand` è la classe astratta alla base di tutti i comandi di generazione di codice di Laravel. `make:model`, `make:controller`, `make:request` ne sono tutte estensioni.

```mermaid theme={null}
flowchart TD
    A["GeneratorCommand<br>(classe astratta)"] --> B["make:model<br>ModelMakeCommand"]
    A --> C["make:request<br>RequestMakeCommand"]
    A --> D["make:controller<br>ControllerMakeCommand"]
    A --> E["make:handler<br>Il tuo comando"]
```

Fornendo un proprio comando `make:xxx` nel pacchetto, l'utente non crea più le classi a mano: basta eseguire `php artisan make:handler OrderHandler` per generare il file con il namespace corretto.

<Info>
  `GeneratorCommand` è quasi assente dalla documentazione ufficiale: si comprende solo leggendo il codice sorgente del framework. È un tipico argomento avanzato.
</Info>

## Implementazione minima

L'unico metodo obbligatorio nella classe che estende `GeneratorCommand` è `getStub()`. Le altre proprietà sono opzionali, ma nella pratica sono presenti.

| Membro                  | Tipo                  | Ruolo                                                              |
| ----------------------- | --------------------- | ------------------------------------------------------------------ |
| `$name`                 | Proprietà             | Nome del comando (es: `make:handler`)                              |
| `$description`          | Proprietà             | Descrizione del comando                                            |
| `$type`                 | Proprietà             | Tipo del risultato, usato nei messaggi di successo (es: `Handler`) |
| `getStub()`             | Metodo (obbligatorio) | Restituisce il path del file stub                                  |
| `getDefaultNamespace()` | Metodo                | Controlla il namespace di default della generazione                |

Esempio di implementazione del comando `make:handler`.

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

namespace Vendor\Package\Console\Commands;

use Illuminate\Console\GeneratorCommand;

class HandlerMakeCommand extends GeneratorCommand
{
    protected $name = 'make:handler';

    protected $description = 'Create a new handler class';

    protected $type = 'Handler';

    protected function getStub(): string
    {
        return __DIR__.'/stubs/handler.stub';
    }

    protected function getDefaultNamespace($rootNamespace): string
    {
        return $rootNamespace.'\Handlers';
    }
}
```

Con `getDefaultNamespace()` impostato, eseguendo `php artisan make:handler OrderHandler` viene generata la classe `App\Handlers\OrderHandler` in `app/Handlers/OrderHandler.php`.

## Creare il file stub

Colloca il file stub nel percorso restituito da `getStub()`. Lo stub è un file PHP template i cui placeholder vengono sostituiti con namespace e nome classe.

<Tree>
  <Tree.Folder name="src" defaultOpen>
    <Tree.Folder name="Console" defaultOpen>
      <Tree.Folder name="Commands" defaultOpen>
        <Tree.File name="HandlerMakeCommand.php" />

        <Tree.Folder name="stubs" defaultOpen>
          <Tree.File name="handler.stub" />
        </Tree.Folder>
      </Tree.Folder>
    </Tree.Folder>
  </Tree.Folder>
</Tree>

Esempio di file stub:

```php handler.stub theme={null}
<?php

namespace {{ namespace }};

class {{ class }}
{
    public function handle(): void
    {
        //
    }
}
```

`GeneratorCommand` sostituisce automaticamente i placeholder seguenti.

| Placeholder           | Valore sostituito               | Forma alternativa    |
| --------------------- | ------------------------------- | -------------------- |
| `{{ namespace }}`     | Namespace della classe generata | `DummyNamespace`     |
| `{{ class }}`         | Nome della classe generata      | `DummyClass`         |
| `{{ rootNamespace }}` | Namespace root dell'app         | `DummyRootNamespace` |

`{{ namespace }}` e `DummyNamespace` hanno lo stesso risultato. Gli stub integrati di Laravel usavano entrambe le forme; per nuovi progetti consigliamo `{{ namespace }}`.

## Permettere agli utenti di personalizzare lo stub

Per consentire all'utente di sovrascrivere lo stub, usa il pattern `resolveStubPath()`. Prima pubblichi gli stub dal service provider in `boot()`.

```php theme={null}
public function boot(): void
{
    if ($this->app->runningInConsole()) {
        $this->publishes([
            __DIR__.'/../Console/Commands/stubs' => base_path('stubs'),
        ], 'stubs');
    }
}
```

Poi in `getStub()` prediligi lo stub personalizzato dall'utente.

```php theme={null}
protected function getStub(): string
{
    return $this->resolveStubPath('/stubs/handler.stub');
}

protected function resolveStubPath(string $stub): string
{
    return file_exists($customPath = $this->laravel->basePath(trim($stub, '/')))
        ? $customPath
        : __DIR__.$stub;
}
```

L'utente che esegue `php artisan vendor:publish --tag=stubs` può modificare il template editando `stubs/handler.stub` nella root del progetto.

<Tip>
  `resolveStubPath()` è un pattern usato anche in `RequestMakeCommand` integrato in Laravel. Se pubblichi un pacchetto, adotta questo pattern.
</Tip>

## Registrazione nel service provider

Il comando si registra nel metodo `boot()` del service provider. Verificando `runningInConsole()` eviti caricamenti inutili in fase di richiesta web.

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

namespace Vendor\Package;

use Illuminate\Support\ServiceProvider;
use Vendor\Package\Console\Commands\HandlerMakeCommand;

class PackageServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        if ($this->app->runningInConsole()) {
            $this->commands([
                HandlerMakeCommand::class,
            ]);

            $this->publishes([
                __DIR__.'/../Console/Commands/stubs' => base_path('stubs'),
            ], 'stubs');
        }
    }
}
```

Impostando `extra.laravel` nel `composer.json` del pacchetto, l'utente non deve registrare a mano il service provider.

```json theme={null}
"extra": {
    "laravel": {
        "providers": [
            "Vendor\\Package\\PackageServiceProvider"
        ]
    }
}
```

## Casi d'uso

Alcuni scenari tipici in cui `GeneratorCommand` brilla.

<AccordionGroup>
  <Accordion title="Estensione delle form request">
    Un comando che genera Request che estendono una tua classe base, con logica di autorizzazione e regole di validazione personalizzate. In `getDefaultNamespace()` restituisci `App\Http\Requests`.
  </Accordion>

  <Accordion title="Generatore di DTO">
    Un comando che genera il boilerplate dei Data Transfer Object. Prepara uno stub con proprietà `readonly` e un metodo factory `from()`.
  </Accordion>

  <Accordion title="Classi Action">
    Un comando che genera classi Action a singola responsabilità. Genera una classe nel namespace `App\Actions` con il metodo `execute()`.
  </Accordion>

  <Accordion title="Anche Livewire usa questo meccanismo">
    Il comando `make:livewire` è implementato dalla classe `MakeCommand` che estende `GeneratorCommand`. Fa override di `handle()` per generare in una sola volta due file: la classe componente e la view Blade.
  </Accordion>
</AccordionGroup>

## Test

Con Orchestra Testbench verifichi che il comando generi correttamente il file.

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

namespace Tests\Feature\Console;

use Illuminate\Support\Facades\File;
use Orchestra\Testbench\TestCase;
use Vendor\Package\PackageServiceProvider;

class HandlerMakeCommandTest extends TestCase
{
    protected function getPackageProviders($app): array
    {
        return [PackageServiceProvider::class];
    }

    protected function tearDown(): void
    {
        File::deleteDirectory(app_path('Handlers'));

        parent::tearDown();
    }

    public function test_make_handler_creates_file(): void
    {
        $path = app_path('Handlers/OrderHandler.php');

        $this->artisan('make:handler', ['name' => 'OrderHandler'])
            ->assertSuccessful();

        $this->assertFileExists($path);
        $this->assertStringContainsString('namespace App\Handlers;', File::get($path));
        $this->assertStringContainsString('class OrderHandler', File::get($path));
    }

    public function test_make_handler_does_not_overwrite_existing_file(): void
    {
        $path = app_path('Handlers/OrderHandler.php');
        File::ensureDirectoryExists(dirname($path));
        File::put($path, '<?php // existing');

        $this->artisan('make:handler', ['name' => 'OrderHandler'])
            ->assertFailed();
    }
}
```

<Warning>
  I comandi generator scrivono nel filesystem reale. Fai sempre pulizia in `tearDown()`, così l'operazione avviene anche se un test fallisce a metà.
</Warning>

## Pagine correlate

<Columns cols={2}>
  <Card title="Sviluppo di pacchetti Laravel" icon="package" href="/it/advanced/package-development">
    Rivedi le basi dello sviluppo di pacchetti tramite service provider.
  </Card>

  <Card title="Testare pacchetti Laravel con Orchestra Testbench" icon="flask-conical" href="/it/advanced/package-testing">
    Rivedi come costruire l'infrastruttura di test per un pacchetto.
  </Card>
</Columns>

<Info>
  Fonte: [Illuminate\Console\GeneratorCommand](https://github.com/laravel/framework/blob/master/src/Illuminate/Console/GeneratorCommand.php), [Illuminate\Foundation\Console\RequestMakeCommand](https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/Console/RequestMakeCommand.php)
</Info>


## Related topics

- [Feed Generator](/it/packages/laravel-bluesky/feed-generator.md)
- [Struttura delle directory](/it/directory-structure.md)
- [Tutorial per bot - Laravel Bluesky](/it/packages/laravel-bluesky/bot-tutorial.md)
- [Cast personalizzati di Eloquent](/it/advanced/eloquent-casts.md)
- [Scope di Eloquent](/it/advanced/eloquent-scopes.md)
