atwx / silverstripe-tenancy
Multi-tenancy for Silverstripe apps: tenant resolution by host, automatic query scoping and tenant membership.
Package info
github.com/atwx/silverstripe-tenancy
Type:silverstripe-vendormodule
pkg:composer/atwx/silverstripe-tenancy
Requires
- php: ^8.3
- silverstripe/framework: ^6
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-28 10:57:59 UTC
README
Multi-tenancy for Silverstripe 6 applications (e.g. frontdesk-kit apps):
Tenantwith severalTenantDomains andTenantMemberships (member + role)TenantResolverwith pluggable strategies (host, back-office session, default tenant)TenantScopedExtension: automatic query scoping viaaugmentSQL, fail-closed (no current tenant → no records), tenant assigned on write, records can't move between tenantsTenantScopeto opt out explicitly for platform code, tasks and jobs
Installation
composer require atwx/silverstripe-tenancy
Usage
Scope a model (apply to the base class of a hierarchy):
App\Model\Form: extensions: - Atwx\Tenancy\Extension\TenantScopedExtension
Form::get(); // only records of the current tenant TenantResolver::singleton()->current(); // ?Tenant TenantResolver::singleton()->withTenant($t, fn () => Form::get()->count()); TenantScope::withoutScope(fn () => Form::get()->count()); // all tenants TenantScope::unscoped(Form::get()); // single list without filter
Templates: $CurrentTenant.
Resolution
Strategies are configured on Atwx\Tenancy\TenantResolver.strategies and asked in order:
| Strategy | Behaviour |
|---|---|
HostStrategy |
exact match of the request host against TenantDomain.Domain (active tenants only) |
SessionStrategy |
tenant chosen in a back-office switcher (SessionStrategy::remember()), only on hosts that belong to no tenant and only if the member may access the tenant |
DefaultTenantStrategy |
tenant flagged IsDefault (not enabled by default) |
Custom strategies implement ResolverStrategy.
Access
Tenant::canAccess($member) is true for members of the tenant and for members with
ADMIN or TENANCY_ACCESS_ALL. Member::AccessibleTenants() lists the tenants a
member may switch to. Roles are configurable via TenantMembership.roles.
Caveats
- Versioned models: the filter is added to the base query; test scoping on
_Livetables if you scope versioned models. - Raw SQL (
DB::query,SQLSelect) is not scoped.
Tests
From a project root with this module installed (the DB user needs CREATE DATABASE):
vendor/bin/phpunit vendor/atwx/silverstripe-tenancy/tests