Динамическое подключение к базе данных symfony2

Мой проект symfony2 имеет основную базу данных и множество дочерних баз данных. Каждая дочерняя база данных создается для каждого пользователя, учетные данные базы данных хранятся в основной базе данных. Когда пользователь входит в систему, пользовательские учетные данные для базы данных извлекаются из основной базы данных и идеальное соединение с дочерней базой. Я тоже искал Google, и я пришел к ряду решений и, наконец, сделал следующее:

#config.yml doctrine: dbal: default_connection: default connections: default: dbname: maindb user: root password: null host: localhost dynamic_conn: dbname: ~ user: ~ password: ~ host: localhost orm: default_entity_manager: default entity_managers: default: connection: default auto_mapping: true dynamic_em: connection: dynamic_conn auto_mapping: true 

Я создал соединение по умолчанию для подключения к основной базе данных и пустое соединение для дочерней базы данных, аналогично я создал менеджеров сущностей. Затем я создал прослушиватель событий по умолчанию и добавил следующий код в 'onKernelRequest':

 public function onKernelRequest(GetResponseEvent $event) //works like preDispatch in Zend { //code to get db credentials from master database and stored in varaiables .... $connection = $this->container->get(sprintf('doctrine.dbal.%s_connection', 'dynamic_conn')); $connection->close(); $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'] = $dbName; $params['user'] = $dbUser; $params['password'] = $dbPass; $refParams->setAccessible('private'); $refParams->setValue($connection, $params); $this->container->get('doctrine')->resetEntityManager('dynamic_em'); .... } 

Вышеприведенный код устанавливает параметры дочерней базы данных и сбрасывает диспетчер объектов dynamic_em.

Когда я делаю следующее в каком-то контроллере, он отлично работает и данные извлекаются из дочерней базы данных.

 $getblog= $em->getRepository('BloggerBlogBundle:Blog')->findById($id); //uses doctrine 

Но когда я использую контекст безопасности, как показано в следующем коде, я получаю сообщение об ошибке «NO DATABASE SELECTED».

 $securityContext = $this->container->get('security.context'); $loggedinUserid = $securityContext->getToken()->getUser()->getId(); 

Как установить динамическое соединение с базой данных и использовать контекст безопасности?

ОБНОВИТЬ:-

После большого количества времени, затраченного на пробную версию и ошибки, и поиска в Google, я понял, что security.context задан перед выполнением onKernelRequest . Теперь вопрос заключается в том, как вводить детали подключения к базе данных в файл security.context и куда вводить?

Нам нужно дойти до точки, в которой установлен DBAL и контекст безопасности, и маркер безопасности создается, и мы можем манипулировать деталями подключения к базе данных.

Следовательно, как сказал человек в следующей ссылке, я внес изменения в свой код, так как это именно то, что я хотел бы сделать. http://forum.symfony-project.org/viewtopic.php?t=37398&p=124413

Это оставляет мне следующий код для моего проекта:

 #config.yml //remains unchanged, similar to above code 

Пропуск компилятора создается следующим образом:

 // src/Blogger/BlogBundle/BloggerBlogBundle.php namespace Blogger\BlogBundle; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; use Blogger\BlogBundle\DependencyInjection\Compiler\CustomCompilerPass; class BloggerBlogBundle extends Bundle { public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass(new CustomCompilerPass()); } } 

Протокол компилятора выглядит следующим образом:

 # src/Blogger/BlogBundle/DependencyInjection/Compiler/CustomCompilerPass.php class CustomCompilerPassimplements CompilerPassInterface { public function process(ContainerBuilder $container) { $connection_service = 'doctrine.dbal.dynamic_conn_connection'; if ($container->hasDefinition($connection_service)) { $def = $container->getDefinition($connection_service); $args = $def->getArguments(); $args[0]['driverClass'] = 'Blogger\BlogBundle\UserDependentMySqlDriver'; $args[0]['driverOptions'][] = array(new Reference('security.context')); $def->replaceArgument(0, $args[0]); } } } 

Код класса драйвера выглядит следующим образом:

 # src/Blogger/BlogBundle/UserDependentMySqlDriver.php use Doctrine\DBAL\Driver\PDOMySql\Driver; class UserDependentMySqlDriver extends Driver { public function connect(array $params, $username = null, $password = null, array $driverOptions = array()) { $dbname = ..... //store database name in variable $params['dbname'] = $dbname; return parent::connect($params, $username, $password, array()); } } 

Вышеприведенный код был добавлен в мой проект, и я предполагаю, что это фактическая работа для моей проблемы.

Но теперь я получаю следующую ошибку:

ServiceCircularReferenceException: обнаружена циркулярная ссылка для службы «security.context», путь: «profiler_listener -> профайлер -> security.context -> security.authentication.manager -> fos_user.user_provider.username_email -> fos_user.user_manager -> doctrine.orm. dynamic_manager_entity_manager -> doctrine.dbal.dynamic_conn_connection ".

Как я могу заставить мой код работать? Бьюсь об заклад, что я делаю что-то неправильно здесь, и я был бы признателен за любые подсказки и помощь.

Related of "Динамическое подключение к базе данных symfony2"

Здесь вам нужно реализовать свою собственную логику самостоятельно, в своем собственном бизнесе.

Взгляните на документацию Doctrine на тему «Как создать диспетчер сущностей».

Затем создайте службу с понятным API:

 $this->get('em_factory')->getManager('name-of-my-client'); // returns an EntityManager 

Вы не можете сделать это с помощью DoctrineBundle по умолчанию, он не может использоваться для динамических функций.

 class EmFactory { public function getManager($name) { // you can get those values: // - autoguess, based on name // - injection through constructor // - other database connection // just create constructor and inject what you need $params = array('username' => $name, 'password' => $name, ....); // get an EM up and running // see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/getting-started.html#obtaining-the-entitymanager return $em; } } 

И объявите услугу.

Я хотел бы предложить другое решение вашей исходной проблемы. Вы можете использовать PhpFileLoader для динамического определения параметров для вашего config.yml.

  1. Извлеките основные параметры подключения базы данных в отдельный файл:

     # src/Blogger/BlogBundle/Resources/config/parameters.yml parameters: main_db_name: maindb main_db_user: root main_db_password: null main_db_host: localhost 
  2. Создайте новый PHP-скрипт (скажем, DynamicParametersLoader.php), который добавит новые параметры в контейнер приложения. Я думаю, вы не можете использовать свое приложение symfony в этом скрипте, но вы можете прочитать основные учетные данные db из переменной $ container. Например:

     # src/Blogger/BlogBundle/DependecyInjection/DynamicParametersLoader.php <?php $mainDbName = $container->getParameter('main_db_name'); $mainDbUser = $container->getParameter('main_db_user'); $mainDbPassword = $container->getParameter('main_db_password'); $mainDbHost = $container->getParameter('main_db_host'); # whatever code to query your main database for dynamic DB credentials. You cannot use your symfony2 app services here, so it ought to be plain PHP. ... # creating new parameters in container $container->setParameter('dynamic_db_name', $dbName); $container->setParameter('dynamic_db_user', $dbUser); $container->setParameter('dynamic_db_password', $dbPass); 
  3. Теперь вам нужно сказать Symfony о вашем скрипте и новом файле parameters.yml:

     # config.yml imports: - { resource: parameters.yml } - { resource: ../../DependencyInjection/DynamicParametersLoader.php } 
  4. На этом этапе вы можете свободно использовать введенные параметры в вашем config:

     # config.yml ... dynamic_conn: dbname: %dynamic_db_name% user: %dynamic_db_user% password: %dynamic_db_password% ... 

Существует очень хорошее решение, использующее прослушиватель событий, размещенный здесь:

Symfony2, Dynamic DB Connection / Раннее переопределение службы Doctrine Service