Event-Hooks mit Doctrine-Lifecycle-Events
Event-Hooks mit Doctrine-Lifecycle-Events
~13 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
State Processor (Kapitel 58) sind der BEVORZUGTE Weg für API-PLATFORM-spezifische Logik – für Logik, die UNABHÄNGIG davon greifen soll, WIE eine Entity gespeichert wird (auch außerhalb der API), sind Doctrine-Events die richtige Wahl.
Ein Beispiel: automatisches updatedAt
// Project.php - neues Feld
#[ORM\Column(nullable: true)]
#[Groups(['project:read'])]
private ?\DateTimeImmutable $updatedAt = null;
public function getUpdatedAt(): ?\DateTimeImmutable
{
return $this->updatedAt;
}
public function setUpdatedAt(\DateTimeImmutable $updatedAt): static
{
$this->updatedAt = $updatedAt;
return $this;
}Einen Event-Listener schreiben
<?php
declare(strict_types=1);
namespace App\EventListener;
use App\Entity\Project;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener;
use Doctrine\ORM\Event\PrePersistEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Events;
#[AsEntityListener(event: Events::prePersist, entity: Project::class)]
#[AsEntityListener(event: Events::preUpdate, entity: Project::class)]
final class ProjectUpdatedAtListener
{
public function prePersist(Project $project, PrePersistEventArgs $args): void
{
$project->setUpdatedAt(new \DateTimeImmutable());
}
public function preUpdate(Project $project, PreUpdateEventArgs $args): void
{
$project->setUpdatedAt(new \DateTimeImmutable());
}
}#[AsEntityListener] registriert den Listener AUTOMATISCH bei Doctrine – prePersist feuert beim ERSTMALIGEN Speichern, preUpdate bei JEDER nachfolgenden Änderung, UNABHÄNGIG davon, ob über die API, eine Fixture oder eine Konsolen-Kommando ausgelöst.
Achtung: Der ENTSCHEIDENDE Unterschied zu Kapitel 58: ein Doctrine-Event feuert IMMER, auch bei einem bin/console-Skript OHNE jeden API-Bezug – ein State Processor greift NUR bei API-Requests. Für updatedAt ist das GEWÜNSCHTE Verhalten (IMMER aktuell, egal WIE gespeichert wird), für owner (Kapitel 54) WÄRE ein Doctrine-Event UNGEEIGNET, da Security::getUser() außerhalb eines HTTP-Requests NICHT verfügbar ist.
Wann Doctrine-Events statt Processor
| Mechanismus | Einsatzbereich |
|---|---|
| State Processor | Logik ist SPEZIFISCH für API-Requests (braucht z. B. den eingeloggten Nutzer, Request-Kontext) |
| Doctrine-Event | Logik soll IMMER greifen, unabhängig VOM Auslöser (Datenintegrität, Audit-Timestamps) |
Tipp: GENAU dieselben Doctrine-Events (prePersist, preUpdate, preRemove etc.) wurden BEREITS in der Symfony-Schulung behandelt (Kapitel 28) – das Wissen überträgt sich VOLLSTÄNDIG, NUR der Kontext (API statt klassischer Controller) ist neu.