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

# Events und Listener

> Erfahren Sie, wie Sie mit dem Event-System von Laravel die Komponenten Ihrer Anwendung lose gekoppelt halten.

## Was sind Events?

Das Event-System von Laravel ist eine schlanke Umsetzung des Observer-Musters.
Sie feuern innerhalb der Anwendung Ereignisse (Events) und definieren Listener, die darauf reagieren – Abhängigkeiten zwischen Komponenten bleiben so minimal.

Wird zum Beispiel das Event „Bestellung wurde bestätigt" ausgelöst, arbeiten mehrere Listener unabhängig voneinander: „Bestätigungs-E-Mail versenden", „Bestand reduzieren", „Slack benachrichtigen".
Die Bestellungslogik selbst muss weder E-Mail-Versand noch Slack-Notifications kennen.

<Info>
  Event-Klassen liegen im Verzeichnis `app/Events`, Listener-Klassen in `app/Listeners`.
  Existieren die Verzeichnisse noch nicht, legen die Artisan-Befehle sie automatisch an.
</Info>

```mermaid theme={null}
flowchart TD
    A["Event auslösen<br>dispatch()"] --> B["Event-Dispatcher"]
    B --> C["Listener 1<br>(synchron)"]
    B --> D["Listener 2<br>(synchron)"]
    B --> E["Listener 3<br>ShouldQueue implementiert"]
    C --> F["Sofort ausgeführt"]
    D --> G["Sofort ausgeführt"]
    E --> H["In die Queue gelegt"]
    H --> I["Worker führt asynchron aus"]
```

## Events und Listener erzeugen

Mit den Artisan-Befehlen `make:event` und `make:listener` erstellen Sie das jeweilige Grundgerüst.

```bash theme={null}
php artisan make:event UserRegistered

php artisan make:listener SendWelcomeEmail --event=UserRegistered
```

Ohne Argument fragt der Befehl die Angaben interaktiv ab.

```bash theme={null}
php artisan make:event

php artisan make:listener
```

## Events registrieren

### Event Discovery (automatisch)

Standardmäßig durchsucht Laravel das Verzeichnis `app/Listeners` und registriert Listener automatisch.
Die Zuordnung zu einem Event erfolgt anhand des Argumenttyps der Methode `handle` bzw. `__invoke`.

```php theme={null}
use App\Events\UserRegistered;

class SendWelcomeEmail
{
    public function handle(UserRegistered $event): void
    {
        // Willkommens-E-Mail senden
    }
}
```

Mit PHP-Union-Types kann eine Methode auf mehrere Events reagieren.

```php theme={null}
public function handle(UserRegistered|UserUpdated $event): void
{
    // ...
}
```

Legen Sie Ihre Listener in ein anderes Verzeichnis, geben Sie zusätzliche Suchpfade in `bootstrap/app.php` an.

```php theme={null}
->withEvents(discover: [
    __DIR__.'/../app/Domain/Orders/Listeners',
])
```

Mit einem Wildcard-Muster erfassen Sie mehrere Verzeichnisse in einer Angabe.

```php theme={null}
->withEvents(discover: [
    __DIR__.'/../app/Domain/*/Listeners',
])
```

Alle registrierten Listener sehen Sie mit dem folgenden Befehl:

```bash theme={null}
php artisan event:list
```

<Tip>
  Cachen Sie das Listener-Manifest in der Produktion für bessere Performance.
  Führen Sie beim Deployment `php artisan optimize` oder `php artisan event:cache` aus.
  Zum Löschen des Caches verwenden Sie `php artisan event:clear`.
</Tip>

### Manuelle Registrierung

Sie können Listener in der `boot`-Methode Ihres `AppServiceProvider` über die `Event`-Facade auch manuell registrieren.

```php theme={null}
use App\Events\UserRegistered;
use App\Listeners\SendWelcomeEmail;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(
        UserRegistered::class,
        SendWelcomeEmail::class,
    );
}
```

Auch die Registrierung über eine Closure ist möglich.

```php theme={null}
use App\Events\UserRegistered;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::listen(function (UserRegistered $event) {
        // ...
    });
}
```

## Events definieren

Event-Klassen sind einfache Datenträger. Sie enthalten keine Logik, sondern halten die zum Event gehörenden Informationen als Properties.

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

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}
```

Das Trait `SerializesModels` sorgt dafür, dass Eloquent-Modelle beim Serialisieren des Events für die Queue korrekt behandelt werden.

## Events auslösen

Feuern Sie Events über die statische Methode `dispatch` oder den Helper `event()`.

```php theme={null}
use App\Events\UserRegistered;

// Statische Methode
UserRegistered::dispatch($user);

// Helper-Funktion
event(new UserRegistered($user));
```

Für bedingtes Auslösen stehen ebenfalls Methoden bereit.

```php theme={null}
UserRegistered::dispatchIf($condition, $user);

UserRegistered::dispatchUnless($condition, $user);
```

### Auslösen nach einer Datenbanktransaktion

Möchten Sie ein Event erst nach dem Commit einer Transaktion auslösen, implementieren Sie in der Event-Klasse `ShouldDispatchAfterCommit`.
Bei einem Rollback wird das Event verworfen.

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

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class UserRegistered implements ShouldDispatchAfterCommit
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(
        public User $user,
    ) {}
}
```

## Listener implementieren

Ein Listener empfängt das Event in der Methode `handle`.
Abhängigkeiten im Konstruktor löst der Service Container automatisch auf.

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

namespace App\Listeners;

use App\Events\UserRegistered;
use App\Mail\WelcomeMail;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmail
{
    public function __construct() {}

    public function handle(UserRegistered $event): void
    {
        Mail::to($event->user->email)
            ->send(new WelcomeMail($event->user));
    }
}
```

Gibt die Methode `handle` `false` zurück, wird die Weitergabe des Events an nachfolgende Listener gestoppt.

## Listener in der Queue

Zeitaufwendige Aufgaben – etwa E-Mail-Versand oder HTTP-Anfragen – können asynchron in einer Queue laufen.
Es genügt, das Interface `ShouldQueue` zu implementieren; beim Auslösen des Events wird der Listener automatisch in die Queue gestellt.

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

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // Wird vom Queue-Worker asynchron ausgeführt
    }
}
```

<Info>
  Vor der Nutzung von queued Listenern müssen Sie die Queue konfigurieren und einen Worker starten.
  Details finden Sie auf der Seite [Queues und Jobs](/de/queues).
</Info>

### Connection, Queue-Name und Delay anpassen

Über PHP-Attribute legen Sie Zielverbindung, Queue-Name und Verzögerung fest.

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

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\Attributes\Connection;
use Illuminate\Queue\Attributes\Delay;
use Illuminate\Queue\Attributes\Queue;

#[Connection('redis')]
#[Queue('emails')]
#[Delay(10)]
class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event): void
    {
        // ...
    }
}
```

Auch dynamische Werte über Methoden sind möglich.

```php theme={null}
public function viaConnection(): string
{
    return 'redis';
}

public function viaQueue(): string
{
    return 'emails';
}

public function withDelay(UserRegistered $event): int
{
    return 10;
}
```

### Anzahl Versuche und Timeout

Mit den Attributen `#[Tries]` und `#[Timeout]` steuern Sie das Verhalten bei Fehlschlägen.

```php theme={null}
use Illuminate\Queue\Attributes\Tries;
use Illuminate\Queue\Attributes\Timeout;

#[Tries(3)]
#[Timeout(30)]
class SendWelcomeEmail implements ShouldQueue
{
    // ...
}
```

### Fehlerbehandlung

Definieren Sie die Methode `failed`, um nach überschrittener Versuchsanzahl aufzuräumen.

```php theme={null}
use Throwable;

public function failed(UserRegistered $event, Throwable $exception): void
{
    // Administrator benachrichtigen usw.
}
```

## Event-Subscriber

Event-Subscriber fassen mehrere zusammengehörige Event-Handler in einer Klasse zusammen.

### Subscriber erstellen

Aus der Methode `subscribe` geben Sie ein Array zurück, das Events auf Handler-Methoden abbildet.

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

namespace App\Listeners;

use Illuminate\Auth\Events\Login;
use Illuminate\Auth\Events\Logout;
use Illuminate\Events\Dispatcher;

class UserActivitySubscriber
{
    public function handleLogin(Login $event): void
    {
        // Login verarbeiten
    }

    public function handleLogout(Logout $event): void
    {
        // Logout verarbeiten
    }

    /**
     * @return array<string, string>
     */
    public function subscribe(Dispatcher $events): array
    {
        return [
            Login::class => 'handleLogin',
            Logout::class => 'handleLogout',
        ];
    }
}
```

### Subscriber registrieren

Ist Event Discovery aktiv, werden Subscriber, deren `subscribe`-Methode ein Array zurückgibt, automatisch registriert.
Für eine manuelle Registrierung nutzen Sie in der `boot`-Methode Ihres `AppServiceProvider` `Event::subscribe`.

```php theme={null}
use App\Listeners\UserActivitySubscriber;
use Illuminate\Support\Facades\Event;

public function boot(): void
{
    Event::subscribe(UserActivitySubscriber::class);
}
```

## Praxisbeispiel: Willkommens-E-Mail bei Registrierung senden

<Steps>
  <Step title="Event-Klasse erstellen">
    ```bash theme={null}
    php artisan make:event UserRegistered
    ```

    Ergänzen Sie in `app/Events/UserRegistered.php` eine Property für den registrierten Nutzer.

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

    namespace App\Events;

    use App\Models\User;
    use Illuminate\Broadcasting\InteractsWithSockets;
    use Illuminate\Foundation\Events\Dispatchable;
    use Illuminate\Queue\SerializesModels;

    class UserRegistered
    {
        use Dispatchable, InteractsWithSockets, SerializesModels;

        public function __construct(
            public User $user,
        ) {}
    }
    ```
  </Step>

  <Step title="Listener-Klasse erstellen">
    ```bash theme={null}
    php artisan make:listener SendWelcomeEmail --event=UserRegistered
    ```

    Um den E-Mail-Versand asynchron über die Queue auszuführen, implementieren Sie `ShouldQueue`.

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

    namespace App\Listeners;

    use App\Events\UserRegistered;
    use App\Mail\WelcomeMail;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Support\Facades\Mail;

    class SendWelcomeEmail implements ShouldQueue
    {
        public function handle(UserRegistered $event): void
        {
            Mail::to($event->user->email)
                ->send(new WelcomeMail($event->user));
        }
    }
    ```
  </Step>

  <Step title="Event im Controller auslösen">
    Nach der Registrierung rufen Sie `UserRegistered::dispatch()` auf.

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

    namespace App\Http\Controllers\Auth;

    use App\Events\UserRegistered;
    use App\Models\User;
    use Illuminate\Http\RedirectResponse;
    use Illuminate\Http\Request;

    class RegisterController extends Controller
    {
        public function store(Request $request): RedirectResponse
        {
            $user = User::create($request->validated());

            UserRegistered::dispatch($user);

            return redirect('/dashboard');
        }
    }
    ```

    Der `RegisterController` löst nur das Event `UserRegistered` aus und weiß nichts vom E-Mail-Versand.
    Auch wenn später eine Slack-Benachrichtigung dazukommt, bleibt der Controller unverändert.
  </Step>

  <Step title="Worker starten">
    Um queued Listener zu verarbeiten, starten Sie einen Queue-Worker.

    ```bash theme={null}
    php artisan queue:work
    ```
  </Step>
</Steps>

<Tip>
  Ist Event Discovery aktiv, ist keine manuelle Registrierung im `AppServiceProvider` nötig.
  Listener in `app/Listeners` werden automatisch erkannt.
</Tip>

<Warning>
  Mit `php artisan event:list` prüfen Sie die Liste registrierter Events und Listener.
  Kontrollieren Sie regelmäßig, ob keine unerwarteten Listener registriert sind.
</Warning>


## Related topics

- [Eloquent-Observer und Modell-Events](/de/advanced/eloquent-observers.md)
- [Laravel Telescope – Praxistechniken](/de/blog/telescope-introduction.md)
- [FAQ zur neuen App-Struktur ab Laravel 11](/de/advanced/app-structure-faq.md)
- [Events](/de/packages/laravel-copilot-sdk/events.md)
- [send() und on()](/de/packages/laravel-copilot-sdk/send-on.md)
