zendframework/zend-developer-tools

ZF 3 with DeveloperTools

Closed this issue · 10 comments

Hi,

  1. I installed zf3 via composer (all dependencies for testing purposes).
  2. Vhost application env to "development"
  3. Added via composer require-dev "zendframework/zend-developer-tools": "^1.1"
  4. Added a development.config.php to my /config folder with the following content:
<?php
// zf3-tutorial/config/autoload/zenddevelopertools.local.php
return [
    // Development time modules
    'modules' => [
        'ZendDeveloperTools',
    ],
    'module_listener_options' => [
        // Turn off caching
        'config_glob_paths' => [realpath(__DIR__) . '/autoload/{,*.}{global,local}-development.php'],
        'config_cache_enabled'     => false,
        'module_map_cache_enabled' => false,
    ],
    'view_manager' => [
        'display_exceptions' => true,
    ],
];

When I comment out the modules value part for the ZendDeveloperTools my system is starting, but if I want the DevTools the system is crashing with the following error:

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/rogatec/zf3-tutorial/vendor/zendframework/zend-servicemanager/src/ServiceManager.php on line 754

( ! ) Zend\Db\Adapter\Exception\InvalidArgumentException: createDriver expects a "driver" key
to be present inside the parameters in /var/www/USER/rogatec/zf3-tutorial/vendor/zendframework/zend-db/src/Adapter/Adapter.php on line 262

So the upper problem seems to be a problem with the database adapters I've configured in my global.php and local.php file.

So take a look to the db part global.php:

// zf3-tutorial/config/autoload/global.php
use Zend\Db\Adapter\AdapterAbstractServiceFactory;
return [
    'service_manager' => [
        'abstract_factories' => [
            AdapterAbstractServiceFactory::class,
        ],
    ],
];

local.php:

// zf3-tutorial/config/autoload/local.php
'db' => [
        'adapters' => [
            'db1' => [
                'driver' => 'Pdo',
                'dsn' => 'mysql:dbname=database1;host=localhost',
                'driver_options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ],
                'username' => 'test',
                'password' => 'test',
            ],
            'db2' => [
                'driver' => 'Pdo',
                'dsn' => 'mysql:dbname=database2;host=localhost',
                'driver_options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ],
                'username' => 'test',
                'password' => 'test',
            ],
        ],
    ],

Any hints what I've might done wrong or any missing information you need for give some solution hints?

The problem occurs because the AdapterServiceFactory misses the single db configuration:

// single db adapter solution example
return [
    'db' => [
        'driver' => 'Pdo',
        'dsn' => 'mysql:dbname=database;host=localhost',
        'driver_options' => [
               PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ],
        'username' => 'test',
        'password' => 'test',
    ],
];

The documentation says, that when using a multi db configuration you should implement the abstract_factories part, which I obviously did.

@rogatec What call are you making to the service manager to retrieve the db instance? If you call "get('db1')" or "get('db2')" I should think this setup should work.

Hi @robob4him - for example in my AlbumControllerFactory I do this:

public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $albumTable = $container->get(AlbumTable::class);
        $svAdapter = $container->get('db2');

        return new AlbumController($albumTable, $svAdapter);
    }

Then in my AlbumController I can call the db adapter:

public function gotoAction()
    {
        // second adapter
        $db = new Sql($this->svAdapter);
        $select = $db->select('projects');
        $select->where(['id' => 139]);
        $stmt   = $db->prepareStatementForSqlObject($select);
        $result = $stmt->execute();

        // ...
    }

So this setup works fine - but when I enable the development-mode (now the ZendDeveloperTools module is active) via terminal my page crashes with the exception from my initial post.

I'll take a guess and say you have the db profiler enabled. The problem with that is that bjyprofiler doesn't support multiple db connections via the adapter factory. It wouldn't be hard, really, just combine the functionality of the adapter factory and the Zend\Db\Adapter\AdapterAbstractFactory and enable it in the service manager instead of zend framework's. If you have a fuller trace of the exception you could verify that it is bjyprofiler throwing the exception. If I remember I'll try this setup to try to break down exactly where it's happening.

Sadly to say, but I neither have the db profiler enabled nor installed.

This is my modules.config.php

return [
    'Zend\InputFilter',
    'Zend\Filter',
    'Zend\Hydrator',
    'Zend\I18n',
    'Zend\ServiceManager\Di',
    'Zend\Session',
    'Zend\Mvc\Plugin\Prg',
    'Zend\Mvc\Plugin\Identity',
    'Zend\Mvc\Plugin\FlashMessenger',
    'Zend\Mvc\Plugin\FilePrg',
    'Zend\Mvc\Console',
    'Zend\Log',
    'Zend\Form',
    'Zend\Db',
    'Zend\Router',
    'Zend\Validator',
    'Application',
    'Album',
];

The ZendDeveloperTools are getting enabled via composer development-enable - then the existing development.config.php.dist in my /config folder will be transformed to a valid php file with the following content:

return [
    // Additional modules to include when in development mode
    'modules' => [
        'ZendDeveloperTools',
    ],
    // Configuration overrides during development mode
    'module_listener_options' => [
        'config_glob_paths' => [realpath(__DIR__) . '/autoload/{,*.}{global,local}-development.php'],
        'config_cache_enabled' => false,
        'module_map_cache_enabled' => false,
    ],
];

should already fixed by #218 , close-able.

@samsonasik nope this (f75787f) does not fix the issue.

What's the correct configuration for multi-db adapters, that works with the dev tools?

Why is:

'db' => [
        'adapters' => [
            'db1' => [
                'driver' => 'Pdo',
                'dsn' => 'mysql:dbname=zf3;host=localhost',
                'driver_options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ],
            ],
            'db2' => [
                'driver' => 'Pdo',
                'dsn' => 'mysql:dbname=redmine;host=localhost',
                'driver_options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ],
            ],
        ],
    ],

working, when dev tools are disabled, but not if it is?

@rogatec I think the 'root' adapter of 'db' should be defined first if you define 'db' key, so, your config may be:

'db' => [
     // root adapter called from $services->get(\Zend\Db\Adapter\AdapterInterface::class);
     'driver' => 'Pdo',
     'dsn' => 'mysql:dbname=zf3;host=localhost',
     'driver_options' => [
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
      ],

       // more adapters
        'adapters' => [
            'db1' => [
                'driver' => 'Pdo',
                'dsn' => 'mysql:dbname=zf3;host=localhost',
                'driver_options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ],
            ],
            'db2' => [
                'driver' => 'Pdo',
                'dsn' => 'mysql:dbname=redmine;host=localhost',
                'driver_options' => [
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ],
            ],
        ],
    ],

@samsonasik - yes this is a workaround when you are in development mode.

But you can work with adapters only, when in production mode - this is quite confusing.

this default 'db' config by @weierophinney may fixes this issue zendframework/zend-db#164

can be closed in favor of #218