API reference¶
Everything goes through the booking.booking_manager service
(\Drupal\yoyaku\BookingManagerInterface).
$manager = \Drupal::service('booking.booking_manager');
// In services, inject \Drupal\yoyaku\BookingManagerInterface.
BookingManager¶
hold()¶
public function hold(
BookingCategoryInterface $category,
int $quantity = 1,
?int $ttl = NULL,
?string $subject = NULL,
): BookingInterface
Reserves $quantity places on $category and returns a held booking.
Runs constraint plugins and a vetoable pre-hold event, then checks and
reserves capacity atomically. $ttl overrides the resource's default hold
window (seconds). $subject is an opaque correlation handle.
Throws CapacityExceededException if it will not fit, or
BookingException if a constraint or subscriber denies it.
book()¶
public function book(
BookingCategoryInterface $category,
int $quantity = 1,
?string $subject = NULL,
): BookingInterface
Reserves and confirms in one atomic step - returns a confirmed booking
with no hold window/TTL, firing only CONFIRMED. For callers that already know
the booking is final (an operator entering an already-settled reservation,
imports, free slots), so they need not hold() then confirm(). Capacity is
checked under the same lock as hold().
confirm()¶
public function confirm(BookingInterface $booking): BookingInterface
Moves a held booking to confirmed. Throws HoldExpiredException if the
hold is no longer live.
release() / cancel()¶
public function release(BookingInterface $booking): BookingInterface // held → released
public function cancel(BookingInterface $booking): BookingInterface // confirmed → cancelled
Both free capacity. release() is for un-confirmed holds; cancel() is for
confirmed bookings.
expire()¶
public function expire(BookingInterface $booking): BookingInterface
Expires a lapsed hold (held + past deadline → expired). A safe no-op
if the booking was confirmed or extended meanwhile. Normally called by the
yoyaku_expire_holds queue worker.
extendHold()¶
public function extendHold(BookingInterface $booking, ?int $ttl = NULL): BookingInterface
Resets a live hold's expiry to now + $ttl (omit $ttl to reuse the
resource default). Throws HoldExpiredException if the hold already lapsed -
re-hold() instead. See Deposits and payment for the
short-form → long-deposit two-phase pattern.
availability() / consumed()¶
public function availability(BookingCategoryInterface $category): ?int // remaining; NULL = unlimited
public function consumed(BookingCategoryInterface $category): int // held + confirmed quantity
Exceptions¶
classDiagram
RuntimeException <|-- BookingException
BookingException <|-- CapacityExceededException
BookingException <|-- HoldExpiredException
BookingException- base; also thrown when a constraint/subscriber denies a hold.CapacityExceededException- the requested quantity does not fit.HoldExpiredException- an operation needed a live hold but it had lapsed.
All live under \Drupal\yoyaku\Exception\.
Worked example¶
use Drupal\yoyaku\Entity\BookingResource;
use Drupal\yoyaku\Entity\BookingSlot;
use Drupal\yoyaku\Entity\BookingCategory;
use Drupal\yoyaku\Exception\CapacityExceededException;
// 1. Define a resource, a slot, and a category (the capacity pool).
$resource = BookingResource::create(['label' => 'Tennis court', 'hold_ttl' => 900]);
$resource->save();
$slot = BookingSlot::create([
'resource' => $resource->id(),
'start' => strtotime('2026-07-01 10:00'),
'end' => strtotime('2026-07-01 11:00'),
]);
$slot->save();
$category = BookingCategory::create([
'slot' => $slot->id(),
'key' => 'default',
'label' => 'Court time',
'capacity' => 1,
]);
$category->save();
// 2. Hold, then confirm after payment succeeds.
$manager = \Drupal::service('booking.booking_manager');
try {
$booking = $manager->hold($category, 1, ttl: 600, subject: 'order:123');
}
catch (CapacityExceededException) {
// Show "no longer available".
}
// … payment callback …
$manager->confirm($booking);
Entity accessors¶
Each entity exposes typed getters, e.g.:
Resource:isActive(),getCapacity(),getHoldTtl(),getLeadTime(),getLeadTimeUnit().Slot:getResource(),getStart(),getEnd(),getCapacity(),isPublished(),getRule().Category:getSlot(),getKey(),getCapacity().Booking:getQuantity(),getState(),getHoldExpires(),getSubject(),isHeld(),consumes().
All carry getTenantId().