zf2动态数据库连接(带参数)


zf2 dynamic database connection (with parameters)



我正在尝试创建一个具有多个数据库的ZF2应用程序。应该根据用户动态设置数据库。

现在我有以下内容:

database.local.php

return array(
    'db' => array(
        'adapters' => array (
            'master_db' => array(
                'driver'         => 'Pdo',
                'dsn'            => 'mysql:dbname=master_db;host=localhost',
                'driver_options' => array(
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ''UTF8'''
                ),
                'username'       => 'USERNAME',
                'password'       => 'PASSWORD'
            ),
            'tentant_db' => array(
                'driver'         => 'Pdo',
                'dsn'            => 'mysql:dbname=tenant_db;host=localhost',
                'driver_options' => array(
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ''UTF8'''
                ),
                'username'       => 'USERNAME',
                'password'       => 'PASSWORD'
            ),
        )
    ),
    'service_manager' => array(
        'abstract_factories' => array(
                'Zend'Db'Adapter'AdapterAbstractServiceFactory',
        )
    ),
);

出于测试目的,我创建了一个表单,该表单具有获取一些数据并将其放入选择框的方法。下面的代码中显示了获取数据库连接的代码。

MyController.php(在某些模块中(

//... some code
public function someAction(){
        $dbAdapter = $this->getServiceLocator()->get('tentant_db');
        $form = new AddEolConnectorForm($dbAdapter);
        $viewModel = new ViewModel(array(
                                'form' => $form
                            ));
        return $viewModel;

    }
//... some more code

我的问题是,如何在控制器(或模块(中动态设置tentant_db适配器的dbname

谢谢你的帮助。

我相信配置合并事件是zend更新事件之一。它在zend合并配置数组时触发,这非常适合您面临的问题,因为您可以动态覆盖一些数组键。

public function onMergeConfig(ModuleEvent $e)
{
    $configListener = $e->getConfigListener();
    $config         = $configListener->getMergedConfig(false);
    // I'm actually not sure if you have the route match here otherwise you may have to
    // use some other method to retrieve the url.
    $match = $e->getRouteMatch();
    switch ($match) {
    case 'first-dependency':
       $config['db']['adapter'] => array(
          'driver'         => 'Pdo',
          'dsn'            => 'mysql:dbname=master_db;host=localhost',
          'driver_options' => array(
             PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ''UTF8'''
          ),
          'username'       => 'USERNAME',
          'password'       => 'PASSWORD',
        ),
    break;
    case 'second-dependency':
       $config['db']['adapter'] => array(
          'driver'         => 'Pdo',
          'dsn'            => 'mysql:dbname=tenant_db;host=localhost',
          'driver_options' => array(
             PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES ''UTF8'''
          ),
          'username'       => 'USERNAME',
          'password'       => 'PASSWORD',
        ),
    break;
    // Pass the changed configuration back to the listener:
    $configListener->setMergedConfig($config);
}

基于以上答案,我创建了以下内容:

Module.php

class Module implements AutoloaderProviderInterface
{
  public function init(ModuleManager $moduleManager)
    {
        $events = $moduleManager->getEventManager();
        // Registering a listener at default priority, 1, which will trigger
        // after the ConfigListener merges config.
        $events->attach(ModuleEvent::EVENT_MERGE_CONFIG, array($this, 'onMergeConfig'));
    }
    public function onMergeConfig(ModuleEvent $e)
    {
        $db = $this->getTentantDb();
        $configListener = $e->getConfigListener();
        $config         = $configListener->getMergedConfig(false);
        $config['db']['adapters']['tenant_db']['dsn'] = 'mysql:dbname='. $db .';host=localhost';
        $configListener->setMergedConfig($config);
    }
    // Some more code
    public function getTenantDb(){
        $tenant_db = 'tenant_12345'
        return $tenant_db;
    }
}

我不知道这是否是最好的解决方案,但上面的代码是有效的。我认为接下来的步骤应该是将代码放在一个通用模块或其他模块中,这样我就可以从我的所有模块中访问它。