alessandrolandim/multi-user-bundle
Installation
composer require alessandrolandim/multi-user-bundle
Add the bundle to config/bundles.php:
return [
// ...
Alessandrolandim\MultiUserBundle\AlessandrolandimMultiUserBundle::class => ['all' => true],
];
Configuration
Override default settings in config/packages/alessandrolandim_multi_user.yaml:
alessandrolandim_multi_user:
user_class: App\Entity\User
user_manager: app.user_manager
# Other optional configs (see below)
First Use Case: Multi-Tenant User Switching
Inject the MultiUserManager service into a controller:
use Alessandrolandim\MultiUserBundle\Manager\MultiUserManager;
class TenantController extends AbstractController
{
public function __construct(private MultiUserManager $multiUserManager) {}
public function switchUser(Tenant $tenant, User $user)
{
$this->multiUserManager->setCurrentUser($tenant->getId(), $user);
return $this->redirectToRoute('dashboard');
}
}
Tenant-Aware User Management
// Set/get current user per tenant
$this->multiUserManager->setCurrentUser($tenantId, $user);
$currentUser = $this->multiUserManager->getCurrentUser($tenantId);
Event-Driven Extensions
Listen to multi_user.pre_switch and multi_user.post_switch events:
// src/EventListener/MultiUserListener.php
public function onPreSwitch(MultiUserEvent $event)
{
$event->getUser()->setLastSwitchAt(new \DateTime());
}
Repository Integration
Extend MultiUserRepository to add tenant-aware queries:
class TenantAwareUserRepository extends MultiUserRepository
{
public function findByTenantEmail($tenantId, $email)
{
return $this->createQueryBuilder('u')
->where('u.tenant = :tenantId')
->andWhere('u.email = :email')
->setParameter('tenantId', $tenantId)
->setParameter('email', $email)
->getQuery()
->getOneOrNullResult();
}
}
Symfony Security: Override UserProvider to respect tenant context:
class TenantUserProvider implements UserProviderInterface
{
public function loadUserByIdentifier($identifier)
{
$tenantId = $this->tenantResolver->getCurrentTenantId();
return $this->multiUserManager->findUserByEmail($tenantId, $identifier);
}
}
Doctrine Lifecycle Callbacks: Use prePersist/preUpdate to auto-set tenant:
// src/Entity/User.php
public function prePersist()
{
$this->tenant = $this->tenantResolver->getCurrentTenantId();
}
Missing Tenant Context
getCurrentUser() returns null unexpectedly.TenantResolver is properly configured and injected. Verify middleware sets the tenant early in the request lifecycle.Circular Dependencies
MultiUserManager fails to initialize with "circular reference" errors.config/services.yaml:
services:
Alessandrolandim\MultiUserBundle\Manager\MultiUserManager:
arguments:
$tenantResolver: '@tenant.resolver'
$userManager: '@app.user_manager'
tags: ['container.service_subscriber']
Event Ordering
pre_switch events fire after the user is already switched.kernel.event_dispatcher to reorder listeners:
# config/packages/alessandrolandim_multi_user.yaml
alessandrolandim_multi_user:
event_priority: 255 # Highest priority
Log Tenant Context: Add a subscriber to log tenant/user switches:
public function onPostSwitch(MultiUserEvent $event)
{
$this->logger->info('Switched to user {userId} in tenant {tenantId}',
['userId' => $event->getUser()->getId(), 'tenantId' => $event->getTenantId()]
);
}
Check Configuration
Validate user_class and user_manager in config/packages/alessandrolandim_multi_user.yaml match your actual entities/services.
Custom User Storage
Override MultiUserStorageInterface to use a non-DB backend (e.g., Redis):
class RedisUserStorage implements MultiUserStorageInterface
{
public function save($tenantId, User $user)
{
$this->redis->hSet("user:{$tenantId}", $user->getId(), json_encode($user));
}
}
Dynamic Tenant Resolution
Implement TenantResolverInterface for runtime tenant detection (e.g., subdomain):
class SubdomainTenantResolver implements TenantResolverInterface
{
public function getCurrentTenantId()
{
return substr($_SERVER['HTTP_HOST'], strrpos($_SERVER['HTTP_HOST'], '.') + 1);
}
}
Bulk Operations
Use MultiUserManager::getAllUsers() cautiously—consider pagination for large tenants:
$users = $this->multiUserManager->getAllUsers($tenantId, 10, 0);
How can I help you explore Laravel packages today?