Search by

atwx / silverstripe-tenancy

adiwidjaja

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

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main / 1.x-dev 2026-10-27 17:48 UTC

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):

  • Tenant with several TenantDomains and TenantMemberships (member + role)
  • TenantResolver with pluggable strategies (host, back-office session, default tenant)
  • TenantScopedExtension: automatic query scoping via augmentSQL, fail-closed (no current tenant → no records), tenant assigned on write, records can't move between tenants
  • TenantScope to 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 _Live tables 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