https://github.com/apajo/symfony-multi-tenancy-bundle
Multi tenancy bundle for Symfony
https://github.com/apajo/symfony-multi-tenancy-bundle
Last synced: 26 days ago
JSON representation
Multi tenancy bundle for Symfony
- Host: GitHub
- URL: https://github.com/apajo/symfony-multi-tenancy-bundle
- Owner: apajo
- Created: 2024-06-10T01:37:12.000Z (11 months ago)
- Default Branch: master
- Last Pushed: 2025-02-18T02:27:03.000Z (3 months ago)
- Last Synced: 2025-02-24T08:05:43.632Z (3 months ago)
- Language: PHP
- Size: 130 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Symfony Multi Tenancy Bundle
## DescriptionThere are many packages that provide multi tenancy in Symfony.
All of them provide only different database configuration per tenant.This package's goal is to provide a way to manage any kind of configuration in your system.
This bundle aims to provide multi tenancy on a higher level. It provides a way to dynamically
change the system configuration based on the tenant (database, media provider, mailer etc).It also bundles a way to manage migrations for each tenant.
The package's development is in early stages, any feedback is welcome.
## Requirements
- [Symfony 6.4 / 7.1](https://www.symfony.com/)
- [Doctrine Bundle 2.12](https://github.com/doctrine/DoctrineBundle.git)
- [Doctrine Migrations Bundle 3.3](https://github.com/doctrine/migrations.git)
- [Symfony Security Bundley](https://symfony.com/components/Security%20Bundle)
- [PHP 8.2](https://www.php.com/)Installation
============Make sure Composer is installed globally, as explained in the
[installation chapter](https://getcomposer.org/doc/00-intro.md)
of the Composer documentation.Applications that use Symfony Flex
----------------------------------Open a command console, enter your project directory and execute:
```bash
composer require apajo/symfony-multi-tenancy-bundle
```Applications that don't use Symfony Flex
----------------------------------------### Step 1: Download the Bundle
Open a command console, enter your project directory and execute the
following command to download the latest stable version of this bundle:```bash
composer require apajo/symfony-multi-tenancy-bundle
```### Step 2: Enable the Bundle
Then, enable the bundle by adding it to the list of registered bundles
in the `config/bundles.php` file of your project:```php
// config/bundles.phpreturn [
// ...
aPajo\MultiTenancyBundle\APajoMultiTenancyBundle::class => ['all' => true],
];
```## Configuration
To change your
### doctrine.yml
You need 2 connections and entity_managers:
```yaml
doctrine:
dbal:
default_connection: default
connections:
default:
url: '%env(DEFAULT_DATABASE_URL)%'
driver: pdo_mysql
charset: utf8
server_version: '8'tenant:
url: '%env(TENANT_DATABASE_URL)%'
driver: pdo_mysql
charset: utf8
server_version: '8'orm:
default_entity_manager: default
auto_generate_proxy_classes: true
entity_managers:
default:
connection: default
naming_strategy: doctrine.orm.naming_strategy.underscore_number_awaretenant:
connection: tenant
naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
mappings:
```In this case thay are named `default` and `tenant` but you can name them as you wish.
> __NB!__ Third party packages may require the `default` connection to be present so you might want to keep the `default` name.
Connection and entity manager `default` are common for all the individual tenants.
Connection and entity manager `tenant` are specific for the tenant.## apajo_multi_tenancy.yml
```yaml
apajo_multi_tenancy:
adapters: # Adapters dynamically change the system configuration for selected tenant
- aPajo\MultiTenancyBundle\Adapter\Database\DatabaseAdapter
- aPajo\MultiTenancyBundle\Adapter\Filesystem\FilesystemAdapter
- aPajo\MultiTenancyBundle\Adapter\Mailer\MailerAdapter
tenant: # Tenant (entity) configuration
class: App\Entity\Tenant # Must implement TenantInterface
identifier: key # Identifier column name (must be unique field)
entity_manager: default # Tenant entity manager name
resolvers: # Resolvers resolve the tenant based on the request
- aPajo\MultiTenancyBundle\Service\Resolver\HostBasedResolver
migrations: # Tenant Migration configurations
default: 'config/migrations/default.yml'
tenant: 'config/migrations/tenant.yml'
```## services.yml
Every adapter you use must be registered as a service.
Example of the built-in ones:```yaml
services:
# ...aPajo\MultiTenancyBundle\Adapter\Filesystem\FilesystemAdapter:
arguments:
- '@sonata.media.adapter.filesystem.local' # sonata.media.adapter.filesystem.ftp
aPajo\MultiTenancyBundle\Adapter\Mailer\MailerAdapter:
tags:
- { name: mailer.transport_factory }
aPajo\MultiTenancyBundle\Adapter\Database\DatabaseAdapter:
arguments:
$doctrine: '@doctrine'
# ...
```### Doctrine migrations configuration
Recommended path for the configuration files is `config/migrations/`.
#### default.yml
```yaml
migrations_paths:
'App\Migrations\Default': 'migrations/default'
```#### tenant.yml
```yaml
migrations_paths:
'App\Migrations\Tenant': 'migrations/tenant'
```## Adapters
Adapters are responsible for dynamic configuration changes based on tenant table values at runtime.
For more on (built-in) adapters see [Adapters directory](./src/Adapter/README.md)
## Resolvers
Resolvers are responsible for resolving current tenant.
For more on (built-in) resolvers see [Resolvers directory](./src/Service/Resolver/README.md)
## Database migrations
This bundle adds just 2 new commands to your project:
```shell
# Create new migrations/diffs (for default and tenant connections)php bin/console tenants:migrations:diff
``````shell
# Apply migrations to the tenants (or a single tenant) and the default connectionphp bin/console tenants:migrations:migrate [tenant_id]
```__NB!__ All other migration commands are as-is by [DoctrineMigrationsBundle](https://symfony.com/bundles/DoctrineMigrationsBundle/current/index.html)
## Examples
### Switch/select tenant
```php
use aPajo\MultiTenancyBundle\Service\EnvironmentProvider;
use aPajo\MultiTenancyBundle\Entity\TenantInterface;
use aPajo\MultiTenancyBundle\Event\TenantSelectEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterfaceclass Tenant implements TenantInterface {
// ...
}class MyTenantSelectService {
public function __construct (
private EnvironmentProvider $environmentProvider,
private EventDispatcherInterface $dispatcher,
) {
}
/**
* Use the EnvironmentProvider to select a different tenant
*/
public function select () {
$tenant = new Tenant();
$environmentProvider->select($tenant);
// Now the system is configured based on the tenant
}/**
* You can also dispatch an event to select a new tenant
*/
public function alternativeSelect () {
$tenant = new Tenant();
$event = new TenantSelectEvent($tenant);
$this->dispatcher->dispatch($event);
}
}
```### Iterate over all tenant environments
```php
use aPajo\MultiTenancyBundle\Service\EnvironmentProvider;
use aPajo\MultiTenancyBundle\Entity\TenantInterface;class MyTenantService {
public function __construct (
private EnvironmentProvider $environmentProvider,
) {
$environmentProvider->forAll(function (TenantInterface $tenant) {
// Each iteration will have tenant specific configuration/environment
});
}}
```
## Development### Testing
```shell
./vendor/bin/simple-phpunit
```## Issues
Feel free to report an issue [under GitHub Issues](https://github.com/apajo/symfony-multi-tenancy-bundle/issues)
### Known Issues
* Resetting to default/initial tenant does not work
* Symfony profiler currently shows only default entity managers migrations## Contributing
Feel free to [contribute](https://github.com/apajo/symfony-multi-tenancy-bundle/pulls)
### Versioning
Versions must be numbered following the [Semantic Versioning Specification](https://semver.org/).
### Packagist
Packagist [link](https://packagist.org/packages/apajo/symfony-multi-tenancy-bundle)
### Thanks to
This bundle is inspired by the [RamyHakam / multi_tenancy_bundle](https://github.com/RamyHakam/multi_tenancy_bundle)