Architecture Overview
+----------------------+ +----------------------+
| Main DB | | Tenant DB(s) |
| +------------------+ | | +------------------+ |
| | TenantConfig | |<---->| | Schema & Data | |
| +------------------+ | | +------------------+ |
+----------------------+ +----------------------+
EventDispatcher -> SwitchDbEvent -> TenantEntityManager switches connection
The Symfony Multi-Tenancy Bundle is built on a clear, event-driven architecture that keeps tenant data isolated while sharing a single application codebase.
- Tenant Registry & Configuration
- The Main Database stores a
TenantDbConfig
entity for each tenant. - This entity holds connection parameters (host, driver, credentials, schema name) and lifecycle timestamps.
- Dynamic Connection Switching
- At runtime—whether in an HTTP request or console command—you dispatch:
$dispatcher->dispatch(new SwitchDbEvent($tenantId));
- The bundle listens for
SwitchDbEvent
, resolves the associatedTenantDbConfig
, and reconfigures theTenantEntityManager
connection parameters on the fly.
- Isolated Entity Managers
- Main EntityManager: Manages your global and shared entities (e.g., tenants registry, application settings).
- TenantEntityManager: A separate service injected wherever you need tenant-specific operations. It automatically reconnects to the selected tenant’s database after the event is dispatched.
- Separate Migration & Fixture Paths
- Migrations for the main schema and tenant schemas live in different directories (
migrations/Main
vsmigrations/Tenant
). - Fixtures decorated with
#[TenantFixture]
only run against tenant DBs, ensuring seeding and test data remain isolated.
- Lifecycle & Error Handling
- If a tenant database doesn’t exist, you can enable on-the-fly creation.
- Connection failures throw clear exceptions, allowing you to implement retry logic or fallback strategies.
How to Use This Architecture
-
Define Your TenantConfig Create an entity in
src/Entity/Main
implementingTenantDbConfigurationInterface
(use the provided trait for convenience). -
Dispatch the Switch Event In controllers or services, dispatch
SwitchDbEvent
before any tenant operations:
public function index(EventDispatcherInterface $dispatcher, TenantEntityManager $tem)
{
$dispatcher->dispatch(new SwitchDbEvent($tenantId));
$user = (new User())->setName('Demo');
$tem->persist($user);
$tem->flush();
}
- Manage Migrations & Fixtures
-
Generate tenant migrations:
php bin/console tenant:migration:diff
-
Apply them:
php bin/console tenant:migration:migrate update
-
Load fixtures:
php bin/console tenant:fixtures:load --append
With this architecture, you maintain a single codebase but fully isolated data layers for each tenant, combining the best of multi-tenancy and Symfony’s power.