Events — EventDispatcher
PSR-14 dispatcher met prioriteits-based listeners. TableRepository en DynamicWriter dispatchen lifecycle-events (Before/After Insert/Update/Delete) wanneer je een EventDispatcher injecteert. Listeners op BeforeInsertEvent en BeforeUpdateEvent mogen via setData() de data muteren.
Basics — listener registreren en dispatchen
on($eventClass, $callable, priority) registreert. Hogere priority = eerst.
$provider = new ListenerProvider();
$dispatcher = new EventDispatcher($provider);
$log = [];
$provider->on(BeforeInsertEvent::class, function (BeforeInsertEvent $e) use (&$log) {
$log[] = "BEFORE: {$e->table}";
});
$provider->on(AfterInsertEvent::class, function (AfterInsertEvent $e) use (&$log) {
$log[] = "AFTER: {$e->table} id={$e->id}";
});
// Dispatch handmatig (normaal doet de repository dit voor je):
$dispatcher->dispatch(new BeforeInsertEvent('members', ['name' => 'Jan']));
$dispatcher->dispatch(new AfterInsertEvent('members', 42, ['name' => 'Jan']));
return $log;Array
(
[0] => BEFORE: members
[1] => AFTER: members id=42
)
TableRepository — automatische event-dispatch
Inject de EventDispatcher in de repo-constructor; daarna komen alle insert/update/delete-events vanzelf langs.
$pdo->exec('CREATE TABLE members (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT, name TEXT)');
$provider = new ListenerProvider();
$dispatcher = new EventDispatcher($provider);
$log = [];
foreach ([BeforeInsertEvent::class, AfterInsertEvent::class,
BeforeUpdateEvent::class, AfterUpdateEvent::class,
AfterDeleteEvent::class] as $cls) {
$provider->on($cls, function ($e) use (&$log, $cls) {
$log[] = (new ReflectionClass($cls))->getShortName();
});
}
$repo = new TableRepository($pdo, 'members', events: $dispatcher);
$id = $repo->insert(['email' => 'a@b', 'name' => 'A']);
$repo->update($id, ['name' => 'B']);
$repo->delete($id);
return $log;Array
(
[0] => BeforeInsertEvent
[1] => AfterInsertEvent
[2] => BeforeUpdateEvent
[3] => AfterUpdateEvent
[4] => AfterDeleteEvent
)
BeforeInsert / BeforeUpdate kan data muteren
setData() op het event verandert wat er naar de DB gaat — handig voor audit-velden, hashing, normalisatie.
$pdo->exec('CREATE TABLE members (id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT, name TEXT, created_at TEXT)');
$provider = new ListenerProvider();
$dispatcher = new EventDispatcher($provider);
$provider->on(BeforeInsertEvent::class, function (BeforeInsertEvent $e) {
$data = $e->getData();
$data['name'] = strtoupper($data['name']);
$data['created_at'] = date('Y-m-d H:i:s');
$e->setData($data);
});
$repo = new TableRepository($pdo, 'members', events: $dispatcher);
$id = $repo->insert(['email' => 'a@b', 'name' => 'jan']);
return $repo->find($id); // → name=JAN, created_at gevuldArray
(
[id] => 1
[email] => a@b
[name] => JAN
[created_at] => 2026-05-10 14:04:22
)
Priority — meerdere listeners voor hetzelfde event
Hogere priority loopt eerst. Default = 0.
$provider = new ListenerProvider();
$dispatcher = new EventDispatcher($provider);
$log = [];
$provider->on(BeforeInsertEvent::class, function () use (&$log) { $log[] = 'low'; }, priority: 0);
$provider->on(BeforeInsertEvent::class, function () use (&$log) { $log[] = 'high'; }, priority: 10);
$provider->on(BeforeInsertEvent::class, function () use (&$log) { $log[] = 'medium'; }, priority: 5);
$dispatcher->dispatch(new BeforeInsertEvent('x', []));
return $log; // ['high', 'medium', 'low']Array
(
[0] => high
[1] => medium
[2] => low
)
Eigen events maken
Een event is gewoon een class — geen interface verplicht (PSR-14 stoppable is optioneel via StoppableEventInterface).
final class UserRegistered {
public function __construct(public readonly int $userId, public readonly string $email) {}
}
$provider->on(UserRegistered::class, function (UserRegistered $e) {
// mail($e->email, ...);
});
$dispatcher->dispatch(new UserRegistered(42, 'jan@x.nl'));UserRegistered event-class kan elk DTO zijn — geen interface vereist.Via Kernel — `$kernel->events` en `$kernel->listeners`
Bij gebruik van de framework-Kernel zijn de dispatcher en listener-provider al gewired via de container.
// index.php / page-bootstrap
$kernel = require __DIR__ . '/bootstrap.php';
$kernel->listeners->on(AfterInsertEvent::class, function (AfterInsertEvent $e) {
error_log("Insert: {$e->table} id={$e->id}");
});
// Pages mogen de dispatcher gebruiken voor eigen events:
$kernel->events->dispatch(new MyDomainEvent(...));$kernel->events + $kernel->listeners hangen als virtual readonly properties op de Kernel.