> ## 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 — Eigene make:-Befehle implementieren

> Wie Sie durch Ableiten von Illuminate\Console\GeneratorCommand paket-eigene make:-Befehle erstellen. Von der Erstellung der Stub-Dateien bis zur Steuerung des Namensraums.

## Was ist GeneratorCommand?

`Illuminate\Console\GeneratorCommand` ist die abstrakte Basisklasse aller Code-Generierungs-Befehle in Laravel. `make:model`, `make:controller`, `make:request` usw. leiten alle von dieser Klasse ab.

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

Bietet ein Paket einen eigenen `make:xxx`-Befehl an, so muss der Nutzer keine Klassen von Hand anlegen. Ein `php artisan make:handler OrderHandler` genügt, um eine Datei mit korrektem Namensraum zu erzeugen.

<Info>
  `GeneratorCommand` wird in der offiziellen Doku kaum erwähnt und ist ohne Blick in den Framework-Code kaum zu verstehen — ein klassisches Advanced-Thema.
</Info>

## Minimale Implementierung

Die einzig zwingend erforderliche Methode in einer von `GeneratorCommand` abgeleiteten Klasse ist `getStub()`. Alle anderen Properties sind optional, in der Praxis definiert man aber typischerweise diese:

| Element                 | Typ               | Rolle                                                                         |
| ----------------------- | ----------------- | ----------------------------------------------------------------------------- |
| `$name`                 | Property          | Kommandoname (z. B. `make:handler`)                                           |
| `$description`          | Property          | Beschreibung des Befehls                                                      |
| `$type`                 | Property          | Bezeichnung des Artefakts — erscheint in der Erfolgsmeldung (z. B. `Handler`) |
| `getStub()`             | Methode (Pflicht) | Gibt den Pfad zur Stub-Datei zurück                                           |
| `getDefaultNamespace()` | Methode           | Steuert den Ziel-Namensraum                                                   |

Beispielhafte Implementierung eines `make:handler`-Befehls:

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

Mit dieser Konfiguration von `getDefaultNamespace()` legt `php artisan make:handler OrderHandler` die Klasse `App\Handlers\OrderHandler` in `app/Handlers/OrderHandler.php` an.

## Stub-Datei erstellen

Legen Sie eine Stub-Datei an dem Pfad ab, den `getStub()` zurückgibt. Ein Stub ist eine PHP-Vorlage, in der Platzhalter für Namensraum und Klassennamen ersetzt werden.

<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>

Beispiel für eine Stub-Datei:

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

namespace {{ namespace }};

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

`GeneratorCommand` ersetzt in Stubs automatisch folgende Platzhalter:

| Platzhalter           | Ersetzter Wert                  | Alternative Notation |
| --------------------- | ------------------------------- | -------------------- |
| `{{ namespace }}`     | Namensraum der erzeugten Klasse | `DummyNamespace`     |
| `{{ class }}`         | Name der erzeugten Klasse       | `DummyClass`         |
| `{{ rootNamespace }}` | Root-Namensraum der App         | `DummyRootNamespace` |

`{{ namespace }}` und `DummyNamespace` liefern das gleiche Ergebnis. In den Laravel-Stubs sind beide Formen enthalten; für neue Stubs empfehlen wir die Form `{{ namespace }}`.

## Stubs anpassbar machen

Um Nutzern zu erlauben, die Stubs zu überschreiben, nutzen Sie das `resolveStubPath()`-Muster. Zunächst veröffentlichen Sie die Stubs im `boot()` des Service Providers.

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

Danach lassen Sie `getStub()` das vom Nutzer angepasste Stub bevorzugt verwenden.

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

Nach `php artisan vendor:publish --tag=stubs` bearbeiten Nutzer die Datei `stubs/handler.stub` im Projekt-Root und passen so die Vorlage an.

<Tip>
  `resolveStubPath()` ist auch das Muster, das der eingebaute `RequestMakeCommand` nutzt. Übernehmen Sie es für veröffentlichte Pakete.
</Tip>

## Registrierung im Service Provider

Registrieren Sie den Befehl in der `boot()`-Methode Ihres Service Providers. Mit `runningInConsole()` verhindern Sie unnötiges Laden bei Web-Requests.

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

Mit `extra.laravel` in der `composer.json` Ihres Pakets müssen Nutzer den Provider nicht selbst registrieren.

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

## Anwendungsbeispiele

Wo `GeneratorCommand` glänzt:

<AccordionGroup>
  <Accordion title="Form-Request-Erweiterung">
    Ein Befehl, der Requests erzeugt, die von einer eigenen Basisklasse mit Auth-Prüfung und eigener Validierung erben. `getDefaultNamespace()` liefert `App\Http\Requests`.
  </Accordion>

  <Accordion title="DTO-Generator">
    Ein Befehl, der Boilerplate für Data Transfer Objects erzeugt. Der Stub enthält readonly-Properties und eine `from()`-Factory-Methode.
  </Accordion>

  <Accordion title="Action-Klasse">
    Ein Befehl, der Action-Klassen mit einer einzigen Verantwortlichkeit erzeugt. Er legt Klassen mit `execute()`-Methode im Namensraum `App\Actions` an.
  </Accordion>

  <Accordion title="Livewire nutzt denselben Mechanismus">
    Der Befehl `make:livewire` ist als `MakeCommand`-Klasse implementiert, die von `GeneratorCommand` erbt. Um sowohl Komponentenklasse als auch Blade-View zu erzeugen, überschreibt sie `handle()`.
  </Accordion>
</AccordionGroup>

## Tests

Mit Orchestra Testbench testen Sie, dass Ihr Befehl die Dateien korrekt erzeugt.

```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>
  Generator-Commands schreiben tatsächlich ins Dateisystem. Räumen Sie in `tearDown()` konsequent auf, damit auch bei fehlgeschlagenen Tests aufgeräumt wird.
</Warning>

## Verwandte Seiten

<Columns cols={2}>
  <Card title="Laravel-Paketentwicklung" icon="package" href="/de/advanced/package-development">
    Grundlagen der Paketentwicklung mit Service Providern.
  </Card>

  <Card title="Laravel-Pakete mit Orchestra Testbench testen" icon="flask-conical" href="/de/advanced/package-testing">
    Wie Sie die Grundlagen für Pakettests schaffen.
  </Card>
</Columns>

<Info>
  Quellen: [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](/de/packages/laravel-bluesky/feed-generator.md)
- [Eigene Auth-Guards implementieren](/de/advanced/custom-auth-guard.md)
- [Eigene Casts in Eloquent](/de/advanced/eloquent-casts.md)
- [Eigene Validierungsregeln](/de/advanced/custom-validation-rules.md)
- [Verzeichnisstruktur](/de/directory-structure.md)
