Skip to content

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().