> ## 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 — implémenter des commandes make: personnalisées

> Découvrez comment créer des commandes make: propres à votre package en héritant de Illuminate\Console\GeneratorCommand. De la création du fichier stub au contrôle des namespaces, tout est présenté de manière pratique.

## Qu'est-ce que GeneratorCommand

`Illuminate\Console\GeneratorCommand` est la classe abstraite qui sert de base à toutes les commandes de génération de code de Laravel. `make:model`, `make:controller`, `make:request`, etc. héritent tous de cette classe.

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

Lorsque vous proposez une commande `make:xxx` personnalisée dans votre package, il suffit à l'utilisateur d'exécuter par exemple `php artisan make:handler OrderHandler` au lieu de créer la classe manuellement, et un fichier avec le namespace correct est généré.

<Info>
  `GeneratorCommand` n'est presque pas documenté officiellement : il faut lire directement le code source du framework pour le comprendre. C'est un sujet avancé typique.
</Info>

## Implémentation minimale

Dans une classe qui hérite de `GeneratorCommand`, seule la méthode `getStub()` est obligatoire. Les autres propriétés sont facultatives, mais en pratique on définit généralement les éléments suivants.

| Membre                  | Type                  | Rôle                                                                              |
| ----------------------- | --------------------- | --------------------------------------------------------------------------------- |
| `$name`                 | propriété             | Nom de la commande (ex. : `make:handler`)                                         |
| `$description`          | propriété             | Description de la commande                                                        |
| `$type`                 | propriété             | Nom du type d'élément généré. Utilisé dans le message de succès (ex. : `Handler`) |
| `getStub()`             | méthode (obligatoire) | Renvoie le chemin du fichier stub                                                 |
| `getDefaultNamespace()` | méthode               | Contrôle le namespace par défaut de destination                                   |

Voici un exemple d'implémentation de la commande `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';
    }
}
```

Lorsque `getDefaultNamespace()` est configuré ainsi, exécuter `php artisan make:handler OrderHandler` génère la classe `App\Handlers\OrderHandler` dans `app/Handlers/OrderHandler.php`.

## Créer le fichier stub

Placez le fichier stub au chemin renvoyé par `getStub()`. Un stub est un fichier PHP servant de modèle ; ses espaces réservés sont remplacés par le namespace et le nom de la 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>

Exemple de fichier stub :

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

namespace {{ namespace }};

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

`GeneratorCommand` remplace automatiquement les espaces réservés suivants dans le stub.

| Espace réservé        | Valeur de remplacement            | Notation alternative |
| --------------------- | --------------------------------- | -------------------- |
| `{{ namespace }}`     | Namespace de la classe générée    | `DummyNamespace`     |
| `{{ class }}`         | Nom de la classe générée          | `DummyClass`         |
| `{{ rootNamespace }}` | Namespace racine de l'application | `DummyRootNamespace` |

`{{ namespace }}` et `DummyNamespace` produisent le même résultat. Les stubs intégrés à Laravel incluaient les deux formes, mais pour toute nouvelle création, la forme `{{ namespace }}` est recommandée.

## Permettre la personnalisation des stubs

Pour offrir un mécanisme permettant aux utilisateurs de remplacer les stubs, utilisez le pattern `resolveStubPath()`. Publiez d'abord les stubs dans le `boot()` du service provider.

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

Ensuite, dans `getStub()`, donnez la priorité au stub personnalisé par l'utilisateur.

```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;
}
```

Un utilisateur qui exécute `php artisan vendor:publish --tag=stubs` peut alors éditer `stubs/handler.stub` à la racine du projet pour modifier le modèle.

<Tip>
  `resolveStubPath()` est également le pattern utilisé par `RequestMakeCommand` intégré à Laravel. Si vous publiez un package, adoptez ce pattern.
</Tip>

## Enregistrement dans le service provider

Enregistrez la commande dans la méthode `boot()` du service provider. En vérifiant `runningInConsole()`, vous évitez tout chargement inutile lors des requêtes 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');
        }
    }
}
```

En configurant `extra.laravel` dans le `composer.json` du package, vous évitez à l'utilisateur d'avoir à enregistrer le service provider manuellement.

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

## Cas d'utilisation

Voici quelques cas d'usage où `GeneratorCommand` fait briller ses atouts.

<AccordionGroup>
  <Accordion title="Extensions de Form Request">
    Une commande qui génère des Request héritant d'une classe de base propre incluant des vérifications d'authentification ou une logique de validation personnalisée. `getDefaultNamespace()` renvoie `App\Http\Requests`.
  </Accordion>

  <Accordion title="Générateur de DTO">
    Une commande qui génère le boilerplate d'un Data Transfer Object. Prévoyez un stub avec des propriétés readonly et une méthode factory `from()`.
  </Accordion>

  <Accordion title="Classes Action">
    Une commande qui génère des classes Action à responsabilité unique. Elle crée dans le namespace `App\Actions` des classes dotées d'une méthode `execute()`.
  </Accordion>

  <Accordion title="Livewire utilise le même mécanisme">
    La commande `make:livewire` est implémentée dans la classe `MakeCommand` qui hérite de `GeneratorCommand`. Elle surcharge `handle()` pour générer simultanément la classe du composant et la vue Blade.
  </Accordion>
</AccordionGroup>

## Tests

Utilisez Orchestra Testbench pour vérifier que la commande génère correctement les fichiers.

```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>
  Les commandes Generator écrivent sur le système de fichiers réel. Nettoyez impérativement dans `tearDown()`. Cela garantit l'exécution du nettoyage même si le test échoue en cours de route.
</Warning>

## Pages associées

<Columns cols={2}>
  <Card title="Développement de packages Laravel" icon="package" href="/fr/advanced/package-development">
    Découvrez les bases du développement de packages avec les service providers.
  </Card>

  <Card title="Tester des packages Laravel avec Orchestra Testbench" icon="flask-conical" href="/fr/advanced/package-testing">
    Découvrez comment mettre en place l'infrastructure de test d'un package.
  </Card>
</Columns>

<Info>
  Source : [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](/fr/packages/laravel-bluesky/feed-generator.md)
- [Structure des répertoires](/fr/directory-structure.md)
- [Tutoriel - Laravel Console Starter](/fr/packages/laravel-console-starter/tutorial.md)
- [Règles de validation personnalisées](/fr/advanced/custom-validation-rules.md)
- [Processus](/fr/processes.md)
