Multi-tenancy¶
Booking is multi-tenant by default - but invisibly for single-site
installs. Every resource, slot, category and booking is stamped with a
tenant machine name; a shipped default tenant means simple sites never
think about it.
flowchart LR
REQ[Request] --> TC[TenantContext]
TC --> R1[resolver A]
TC --> R2[resolver B]
R1 -->|tenant id| TC
TC -->|first non-empty wins,<br/>else default| T[(Active tenant)]
T --> DATA[All rows filtered / stamped by tenant]
How it works¶
Tenantis a config entity (yoyaku_tenant), one shipped at install:default.TenantField::definition()provides the sharedtenantbase field every partitioned entity adds. A booking inherits its category's tenant.TenantContext(booking.tenant_context) resolves the active tenant by consulting resolvers taggedbooking.tenant_resolverin priority order, falling back todefault.TenantResolverInterface- implement and tag it to map your dimension (domain, group, siteā¦) to a tenant id.
Adding a resolver¶
# my_module.services.yml
services:
my_module.domain_tenant_resolver:
class: Drupal\my_module\DomainTenantResolver
arguments: ['@domain.negotiator']
tags:
- { name: booking.tenant_resolver, priority: 100 }
use Drupal\yoyaku\TenantResolverInterface;
final class DomainTenantResolver implements TenantResolverInterface {
public function resolveTenantId(): ?string {
// Return a tenant id, or NULL to defer to the next resolver.
}
}
Note
Capacity is always counted per category id, so categories in different tenants are independent by construction. The tenant field additionally lets consumers scope listings and access per tenant.
Tenant-scoped resource types¶
A resource type (yoyaku_resource_type) is a hybrid catalogue, the same
shape as a shared vocabulary with per-tenant additions. Its tenant property
is either empty or a tenant id:
- empty means the type is shared: it is offered in every tenant;
- set means the type is private to that tenant and offered only there.
ResourceTypeCatalogue is the single place this resolves: the types available
in a tenant are the shared types plus that tenant's own. The resource Type
selector lists only available types, and a validation constraint rejects
assigning a type from another tenant, so a resource never references a type
outside its realm.
Manage types and tenants under Booking in the admin menu (Resource types, Tenants).
Constraints are enforced per tenant¶
Order constraints (the per-customer limits) always count within the order's tenant. Even an exclusivity group spanning resources of a shared type pools per tenant: a customer holding one booking of the group in one tenant is not blocked from booking it in another. The tenant is the isolation boundary, so bookings in one realm never interfere with another.