symfony/http-foundation). A Laravel-specific multi-tenancy solution (e.g., stancl/tenancy) would be a better architectural fit.Aware interface, which aligns with Laravel’s Eloquent ORM but requires custom adapters (e.g., traits/interfaces) to integrate with Laravel’s Model classes.TenantsProvider), increasing boilerplate.TenantsProvider and related services (e.g., via Laravel’s bind() or extend()).TenantAware interface to Laravel’s Model trait system.kernel.request) with Laravel’s middleware/pipeline.EntityManager hooks) in Laravel’s Eloquent context.Why Symfony-Specific?
spatie/laravel-multitenancy) achieve the same goals with less risk?Tenant Resolution Strategy
Entity Isolation Scope
TenantAware trait, or only specific ones? Partial adoption could lead to inconsistent isolation.User) be handled?Testing and Validation
Alternatives Assessment
stancl/tenancy or spatie/laravel-multitenancy been evaluated? These are Laravel-native and more mature.EventDispatcher, ContainerInterface) requires significant adaptation. Key mismatches:
TenantAware interface and entity resolution logic must be rewritten for Laravel’s Eloquent ORM.ServiceContainer differs from Laravel’s Container (e.g., no autowiring by default, different DI syntax).HandleTenants) is the standard for tenant resolution, but this bundle lacks integration points.ServiceProvider to rebind Symfony services (e.g., TenantsProvider) to Laravel’s container.TenantsProvider to abstract Symfony dependencies.kernel.request) with Laravel’s Model observers or Eloquent events.Proof of Concept (PoC)
TenantAware trait for Eloquent models:
trait TenantAware {
use \CommitM\MultiTenant\Multitenancy\TenantAware; // Hypothetical adapter
public function getTenantKey(): string { ... }
}
TenantsProvider in a service.where('company_id', auth()->tenant()->id)).Middleware Integration
TenantMiddleware to resolve tenants from the request (e.g., subdomain tenant1.app → Company::find(1)) and set context via TenantsProvider.public function handle(Request $request, Closure $next) {
$tenant = TenantResolver::resolve($request);
app(TenantsProvider::class)->setTenant($tenant);
return $next($request);
}
Doctrine-Eloquent Bridge
EntityManager or use Laravel’s Model events (retrieved, saved) to inject tenant IDs.Model::preventAccessFromNonOwnerUsing(function ($model, $user) {
if (!$model->tenant_id || $model->tenant_id !== $user->tenant_id) {
abort(403);
}
});
Configuration Layer
multi_tenant.yaml to Laravel’s config/tenancy.php:
'tenants' => [
'company_id' => [
'entity' => \App\Models\Company::class,
'aware_interface' => \App\Interfaces\TenantAware::class,
'property' => 'company_id',
],
],
config() helper to access settings.doctrine/dbal), ensure the bundle’s query listeners work with Laravel’s setup.RefreshDatabase or MigrateFresh with tenant-specific seeders.Phase 1: Core Tenancy
TenantsProvider).TenantAware to critical models (e.g., Product, Order).Phase 2: Query Scoping
TenantA cannot see TenantB data).Phase 3: Edge Cases
Phase 4: Migration
EventDispatcher) may increase deployment size and complexity.ParameterBag vs. Laravel’s Request).TenantsProvider results).EntityListener) may not scale well with Eloquent’s simpler approach.tenant_id).TenantsProvider is not reset between requests (e.g., in CLI or queue jobs), data isolation fails.TenantA updates TenantB data due to stale context.How can I help you explore Laravel packages today?