rogaa
rogaa

Reputation: 380

ZF3 multiple database adapters

in ZF2 it was possible to configurate multiple adapters like this in the module.config.php:

'db' => array(
    'adapters'=>array(
        'db1' => array(
            'driver' => 'Pdo',
            'dsn' => 'mysql:dbname=zf2;host=localhost',
            'driver_options' => array(
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
            ),
            'username' => 'zf2',
            'password' => 'zf2test',
        ),
        'db2' => array(
            'driver' => 'Pdo',
            'dsn' => 'mysql:dbname=zf1;host=localhost',
            'driver_options' => array(
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
            ),
            'username' => 'zf1',
            'password' => 'zf1test',
        ),
    )

),

In the controller factory I could get them via the ServiceManager:

class AlbumControllerFactory implements FactoryInterface
{

public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $albumTable = $serviceLocator->getServiceLocator()->get('Album\Model\AlbumTable');
        $db1Adapter = $serviceLocator->getServiceLocator()->get('db1');
        $db2Adapter = $serviceLocator->getServiceLocator()->get('db2');

        return new AlbumController($albumTable, $db1Adapter, $db2Adapter);
    }
}

Now I'm trying to do the same in Zend Framework 3 - but this nested array configuration doesn't work:

Fatal error: Uncaught exception 'Zend\Db\Adapter\Exception\InvalidArgumentException' with message 'createDriver expects a "driver" key to be present inside the parameters' in /var/www/USER/teckert/zf3/vendor/zendframework/zend-db/src/Adapter/Adapter.php:262

I think that in ZF 2 the adapters key are already handled when the dbAdapter is trying to create the driver - but this is not happening in ZF 3.

Any hints are warmly welcomed...

The manual of the zend-db with the adapters section wasn't clear enough for me

EDIT

According to this doc I've added the following snippet to the global config file:

'service_manager' => [
    'abstract_factories' => [
        \Zend\Db\Adapter\AdapterAbstractServiceFactory::class,
    ],
],

While trying to get the dbAdapter with $container->get('db1') in my AlbumTableFactory I get this error:

Unable to resolve service "db1 to a factory; are you certain you provided it during configuration?

Upvotes: 2

Views: 5386

Answers (2)

rogaa
rogaa

Reputation: 380

Okay I finally resolved the problem.

As mentioned by @Pieter I needed the following array content in my config.php:

'service_manager' => [
    'abstract_factories' => [
        \Zend\Db\Adapter\AdapterAbstractServiceFactory::class,
    ],
],

Additionally I had to change the process my classes and dependent factories are talking to each other.

  1. AlbumControllerFactory is called and get's the dependent AlbumTable service ($container->get(AlbumTable::class);) which then triggers the AlbumTableFactory
  2. AlbumTableFactory then is preparing the constructor injection for the AlbumTable with $tableGateway = $container->get(AlbumTableGateway::class);
  3. Now I combined the logic from the AlbumTableFactory and the AlbumTableGatewayFactory into one AbstractFactoryInterface (I removed the AlbumTableGatewayFactory completely)
// AlbumTableFactory implements AbstractFactoryInterface

public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
    $dbAdapter = $container->get('db1');
    $resultSetPrototype = new ResultSet();
    $resultSetPrototype->setArrayObjectPrototype(new Album());

    $tableGateway = new TableGateway('album', $dbAdapter, null, $resultSetPrototype);

    return new AlbumTable($tableGateway);
}

Upvotes: 1

Pieter
Pieter

Reputation: 1774

Make sure you've added Zend\Db\Adapter\AdapterAbstractServiceFactory to the abstract_factories array of the ServiceManager configuration. This abstract factory is responsible for instantiating the individual database adapters. Also, check whether your Album\Model\AlbumTable factory retrieves the database adapter with the correct name.

Upvotes: 2

Related Questions