Die EventDispatcher-Komponente von Symfony ermöglicht die Kommunikation zwischen verschiedenen Teilen einer Anwendung durch das Versenden und Empfangen von Ereignissen. Dies fördert eine lose Kopplung und erhöht die Flexibilität und Erweiterbarkeit Ihrer Anwendung.
In diesem Artikel werden wir die folgenden Themen ausführlich behandeln:
- Einführung in die EventDispatcher-Komponente
- Eingebaute Symfony-Ereignisse
- Erstellen benutzerdefinierter Ereignisse
- Event Listener vs. Event Subscriber
- Praktische Anwendungsfälle
1. Einführung in die EventDispatcher-Komponente
1.1 Was ist der Event Dispatcher?
Der Event Dispatcher ist ein zentraler Bestandteil des Observer-Patterns, der es ermöglicht, dass verschiedene Teile einer Anwendung miteinander kommunizieren, ohne direkt voneinander abhängig zu sein. Komponenten können Ereignisse auslösen, auf die andere Komponenten mit Listenern oder Subscribern reagieren können.
1.2 Vorteile der Verwendung von Ereignissen
- Lose Kopplung: Komponenten müssen nicht direkt miteinander kommunizieren.
- Erweiterbarkeit: Neue Funktionalitäten können hinzugefügt werden, indem auf bestehende Ereignisse reagiert wird.
- Wartbarkeit: Änderungen an einem Teil der Anwendung beeinflussen nicht direkt andere Teile.
1.3 Installation der EventDispatcher-Komponente
Falls nicht bereits installiert, können Sie die Komponente mit Composer hinzufügen:
composer require symfony/event-dispatcher
2. Eingebaute Symfony-Ereignisse
Symfony löst viele Ereignisse während des Anfrage-/Antwortzyklus aus, auf die Sie reagieren können.
2.1 Kern-Ereignisse
- Kernel Events: Ereignisse, die vom HttpKernel ausgelöst werden.
- kernel.request: Bevor die Anfrage verarbeitet wird.
- kernel.controller: Bevor der Controller aufgerufen wird.
- kernel.response: Bevor die Antwort gesendet wird.
- kernel.exception: Wenn eine Ausnahme auftritt.
- kernel.terminate: Nach dem Senden der Antwort (für Hintergrundaufgaben).
2.2 Beispiel: Verwenden des kernel.request
-Ereignisses
Schritt 1: Erstellen eines Event Listeners
// src/EventListener/RequestLoggerListener.php
namespace App\EventListener;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Psr\Log\LoggerInterface;
class RequestLoggerListener
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
$this->logger->info('Neue Anfrage: ' . $request->getUri());
}
}
Schritt 2: Registrieren des Event Listeners
In Ihrer services.yaml
:
# config/services.yaml
services:
App\EventListener\RequestLoggerListener:
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
2.3 Prioritäten von Ereignissen
Sie können die Priorität eines Event Listeners festlegen, um zu bestimmen, in welcher Reihenfolge die Listener ausgeführt werden. Höhere Zahlen haben höhere Priorität.
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 10 }
3. Erstellen benutzerdefinierter Ereignisse
Neben den eingebauten Ereignissen können Sie eigene Ereignisse definieren und auslösen.
3.1 Erstellen einer benutzerdefinierten Ereignisklasse
Beispiel:
Angenommen, Sie möchten ein Ereignis auslösen, wenn ein Benutzer registriert wird.
// src/Event/UserRegisteredEvent.php
namespace App\Event;
use App\Entity\User;
use Symfony\Contracts\EventDispatcher\Event;
class UserRegisteredEvent extends Event
{
public const NAME = 'user.registered';
private User $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function getUser(): User
{
return $this->user;
}
}
3.2 Auslösen des Ereignisses
In Ihrem Controller oder Service:
// src/Controller/RegistrationController.php
namespace App\Controller;
use App\Entity\User;
use App\Event\UserRegisteredEvent;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class RegistrationController extends AbstractController
{
#[Route('/register', name: 'user_register')]
public function register(
Request $request,
EntityManagerInterface $entityManager,
EventDispatcherInterface $eventDispatcher
): Response {
// Annahme: Formularverarbeitung und Benutzererstellung sind hier implementiert
$user = new User();
// ... Formularverarbeitung ...
// Benutzer speichern
$entityManager->persist($user);
$entityManager->flush();
// Ereignis auslösen
$event = new UserRegisteredEvent($user);
$eventDispatcher->dispatch($event, UserRegisteredEvent::NAME);
return new Response('Benutzer registriert!');
}
}
3.3 Erstellen eines Event Listeners für das benutzerdefinierte Ereignis
// src/EventListener/WelcomeEmailListener.php
namespace App\EventListener;
use App\Event\UserRegisteredEvent;
use App\Service\MailerService;
class WelcomeEmailListener
{
private MailerService $mailer;
public function __construct(MailerService $mailer)
{
$this->mailer = $mailer;
}
public function onUserRegistered(UserRegisteredEvent $event)
{
$user = $event->getUser();
$this->mailer->sendWelcomeEmail($user);
}
}
Registrieren des Event Listeners:
# config/services.yaml
services:
App\EventListener\WelcomeEmailListener:
tags:
- { name: kernel.event_listener, event: user.registered, method: onUserRegistered }
4. Event Listener vs. Event Subscriber
4.1 Event Listener
- Definition: Eine Klasse oder Funktion, die auf ein bestimmtes Ereignis reagiert.
- Registrierung: Direkt in der Service-Konfiguration, wobei das Ereignis und die Methode angegeben werden.
- Vorteil: Einfach zu implementieren für einzelne Ereignisse.
Beispiel:
Siehe WelcomeEmailListener
oben.
4.2 Event Subscriber
- Definition: Eine Klasse, die mehrere Ereignisse abonniert und die entsprechenden Methoden bereitstellt.
- Implementierung: Implementiert das
EventSubscriberInterface
. - Vorteil: Besser organisiert, wenn eine Klasse auf mehrere Ereignisse reagieren soll.
Beispiel eines Event Subscribers:
// src/EventSubscriber/UserActivitySubscriber.php
namespace App\EventSubscriber;
use App\Event\UserRegisteredEvent;
use App\Event\UserDeletedEvent;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class UserActivitySubscriber implements EventSubscriberInterface
{
private LoggerInterface $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public static function getSubscribedEvents(): array
{
return [
UserRegisteredEvent::NAME => 'onUserRegistered',
UserDeletedEvent::NAME => 'onUserDeleted',
];
}
public function onUserRegistered(UserRegisteredEvent $event)
{
$user = $event->getUser();
$this->logger->info('Neuer Benutzer registriert: ' . $user->getEmail());
}
public function onUserDeleted(UserDeletedEvent $event)
{
$user = $event->getUser();
$this->logger->info('Benutzer gelöscht: ' . $user->getEmail());
}
}
Registrieren des Event Subscribers:
# config/services.yaml
services:
App\EventSubscriber\UserActivitySubscriber:
tags:
- { name: kernel.event_subscriber }
4.3 Unterschiede zwischen Listener und Subscriber
Event Listener:
- Reagiert auf ein spezifisches Ereignis.
- Wird in der Service-Konfiguration registriert.
- Einfach für einzelne Ereignisse.
Event Subscriber:
- Kann mehrere Ereignisse abonnieren.
- Implementiert
EventSubscriberInterface
. - Bessere Organisation bei mehreren Ereignissen.
5. Praktische Anwendungsfälle
5.1 Senden von Benachrichtigungen
- Anwendung: Senden von E-Mails oder Push-Benachrichtigungen, wenn bestimmte Aktionen stattfinden (z. B. neue Bestellung, Passwortänderung).
- Implementierung: Erstellen eines Ereignisses und eines entsprechenden Listeners oder Subscribers, der die Benachrichtigung sendet.
5.2 Protokollierung und Monitoring
- Anwendung: Protokollieren von Benutzeraktivitäten, Ausnahmen oder Systemereignissen.
- Implementierung: Listener oder Subscriber, die auf Ereignisse wie
kernel.exception
reagieren und die Informationen protokollieren.
5.3 Modifikation von Anfragen und Antworten
- Anwendung: Hinzufügen von Headern zu Antworten, Umleiten von Anfragen, Modifizieren von Inhalten.
- Implementierung: Verwenden von Kernel-Ereignissen wie
kernel.request
,kernel.response
.
Beispiel: Hinzufügen eines Sicherheits-Headers
// src/EventSubscriber/SecurityHeaderSubscriber.php
namespace App\EventSubscriber;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
class SecurityHeaderSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'kernel.response' => 'onKernelResponse',
];
}
public function onKernelResponse(ResponseEvent $event)
{
$response = $event->getResponse();
$response->headers->set('X-Frame-Options', 'DENY');
}
}
5.4 Validierung und Authentifizierung
- Anwendung: Validieren von Anfragen, Überprüfen von Berechtigungen.
- Implementierung: Listener für
kernel.controller
oderkernel.request
, die vor der Ausführung des Controllers bestimmte Checks durchführen.
5.5 Caching und Performance
- Anwendung: Implementieren von Caching-Mechanismen, um die Performance zu verbessern.
- Implementierung: Listener oder Subscriber, die Inhalte zwischenspeichern oder aus dem Cache liefern.
Zusammenfassung
- Event Dispatcher: Ermöglicht die Kommunikation zwischen verschiedenen Teilen der Anwendung durch Ereignisse.
- Eingebaute Ereignisse: Symfony stellt viele Ereignisse bereit, auf die Sie reagieren können.
- Benutzerdefinierte Ereignisse: Sie können eigene Ereignisse erstellen, um auf spezifische Aktionen zu reagieren.
- Event Listener vs. Subscriber: Listener reagieren auf einzelne Ereignisse, Subscriber können mehrere Ereignisse abonnieren.
- Praktische Anwendungsfälle: Benachrichtigungen, Protokollierung, Anfrage-/Antwort-Modifikation, Validierung, Caching.
Weiterführende Ressourcen