I am working in a Symfony 2.8 project with dynamic database connection. As I am developing a SaaS (Software as a Service) application and have to handle with different subdomains, databases are set dynamically based on the subdomain registered. Then, as the user accesses the application for the first time, database is created and its schema updated.
My config file looks like:
doctrine:
dbal:
default_connection: default
connections:
default:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
dynamic_conn:
driver: pdo_mysql
host: ~
port: ~
dbname: ~
user: ~
password: ~
charset: UTF8
orm:
auto_generate_proxy_classes: "%kernel.debug%"
default_entity_manager: default
entity_managers:
default:
connection: default
auto_mapping: false
dynamic_em:
connection: dynamic_conn
auto_mapping: true
There's a listener which is responsible to establish connection for this "new" database and the 'dynamic_conn' parameters are set dynamically. Something like this:
public function onKernelRequest(GetResponseEvent $event)
{
$connection = $this->container->get(sprintf('doctrine.dbal.%s_connection', 'dynamic_conn'));
$connection->close();
// Get params defined in config.yml for dynamic connection, a.k.a 'dynamic_conn'
$refConn = new \ReflectionObject($connection);
$refParams = $refConn->getProperty('_params');
$refParams->setAccessible('public'); //we have to change it for a moment
$params = $refParams->getValue($connection);
$params['dbname'] = $store['db_name'];
$params['user'] = $store['db_user'];
$params['password'] = $store['db_password'];
$refParams->setAccessible('private');
// Set params dynamically in 'config.yml' to access its entity manager
$refParams->setValue($connection, $params);
$this->container->get('doctrine')->resetManager('dynamic_em');
// Grab right entity manager to setup schema
$em = $this->container->get('doctrine')->getManager('dynamic_em');
$metadatas = $em->getMetadataFactory()->getAllMetadata();
$schemaTool = new SchemaTool($em);
$schemaTool->dropDatabase($store['db_name']);
if (!empty($metadatas)) {
$schemaTool->createSchema($metadatas);
}
}
Then, when I want to execute some query using dynamic connection with the entity manager I call the manager and execute it, like this:
$em = $this->container->get('doctrine')->getManager('dynamic_em');
$products = $em
->createQueryBuilder()
->select('partial p.{id}')
->from('AdminBundle\Entity\Product', 'p')
->getQuery()
->getResult()
;
All this works fine! My main problem is for authentication. I tried to use the FOSUserBundle (already used in other project) however I had some troubles and decided to use "Load Security Users from the Database". My entity "User" is created accordingly the documentation and my 'security.yml' looks like this:
providers:
in_memory:
memory: ~
# Admin
admin:
entity:
class: AdminBundle\Entity\User
property: login
manager_name: dynamic_em
firewalls:
...
admin_private:
provider: admin
pattern: ^/admin
form_login:
login_path: admin_login
check_path: admin_login_check
default_target_path: admin_home
use_referer: true
logout:
path: admin_logout
target: admin_login
As there's the 'admin' provider, authentication process has to check in entity 'User' located in class 'AdminBundle\Entity\User' to perform login. However, application can't find the entity User. It gives the following error:
The class 'AdminBundle\Entity\User' was not found in the chain configured namespaces
I guess the main problem is because the configuration for security issues is set before the dynamic connection is set. Which will lead to security context trying to find something that it doesn't exist yet - my entity mapped dynamically! I've found some tracks here but none of them could help me figure it out a solution. Anyone with the same issue and/or a related solution? Any help is appreciated.
Thanks in advance.