динамическое подключение к базе данных zf2 (с параметрами)

#php #zend-framework #zend-framework2

#php #zend-framework #zend-framework2

Вопрос:

Я пытаюсь создать приложение 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(
                'ZendDbAdapterAdapterAbstractServiceFactory',
        )
    ),
);
  

В целях тестирования я создал форму, в которой есть метод для извлечения некоторых данных и помещения их в поле выбора. Код для получения подключения к базе данных показан в коде ниже.

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
  

Мой вопрос в том, как я могу динамически задать dbname для адаптера tentant_db в моем контроллере (или модуле)?

Спасибо за вашу помощь.

Комментарии:

1. zf2.readthedocs.org/en/develop/tutorials/…

2. @cptnk Я не думаю, что понимаю, что вы пытаетесь сказать. Я довольно новичок в zf2. Не могли бы вы, пожалуйста, дать мне еще несколько указаний?

Ответ №1:

Событие слияния конфигурации, я полагаю, является одним из более новых событий 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);
}
  

Комментарии:

1. Я думаю, что нашел решение, основанное на вашем ответе. Спасибо!

Ответ №2:

Основываясь на приведенном выше ответе, я создал следующее:

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

}
  

Я не знаю, лучшее ли это решение, но приведенный выше код работает. Я думаю, что следующими шагами должно быть помещение кода в универсальный модуль или что-то в этом роде, чтобы я мог получить к нему доступ из всех моих модулей.