Events¶
The engine dispatches Symfony events at every lifecycle transition so
consumers (mail, payment, workflow, logging) can react without the core
knowing they exist. Event names are constants on
\Drupal\yoyaku\Event\BookingEvents.
Event catalogue¶
| Constant | Name | Event class | When |
|---|---|---|---|
HOLD_REQUESTED |
booking.hold_requested |
BookingHoldRequestedEvent |
Before a hold - vetoable. |
HELD |
booking.held |
BookingEvent |
After a hold is created. |
CONFIRMED |
booking.confirmed |
BookingEvent |
After confirm(). |
RELEASED |
booking.released |
BookingEvent |
After release(). |
EXPIRED |
booking.expired |
BookingEvent |
After a hold expires. |
CANCELLED |
booking.cancelled |
BookingEvent |
After cancel(). |
HOLD_EXTENDED |
booking.hold_extended |
BookingEvent |
After extendHold(). |
BookingEvent exposes the readonly ->booking. Transition events fire
after the transaction commits (the row lock is released first), so
subscribers can safely do slow work.
Where they fire¶
sequenceDiagram
participant Caller
participant BM as BookingManager
participant D as Dispatcher
Caller->>BM: hold()
BM->>D: HOLD_REQUESTED (vetoable)
alt denied
D-->>BM: deny(reason)
BM-->>Caller: BookingException
else allowed
BM->>BM: txn + lock + reserve + COMMIT
BM->>D: HELD
BM-->>Caller: booking
end
Caller->>BM: confirm()
BM->>BM: txn + lock + COMMIT
BM->>D: CONFIRMED
Vetoing a hold¶
Subscribe to HOLD_REQUESTED and call deny() to block a hold for any reason
the built-in capacity check does not cover. The category, requested quantity
and subject are available on the event.
use Drupal\yoyaku\Event\BookingEvents;
use Drupal\yoyaku\Event\BookingHoldRequestedEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
final class MyBookingRules implements EventSubscriberInterface {
public static function getSubscribedEvents(): array {
return [BookingEvents::HOLD_REQUESTED => 'onHoldRequested'];
}
public function onHoldRequested(BookingHoldRequestedEvent $event): void {
if ($event->quantity > 4) {
$event->deny('At most 4 places per booking.');
}
}
}
Tip
For reusable, configurable rules prefer a constraint plugin; use the vetoable event for one-off or contextual logic.
Reacting to a confirmed booking¶
use Drupal\yoyaku\Event\BookingEvent;
use Drupal\yoyaku\Event\BookingEvents;
public static function getSubscribedEvents(): array {
return [BookingEvents::CONFIRMED => 'onConfirmed'];
}
public function onConfirmed(BookingEvent $event): void {
$booking = $event->booking;
// Send a confirmation email, issue a ticket, notify a workflow…
}