Symfony Doctrine连接包装器

3
我在Symfony2中实现了一个连接包装器,可以根据子域名连接到数据库。我遵循了这个问题的说明:Symfony 2:多个和动态数据库连接
它能正常工作,但是当我尝试更新模式时,Symfony会选择配置文件中我设置的数据库名称(dinamic_database),而不是我在Session中设置的数据库名称(database1)。
问题在于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: ~

连接包装器

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;
    }
}
}

数据库管理器

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();
    }
}

}
1个回答

2

我终于解决了问题,但不知道这是否是最好的方法。

我在ConnectionWrapper的connect方法中重写了构造函数方法:

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;
}

你好,如何在连接包装类中使用Session? - barbuslex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接