问题是你不能在运行时改变连接参数,
我之前在 Symfony 3.4 中也有过相同的情况,我通过扩展 connection 来支持在运行时更改参数来解决此问题。
我终于为此创建了一个 Symfony 捆绑包?
https://github.com/RamyHakam/doctrine-db-switcher-bundle
但它只适用于 Symfony 4+ ?
但是,我可以与您分享它的想法,它应该适用于 Symfony 3.4 ?
你应该像这个例子一样配置你的连接
connections:
default:
driver: ''
charset:
host: ''
port: ''
dbname: ''
user: ''
password: ''
wrapper_class: App\Doctrine\DBAL\TenantConnection
在哪里wrapper_class is your new conneciton
类示例:
namespace App\Doctrine\DBAL;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Event;
class TenantConnection extends Connection
{
/** @var mixed */
protected $params = [];
/** @var bool */
protected $isConnected = false;
/** @var bool */
protected $autoCommit = true;
/**
* TenantConnection constructor.
*
* @param $params
* @param Driver $driver
* @param Configuration|null $config
* @param EventManager|null $eventManager
* @throws \Doctrine\DBAL\DBALException
*/
public function __construct($params, Driver $driver, ?Configuration $config = null, ?EventManager $eventManager = null)
{
$this->params = $params;
parent::__construct($params, $driver, $config, $eventManager);
}
/**
* @return bool
*/
public function connect()
{
if ($this->isConnected) {
return false;
}
$driverOptions = $this->params['driverOptions'] ?? [];
$user = $this->params['user'] ?? null;
$password = $this->params['password'] ?? null;
$this->_conn = $this->_driver->connect($this->params, $user, $password, $driverOptions);
$this->isConnected = true;
if ($this->autoCommit === false) {
$this->beginTransaction();
}
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new Event\ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
return true;
}
/**
* @param string $dbName
* @param string $dbUser
* @param string $dbPassword
*/
public function changeParams(string $dbName, string $dbUser, string $dbPassword)
{
$this->params['dbname'] = $dbName;
$this->params['user'] = $dbUser;
$this->params['password'] = $dbPassword;
}
public function reconnect()
{
if ($this->isConnected) {
$this->close();
}
$this->connect();
}
/**
* @return mixed|mixed[]
*/
public function getParams()
{
return $this->params;
}
public function close()
{
$this->_conn = null;
$this->isConnected = false;
}
然后在您的事件监听器中,您可以将连接切换到另一个数据库
例子:
namespace App\EventListener;
use App\Doctrine\DBAL\TenantConnection;
use App\Main\Domain\Model\Tenant;
use App\Main\Infrastructure\Persistence\Doctrine\Repository\TenantRepository;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
class RequestListener implements EventSubscriberInterface
{
/**
* @var ContainerInterface
*/
private $container;
/**
* @var SessionInterface
*/
private $session;
/**
* @var TenantRepository
*/
private $tenantRepository;
public function __construct(ContainerInterface $container,TenantRepository $tenantRepository)
{
$this->container = $container;
$this->tenantRepository = $tenantRepository;
}
public static function getSubscribedEvents()
{
return [
RequestEvent::class => 'onKernelRequest'
];
}
public function onKernelRequest( RequestEvent $event)
{
$userAgent = $event->getRequest()->headers->get('user_identifier');
/**
* @var TenantConnection $tenantConnection
*/
$tenantConnection = $this->container->get('doctrine')->getConnection('tenant');
/**@var Tenant $tenant */
$tenants = $this->tenantRepository->findAll();
$tenant = $tenants[1];
$tenantConnection->changeParams($tenant->getDbName(), $tenant->getDbUserName(), $tenant->getDbPassword());
$tenantConnection->reconnect();
}
}
[1]: https://github.com/RamyHakam/doctrine-db-switcher-bundle