ArtisanPack UI
DocsBookingsMulti-Site

Multi-Site

Bookings v1.2.2

Site scoping is configured once for the whole ecosystem, in — not in this package's config. Set (or the key) to switch it on, and list resolvers under ...

Site scoping is configured once for the whole ecosystem, in artisanpack.core.multi_tenant — not in this package's config. Set ARTISANPACK_MULTI_TENANT_ENABLED=true (or the enabled key) to switch it on, and list resolvers under artisanpack.core.multi_tenant.resolvers.

Every owned table carries a nullable site_id, and models using Models\Concerns\BelongsToSite filter on whatever ArtisanPackUI\Core\MultiTenancy\SiteContext reports — so a request cannot be site 2 for one ArtisanPack package while being site 1 for this one.

Pinning a site

Work that has to target or span a specific site pins one explicitly, which is what a console command looping over sites needs:

use ArtisanPackUI\Core\Facades\ArtisanPackSite;

ArtisanPackSite::forSite( $siteId, fn () => /* every bookings query answers for $siteId */ );
ArtisanPackSite::withoutSite( fn () => /* unscoped, for maintenance work */ );

acrossAllSites() sees rows in every site, including those written before scoping was enabled.

Enabling on an existing installation

Enabling scoping on an installation that already holds bookings needs site_id backfilled first: rows written while it was off carry a null site_id, and the scope matches on equality, so they leave every site-scoped query the moment a site resolves. acrossAllSites() still sees them.

Interactions to know

  • Series edits run pinned to the series' own site, not the ambient one — see Recurring Bookings.
  • Manage / iCal tokens answer 404 for a token belonging to another site, with the same message as an unknown token — see Manage Tokens.
  • Webhook dispatch left without a site id is scoped to the site in context, which in console is none — and therefore all. Pass the site to WebhookDispatcher::dispatch() when you know it. See Webhooks.

Site resolution is a core contract

Site resolution is not a bookings contract — it is ArtisanPackUI\Core\Contracts\SiteResolver, bound once for the whole ecosystem. With cms-framework installed, artisanpack-ui/core applies its ap.cmsFramework.currentSite.resolve on the package's behalf. See CMS Framework.

Stay in the Loop

Monthly tips, tutorials and package updates — plus a free Quick Start cheat sheet.

Subscribe
Edit this page on GitHub