Symfony Doctrine 连接包装器
Symfony Doctrine connection wrapper
我在 symfony2 中实现了一个连接包装器,用于根据子域连接到数据库。我按照 Symfony 2 : multiple and dynamic database connection
问题的说明进行操作
它工作正常但是当我尝试更新模式时,symfony 正在选择我在配置文件中的数据库名称 (dinamic_database) 而不是我在其中的数据库名称 (database1)会话。
问题是 class Doctrine\DBALConnection 中的私有 属性 $params 的值是在构造函数中创建的,我需要更改我的覆盖连接方法,但我不能更改此属性,因为没有任何方法 setParams()
config.yml
doctrine:
dbal:
default_connection: default
connections:
default:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
cliente:
wrapper_class: 'Em\Bundle\AppBundle\Connection\ConnectionWrapper'
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: 'dinamic_database'
user: "%database_user%"
password: "%database_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: %kernel.debug%
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
EmAdminBundle: ~
EmBackOfficeBundle: ~
EmContabilidadBundle: ~
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
dql:
string_functions:
MONTH: DoctrineExtensions\Query\Mysql\Month
YEAR: DoctrineExtensions\Query\Mysql\Year
cliente:
connection: cliente
mappings:
EmAppBundle: ~
Connection wrapper
class ConnectionWrapper extends Connection
{
const SESSION_ACTIVE_DYNAMIC_CONN = 'active_dynamic_conn';
/**
* @var Session
*/
private $session;
/**
* @var bool
*/
private $_isConnected = false;
/**
* @var
*/
private $defaultDatabaseName;
/**
* @param Session $sess
*/
public function setSession(Session $sess)
{
$this->session = $sess;
}
/**
* @param Session $sess
*/
public function setDefaultDatabaseName($defaultDatabaseName)
{
$this->defaultDatabaseName = $defaultDatabaseName;
}
public function forceSwitch($dbName)
{
if ($this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) {
$current = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN);
if ($current[0] === $dbName) {
return;
}
}
$this->session->set(self::SESSION_ACTIVE_DYNAMIC_CONN, [
$dbName
]);
if ($this->isConnected()) {
$this->close();
}
}
public function forceDefault()
{
$this->forceSwitch($this->defaultDatabaseName);
}
/**
* {@inheritDoc}
*/
public function connect()
{
if (!$this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) {
throw new \InvalidArgumentException('You have to inject into valid context first');
}
if ($this->isConnected()) {
return true;
}
$driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array();
$params = $this->getParams();
$realParams = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN);
$params['dbname'] = $realParams[0];
// $params['dbname'] is "database1"
$this->_conn = $this->_driver->connect($params, $params['user'], $params['password'], $driverOptions);
$paramsAfterConection = $this->getParams();
// $paramsAfterConection['dbname'] is "dinamic_database"
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
$this->_isConnected = true;
return true;
}
/**
* {@inheritDoc}
*/
public function isConnected()
{
return $this->_isConnected;
}
/**
* {@inheritDoc}
*/
public function close()
{
if ($this->isConnected()) {
parent::close();
$this->_isConnected = false;
}
}
}
Database manager
class DatabaseManager
{
/**
* @var EntityManager
*/
private $emCliente;
/**
* @var ConnectionWrapper
*/
private $connection;
public function __construct(EntityManager $emCliente, ConnectionWrapper $connection)
{
$this->emCliente = $emCliente;
$this->connection = $connection;
}
public function createDatabaseApp(AppEvent $event) {
$app = $event->getApp();
$database = $app->getDatabaseName();
$this->connection->getSchemaManager()->createDatabase($database);
$this->connection->forceSwitch($database);
$metadatas = $this->emCliente->getMetadataFactory()->getAllMetadata();
$tool = new SchemaTool($this->emCliente);
$tool->createSchema($metadatas);
$this->connection->forceDefault();
}
public function deleteDatabaseApp(AppEvent $event)
{
$app = $event->getApp();
$database = $app->getDatabaseName();
if(in_array($database, $this->connection->getSchemaManager()->listDatabases())){
$this->connection->getSchemaManager()->dropDatabase($database);
}
}
public function updateSchema(App $app)
{
$database = $app->getDatabaseName();
if(in_array($database, $this->connection->getSchemaManager()->listDatabases())){
$this->connection->forceSwitch($database);
$metadatas = $this->emCliente->getMetadataFactory()->getAllMetadata();
$tool = new SchemaTool($this->emCliente);
$sm = $this->connection->getSchemaManager();
$fromSchema = $sm->createSchema();
//fromSchema is trying to get information from dinamic_database instead of database1
$toSchema = $tool->getSchemaFromMetadata($metadatas);
$comparator = new Comparator();
$schemaDiff = $comparator->compare($fromSchema, $toSchema);
$sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform());
}
}
public function dropSchema(App $app)
{
$database = $app->getDatabaseName();
if(in_array($database, $this->connection->getSchemaManager()->listDatabases())){
$this->connection->forceSwitch($database);
$this->connection->executeQuery('SET FOREIGN_KEY_CHECKS = 0');
$metadatas = $this->emCliente->getMetadataFactory()->getAllMetadata();
$tool = new SchemaTool($this->emCliente);
$tool->dropSchema($metadatas);
$this->connection->executeQuery('SET FOREIGN_KEY_CHECKS = 1');
$this->connection->forceDefault();
}
}
}
我终于解决了这个问题,但不知道这是不是最好的方法
我重写了ConnectionWrapper中connect方法中的constructor方法:
public function connect()
{
if (!$this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) {
throw new \InvalidArgumentException('You have to inject into valid context first');
}
if ($this->isConnected()) {
return true;
}
$driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array();
$params = $this->getParams();
$realParams = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN);
$params['dbname'] = $realParams[0];
//overrride constructor in parent class Connection to set new parameter dbname
parent::__construct($params, $this->_driver, $this->_config,$this->_eventManager);
$this->_conn = $this->_driver->connect($params, $params['user'], $params['password'], $driverOptions);
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
$this->_isConnected = true;
return true;
}
我在 symfony2 中实现了一个连接包装器,用于根据子域连接到数据库。我按照 Symfony 2 : multiple and dynamic database connection
问题的说明进行操作它工作正常但是当我尝试更新模式时,symfony 正在选择我在配置文件中的数据库名称 (dinamic_database) 而不是我在其中的数据库名称 (database1)会话。
问题是 class Doctrine\DBALConnection 中的私有 属性 $params 的值是在构造函数中创建的,我需要更改我的覆盖连接方法,但我不能更改此属性,因为没有任何方法 setParams()
config.yml
doctrine:
dbal:
default_connection: default
connections:
default:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
cliente:
wrapper_class: 'Em\Bundle\AppBundle\Connection\ConnectionWrapper'
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: 'dinamic_database'
user: "%database_user%"
password: "%database_password%"
charset: UTF8
orm:
auto_generate_proxy_classes: %kernel.debug%
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
EmAdminBundle: ~
EmBackOfficeBundle: ~
EmContabilidadBundle: ~
filters:
softdeleteable:
class: Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter
enabled: true
dql:
string_functions:
MONTH: DoctrineExtensions\Query\Mysql\Month
YEAR: DoctrineExtensions\Query\Mysql\Year
cliente:
connection: cliente
mappings:
EmAppBundle: ~
Connection wrapper
class ConnectionWrapper extends Connection
{
const SESSION_ACTIVE_DYNAMIC_CONN = 'active_dynamic_conn';
/**
* @var Session
*/
private $session;
/**
* @var bool
*/
private $_isConnected = false;
/**
* @var
*/
private $defaultDatabaseName;
/**
* @param Session $sess
*/
public function setSession(Session $sess)
{
$this->session = $sess;
}
/**
* @param Session $sess
*/
public function setDefaultDatabaseName($defaultDatabaseName)
{
$this->defaultDatabaseName = $defaultDatabaseName;
}
public function forceSwitch($dbName)
{
if ($this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) {
$current = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN);
if ($current[0] === $dbName) {
return;
}
}
$this->session->set(self::SESSION_ACTIVE_DYNAMIC_CONN, [
$dbName
]);
if ($this->isConnected()) {
$this->close();
}
}
public function forceDefault()
{
$this->forceSwitch($this->defaultDatabaseName);
}
/**
* {@inheritDoc}
*/
public function connect()
{
if (!$this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) {
throw new \InvalidArgumentException('You have to inject into valid context first');
}
if ($this->isConnected()) {
return true;
}
$driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array();
$params = $this->getParams();
$realParams = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN);
$params['dbname'] = $realParams[0];
// $params['dbname'] is "database1"
$this->_conn = $this->_driver->connect($params, $params['user'], $params['password'], $driverOptions);
$paramsAfterConection = $this->getParams();
// $paramsAfterConection['dbname'] is "dinamic_database"
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
$this->_isConnected = true;
return true;
}
/**
* {@inheritDoc}
*/
public function isConnected()
{
return $this->_isConnected;
}
/**
* {@inheritDoc}
*/
public function close()
{
if ($this->isConnected()) {
parent::close();
$this->_isConnected = false;
}
}
}
Database manager
class DatabaseManager
{
/**
* @var EntityManager
*/
private $emCliente;
/**
* @var ConnectionWrapper
*/
private $connection;
public function __construct(EntityManager $emCliente, ConnectionWrapper $connection)
{
$this->emCliente = $emCliente;
$this->connection = $connection;
}
public function createDatabaseApp(AppEvent $event) {
$app = $event->getApp();
$database = $app->getDatabaseName();
$this->connection->getSchemaManager()->createDatabase($database);
$this->connection->forceSwitch($database);
$metadatas = $this->emCliente->getMetadataFactory()->getAllMetadata();
$tool = new SchemaTool($this->emCliente);
$tool->createSchema($metadatas);
$this->connection->forceDefault();
}
public function deleteDatabaseApp(AppEvent $event)
{
$app = $event->getApp();
$database = $app->getDatabaseName();
if(in_array($database, $this->connection->getSchemaManager()->listDatabases())){
$this->connection->getSchemaManager()->dropDatabase($database);
}
}
public function updateSchema(App $app)
{
$database = $app->getDatabaseName();
if(in_array($database, $this->connection->getSchemaManager()->listDatabases())){
$this->connection->forceSwitch($database);
$metadatas = $this->emCliente->getMetadataFactory()->getAllMetadata();
$tool = new SchemaTool($this->emCliente);
$sm = $this->connection->getSchemaManager();
$fromSchema = $sm->createSchema();
//fromSchema is trying to get information from dinamic_database instead of database1
$toSchema = $tool->getSchemaFromMetadata($metadatas);
$comparator = new Comparator();
$schemaDiff = $comparator->compare($fromSchema, $toSchema);
$sqls = $schemaDiff->toSql($this->connection->getDatabasePlatform());
}
}
public function dropSchema(App $app)
{
$database = $app->getDatabaseName();
if(in_array($database, $this->connection->getSchemaManager()->listDatabases())){
$this->connection->forceSwitch($database);
$this->connection->executeQuery('SET FOREIGN_KEY_CHECKS = 0');
$metadatas = $this->emCliente->getMetadataFactory()->getAllMetadata();
$tool = new SchemaTool($this->emCliente);
$tool->dropSchema($metadatas);
$this->connection->executeQuery('SET FOREIGN_KEY_CHECKS = 1');
$this->connection->forceDefault();
}
}
}
我终于解决了这个问题,但不知道这是不是最好的方法
我重写了ConnectionWrapper中connect方法中的constructor方法:
public function connect()
{
if (!$this->session->has(self::SESSION_ACTIVE_DYNAMIC_CONN)) {
throw new \InvalidArgumentException('You have to inject into valid context first');
}
if ($this->isConnected()) {
return true;
}
$driverOptions = isset($params['driverOptions']) ? $params['driverOptions'] : array();
$params = $this->getParams();
$realParams = $this->session->get(self::SESSION_ACTIVE_DYNAMIC_CONN);
$params['dbname'] = $realParams[0];
//overrride constructor in parent class Connection to set new parameter dbname
parent::__construct($params, $this->_driver, $this->_config,$this->_eventManager);
$this->_conn = $this->_driver->connect($params, $params['user'], $params['password'], $driverOptions);
if ($this->_eventManager->hasListeners(Events::postConnect)) {
$eventArgs = new ConnectionEventArgs($this);
$this->_eventManager->dispatchEvent(Events::postConnect, $eventArgs);
}
$this->_isConnected = true;
return true;
}