Jak pravil jeden rakouský malíř z první poloviny 20. století: „Vždy je těžší bojovat proti víře než proti vzdělání“. Když už ale budete věřit tomu...

Eventy jsou běžnou součástí moderních PHP aplikací – umožňují reagovat na změny stavu a udržet kód přehlednější. Tento přístup ale často vede k tomu, že se byznys logika dostává do infrastrukturní vrstvy, což vede k horší čitelnosti a údržbě kódu.
V tomto článku se podíváme na doménové eventy, které přinášejí čistší architekturu a lepší oddělení byznys logiky od databázové vrstvy. Pokud právě stavíte aplikaci nebo se snažíte zpřehlednit svůj kód, doménové eventy vám mohou výrazně usnadnit život. Prozkoumáme rozdíl mezi klasickými ORM eventy a doménovými eventy a ukážeme si, jak je správně implementovat.
Event (událost) je nějaká akce nebo změna stavu, na kterou chceme reagovat. V praxi to znamená, že když v aplikaci nastane určitá situace – např. když se uloží nová entita do databáze – chceme spustit specifickou logiku, aniž bychom ji museli vkládat přímo do kódu, kde se událost stala.
Jako příklad si zvolíme vytvoření nového uživatele. Po jeho registraci mu chceme zaslat e-mail s potvrzením a zároveň mu jako poděkování připsat body do věrnostního programu.
V nejjednodušší variantě bychom kód mohli napsat takto:
$userRepository->save($user);
$emailService->sendConfirmationEmail($user);
$loyaltyService->addPoints($user);
Tento přístup má několik nevýhod:
Jak eventy pomáhají?
Místo přímého volání funkcí můžeme použít eventy. Když se v aplikaci stane něco důležitého – v našem případě vytvoření uživatele – vyvoláme event. Tento event pak mohou zachytit listeneři (posluchači), kteří provedou konkrétní akce, jako je odeslání potvrzovacího e-mailu nebo připsání bodů do věrnostního programu.
Tímto způsobem získáme několik výhod:
Doménové eventy jsou nástrojem, který pomáhá udržet kód čistý a přehledný tím, že odděluje byznys logiku od infrastruktury. Místo toho, aby se aplikace rozhodovala na základě změn v entitách (což dělají např. ORM eventy v Doctrine), doménové eventy vychází přímo z logiky aplikace – tedy z toho, co je skutečně důležité pro fungování systému.
Doménové eventy často souvisí s konceptem Domain-Driven Design (DDD) a využívají se v hexagonální architektuře. To ovšem neznamená, že by se daly použít jen v těchto přístupech – jejich výhody oceníme i v běžných aplikacích, kde chceme, aby byl kód lépe strukturovaný, testovatelný a udržitelný.
Doctrine (a jiné ORM) nám umožňuje reagovat na změny v entitách pomocí ORM eventů, např. prePersist, postUpdate nebo postFlush. Tyto eventy mohou být užitečné v situacích, kdy potřebujeme provést technickou změnu ještě před uložením entity do databáze. Dejme tomu, že pokud uživatel změní svoje jméno, můžeme v preUpdate přepočítat datum kdy má svátek a změnit ho přímo v entitě.
Co když ale potřebujeme reagovat na byznysovou změnu, třeba když se uživatel zaregistruje nebo objednávka přejde do stavu „Doručena“?
V Doctrine bychom na takovou situaci mohli reagovat v postFlush, protože až tam máme jistotu, že byla data opravdu zapsána do databáze. Takové řešení má své zásadní nevýhody:
Nejprve máme entitu uživatele, kde nastavujeme pouze e-mail:
class User
{
private string $id;
private string $email;
public function __construct(string $email)
{
$this->email = $email;
}
}
Po zavolání $entityManager->persist($user); Doctrine automaticky vyvolá svůj event postPersist. Důležité je, že tento event se volá pouze po zavolání persist(), ale změny ještě nejsou v databázi! Samotné zapsání dat proběhne až při zavolání $entityManager->flush();.
Doctrine listener pro postPersist:
use Doctrine\ORM\Event\LifecycleEventArgs;
class UserListener
{
public function postPersist(User $user, LifecycleEventArgs $args)
{
$this->emailService->sendConfirmationEmail($user);
$this->loyaltyService->addPoints($user);
}
}
Nevýhody tohoto přístupu:
V předchozím přístupu s ORM eventy jsme narazili na několik problémů – logika byla skrytá v Doctrine listeneru, nebylo jisté, zda registrace skutečně proběhne, a vazba na ORM stěžovala rozšiřitelnost. Doménové eventy tento problém řeší tím, že jsou součástí domény a jasně říkají, co se v aplikaci stalo.
Nejprve máme entitu uživatele, kde nastavujeme pouze e-mail, ale zároveň ihned vytváříme doménový event:
class User
{
private string $id;
private string $email;
private array $events = [];
public function __construct(string $email)
{
$this->email = $email;
$this->events[] = new UserRegistered($this);
}
public function releaseEvents(): array
{
$events = $this->events;
$this->events = [];
return $events;
}
}
Na rozdíl od Doctrine listeneru, který je pevně svázaný s ORM, si zde musíme sami definovat, jak se eventy budou zpracovávat. Hezky už však jde vidět, že listener je závislý na eventu UserRegistered, takže celkem jednoduše pomocí IDE zjistíme, kde všude se event používá.
class UserRegisteredListener
{
public function handle(UserRegistered $event)
{
$this->emailService->sendConfirmationEmail($event->email);
$this->loyaltyService->addPoints($event->userId);
}
}
Je důležité zmínit, že samotný příklad v tomto článku není kompletní produkční řešení. Slouží pouze k ilustraci toho, jak se doménové eventy dají používat.
Aby vše správně fungovalo, je nutné mít mechanismus pro zpracování doménových eventů. V praxi se to nejčastěji řeší pomocí jednoho centrálního posluchače ORM eventů, který zachytává a zpracovává doménové eventy po úspěšném dokončení transakce.
Tento mechanismus obvykle využívá postFlush v Doctrine, protože až v tomto momentě máme jistotu, že změny byly skutečně zapsány do databáze a není riziko, že by registrace selhala.
Proč nám v tomto případě nevadí ORM event postFlush?
Co dodat na konec? Doménové eventy představují čistší a udržitelnější přístup k práci s událostmi v aplikaci. Oproti ORM eventům nejsou skryté v infrastruktuře, ale jsou součástí domény, což výrazně zlepšuje čitelnost, testovatelnost a flexibilitu kódu.
Pokud chcete lépe oddělit byznys logiku od databázové vrstvy a zpřehlednit architekturu své aplikace, doménové eventy jsou rozhodně cesta, kterou stojí za to prozkoumat.
Lákají tě moderní přístupy v PHP, jako jsou doménové eventy, a chceš se podílet na tvorbě čistého a udržitelného kódu? Přidejte se k týmu Cognito a posouvej společně s námi hranice softwarového vývoje.
Jak pravil jeden rakouský malíř z první poloviny 20. století: „Vždy je těžší bojovat proti víře než proti vzdělání“. Když už ale budete věřit tomu...
Meta zavádí tzv. nastavení Core, což obsahuje mimo jiné významné změny v trackování kampaní, které ovlivní především charitativní organizace a org...
Sociální sítě se mění pomalu mrknutím oka a co ještě včera bylo slay, dnes už může být cringe. Rok 2025 přinese revoluční změny a nám marketérům n...