скажем, у меня есть 3 базы данных:
- prefix_db1
- prefix_db2
- prefix_db3
И я хочу подключиться к ним динамически с URL-адреса, как это http://localhost/my-project/web/app_dev.php/db1/books
, поэтому я знаю, к какой базе данных подключаться с URL-адреса (в данном случае prefix_db1
)
И в основном идея заключалась в том, чтобы подготовить слушателя, который будет запускаться при каждом http запросе , получить имя базы данных из URL-адреса, а затем переопределить параметры доктрины, что-то вроде этого:
В services.yml :
dynamic_connection:
class: AppBundle\service\DynamicDBConnector
arguments: ['@request_stack']
calls:
- [ setDoctrineConnection, ['@doctrine.dbal.default_connection'] ]
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Мой слушатель:
<?php
namespace AppBundle\service;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\RequestStack;
use Exception;
class DynamicDBConnector
{
/**
* @var Connection
*/
private $connection;
/*
* @var Request
*/
private $request;
public function __construct(RequestStack $requestStack)
{
$this->request = $requestStack->getCurrentRequest();
}
/**
* Sets the DB Name prefix to use when selecting the database to connect to
*
* @param Connection $connection
* @return DynamicDBConnector $this
*/
public function setDoctrineConnection(Connection $connection)
{
$this->connection = $connection;
return $this;
}
public function onKernelRequest()
{
if ($this->request->attributes->has('_company')) {
$connection = $this->connection;
$params = $this->connection->getParams();
$companyName = $this->request->get('_company');
// I did the concatenation here because in paramaters.yml I just put the prefix (database_name: prefix_) so after the concatenation I get the whole database name "prefix_db1"
$params['dbname'] = $params['dbname'] . $companyName;
// Set up the parameters for the parent
$connection->__construct(
$params,
$connection->getDriver(),
$connection->getConfiguration(),
$connection->getEventManager()
);
try {
$connection->connect();
} catch (Exception $e) {
// log and handle exception
}
}
return $this;
}
}
Теперь это сработало очень хорошо, я проверил его, используя простой список книг, и каждый раз, когда я меняю URL, я получаю список, связанный с каждой базой данных:
http://localhost/my-project/web/app_dev.php/db1/books // I get books of database prefix_db1
http://localhost/my-project/web/app_dev.php/db2/books // I get books of database prefix_db2
Теперь давайте перейдем к проблеме:) :
Проблема сейчас в том, что когда я защищаю свой проект с помощью системы аутентификации и пытаюсь войти (конечно, каждая база данных имеет user
таблицу), используя этот URL http://localhost/my-project/web/app_dev.php/db1/login
Я получаю это исключение:
An exception occured in driver: SQLSTATE[HY000] [1049] Base 'prefix_' unknown
Как вы можете видеть, symfony пытался войти в систему пользователя, используя database_name
, объявленный в parameters.yml , что означает, что security_checker
symfony был запущен перед моим слушателем и перед переопределением Doctrine's params
.
Мой вопрос :
Есть ли способ запустить мой слушатель перед любым другим слушателем http-запроса? или, может быть, альтернативное решение, чтобы убедиться, что любой запрос к базе данных должен быть с правильным именем базы данных.
Извините за длинный пост.
EDIT:
Из официальной документации Symfony:
https://symfony.com/doc/2.3/cookbook/event_dispatcher/event_listener.html
Другой необязательный атрибут тега называется приоритетом, который по умолчанию
до 0 и контролирует порядок выполнения слушателей (
чем выше приоритет, тем раньше выполняется слушатель ). Это
полезно, когда вам нужно гарантировать, что один слушатель будет выполнен раньше
другой. Приоритеты внутренних слушателей Symfony обычно
в диапазоне от -255 до 255, но ваши собственные слушатели могут использовать любой положительный или
отрицательное целое число.
Я установил приоритет моего слушателя на 10000 :
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest, priority: 10000 }
Но проблема сохраняется, я все еще не могу уволить моего слушателя до Symfony!