Symfony 2:多个动态数据库连接

Fis*_*ish 53 symfony

我是SF2的新手,我想知道如何管理几个数据库到ONE捆绑的连接.目前我有这个解决方案 - 工作正常 - 但我不知道这是否是正确的方法....

在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: ~
Run Code Online (Sandbox Code Playgroud)

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

$O_ressource=  $this->get('doctrine')->getEntityManager('client');
$O_ressource=  $this->get('doctrine')->getEntityManager('default');
Run Code Online (Sandbox Code Playgroud)

那么伙计们,你认为这是管理这个的好方法吗?

我的第二个问题是:

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

谢谢您的帮助!

zul*_*lus 52

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

这是我的方法.我ConnectionFactory有空连接和EntityManager.工作时我只需用Reflections替换连接配置.适用于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)
  }
}
Run Code Online (Sandbox Code Playgroud)

更新:

为doctrine 2.2/sf 2.3(无需重选)提供更优雅的解决方案,为php5.4创建(我喜欢新的数组初始化程序:D)我们可以使用名为connection wrapper的doctrine功能,请参阅http://docs.doctrine-project.org/项目/学说,DBAL/EN /最新/参考/ portability.html

此示例使用会话服务临时存储连接详细信息.

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

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;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

接下来在你的学说配置中注册它:

…

connections:
  dynamic:
    driver:   %database_driver%
    host:     %database_host%
    port:     %database_port%
    dbname:   'empty_database'
    charset:  UTF8
    wrapper_class: 'w3des\DoctrineBundle\Connection\ConnectionWrapper'
Run Code Online (Sandbox Code Playgroud)

我们的ConnectionWrapper已正确注册.现在会话注入.

首先创建特殊的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')
    ]);
}
}
Run Code Online (Sandbox Code Playgroud)

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

public function build(ContainerBuilder $container)
{
    parent::build($container);
    $container->addCompilerPass(new ConnectionCompilerPass());
}
Run Code Online (Sandbox Code Playgroud)

这就是全部!

将根据会话属性按需创建连接.

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

$this->get('doctrine.dbal.dynamic_connection')->forceSwitch($dbname, $dbuser, $dbpass);
Run Code Online (Sandbox Code Playgroud)

好处

  1. 没有更多的反思
  2. 按需创作
  3. 优雅而有力

缺点

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


Pro*_*tic 23

您可以Symfony\Bundle\DoctrineBundle\ConnectionFactory使用容器服务doctrine.dbal.connection_factory查看:

$connectionFactory = $this->container->get('doctrine.dbal.connection_factory');
$connection = $connectionFactory->createConnection(array(
    'driver' => 'pdo_mysql',
    'user' => 'root',
    'password' => '',
    'host' => 'localhost',
    'dbname' => 'foo_database',
));
Run Code Online (Sandbox Code Playgroud)

这只是一个简单的例子,但它应该让你开始.

  • 我设法通过定义一个与假dbal.connection项相关联的实体 - 在我的config.yml文件中 - "动态"创建连接 - 然后我使用doctrine.dbal.connection_factory创建正确的连接,最后我将这个新连接设置为$ this-> container` $ this-> container-> set('doctrine.dbal.custom_client_connection',$ connection); $ myObject = $ this-> get('doctrine') - > getEntityManager('custom_client') - > getRepository('FooBarBundle:MyObject) - > find($ id);`我不知道它是否正确/最好的方式,但它的工作原理 (2认同)