gpt4 book ai didi

交响乐2 : multiple and dynamic database connection

转载 作者:行者123 更新时间:2023-12-03 05:56:53 24 4
gpt4 key购买 nike

我对 SF2 很陌生,我想知道如何将多个数据库的连接管理到一个 bundle 中。目前我有这个解决方案 - 效果很好 - 但我不知道这是否是正确的方法......

在 myBundle\Ressource\config\config.yml 中:

doctrine:
dbal:
default_connection: default
connections:
default:
dbname: SERVER
user: root
password: null
host: localhost
client:
dbname: CLIENT_134
user: root
password: null
host: localhost
orm:
default_entity_manager: default
entity_managers:
default:
connection: default
mappings:
MyBundle: ~
client:
connection: client
mappings:
MyBundle: ~

然后,为了切换到其中一个 BD 或另一个,我这样做:

$O_ressource=  $this->get('doctrine')->getEntityManager('client');
$O_ressource= $this->get('doctrine')->getEntityManager('default');

那么各位,你们认为这是管理这个问题的好方法吗?

我的第二个问题是:

如何建立动态数据库连接?我的意思是我的系统中有 100 个数据库,但我无法在 config.yml 文件中设置所有数据库。所以我希望能够动态更改数据库。

感谢您的帮助!

最佳答案

如果您使用ConnectionFactory,附加到连接的事件订阅者将停止工作,例如 stofDoctrineExtensions。

这是我的方法。我的 ConnectionFactory 有空连接和 EntityManager。在工作时,我只是用反射替换连接配置。适用于 SF 2.0.10 ;)

class YourService extends ContainerAware
{

public function switchDatabase($dbName, $dbUser, $dbPass)
{
$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_manager'); // for sure (unless you like broken transactions)
}
}

更新:

针对 2.2/sf 2.3(无反射)的更优雅的解决方案,为 php5.4 创建(我喜欢新的数组初始值设定项:D)我们可以使用称为连接包装器的学说功能,请参阅http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/portability.html

此示例使用 session 服务临时存储连接详细信息。

首先我们必须创建特殊的连接包装器:

namespace w3des\DoctrineBundle\Connection;

use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\Session\Session;
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Events;
use Doctrine\DBAL\Event\ConnectionEventArgs;

/*
* @author Dawid zulus Pakula [zulus@w3des.net]
*/
class ConnectionWrapper extends Connection
{

const SESSION_ACTIVE_DYNAMIC_CONN = 'active_dynamic_conn';

/**
* @var Session
*/
private $session;

/**
* @var bool
*/
private $_isConnected = false;

/**
* @param Session $sess
*/
public function setSession(Session $sess)
{
$this->session = $sess;
}

public function forceSwitch($dbName, $dbUser, $dbPassword)
{
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,
$dbUser,
$dbPass
]);

if ($this->isConnected()) {
$this->close();
}
}

/**
* {@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['user'] = $realParams[1];
$params['password'] = $realParams[2];

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

/**
* {@inheritDoc}
*/
public function isConnected()
{
return $this->_isConnected;
}

/**
* {@inheritDoc}
*/
public function close()
{
if ($this->isConnected()) {
parent::close();
$this->_isConnected = false;
}
}
}

接下来将其注册到您的学说配置中:



connections:
dynamic:
driver: %database_driver%
host: %database_host%
port: %database_port%
dbname: 'empty_database'
charset: UTF8
wrapper_class: 'w3des\DoctrineBundle\Connection\ConnectionWrapper'

我们的 ConnectionWrapper 已正确注册。现在 session 注入(inject)。

首先创建特殊的 CompilerPass 类:

namespace w3des\DoctrineBundle\DependencyInjection\CompilerPass;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

class ConnectionCompilerPass implements CompilerPassInterface
{

/**
* {@inheritDoc}
*/
public function process(ContainerBuilder $container)
{
$connection = $container
->getDefinition('doctrine.dbal.dynamic_connection')
->addMethodCall('setSession', [
new Reference('session')
]);
}
}

我们在 *Bundle 类中记录新的编译器类:

public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new ConnectionCompilerPass());
}

这就是全部!

将根据 session 属性按需创建连接。

要切换数据库,只需使用:

$this->get('doctrine.dbal.dynamic_connection')->forceSwitch($dbname, $dbuser, $dbpass);

优点

  1. 不再反射(reflection)
  2. 按需创作
  3. 优雅而有力

缺点

  1. 您必须手动清理实体管理器,或为此创建特殊的条令事件
  2. 更多代码

关于交响乐2 : multiple and dynamic database connection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6409167/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com