Issues

ZF-2220: Zend_Db::factory not working with Zend_Config_Xml nor with Zend_Config_Ini

Description

I have the following code.

        //$dbConfiguration = new Zend_Config_Xml(dirname(__FILE__) . '/dbConfiguration.xml', 'production', true);
        $dbConfiguration = new Zend_Config_Ini(dirname(__FILE__) . '/dbConfiguration.ini', 'production', true);

        // Decrypts encrpyted configuration values.
        $dbConfiguration->database->host        = self::decryptData( $dbConfiguration->database->host );
        $dbConfiguration->database->name        = self::decryptData( $dbConfiguration->database->name );
        $dbConfiguration->database->username    = self::decryptData( $dbConfiguration->database->username );
        $dbConfiguration->database->password    = self::decryptData( $dbConfiguration->database->password );

        // Gets Adapter.
        self::$_DataBaseSingleton = Zend_Db::factory($dbConfiguration);

But it does not seem to work. Looking at factory function, i see it has this:

    /*
     * Convert Zend_Config argument to plain string
     * adapter name and separate config object.
     */
    if ($adapter instanceof Zend_Config) {
        if (isset($adapter->params)) {
            $config = $adapter->toArray();
        }elseif(isset($adapter->adapter)) {
            $adapter = (string) $adapter->adapter;
        } else {
            $adapter = null;
        }
    }

Looking at Zend Config, both for XML and INI, I didn't found this params object. Am I doing something wrong or is this a bug?

Comments

Zend_Db::factory() allows you to use the following two formats for Zend_Config_*:


...->adapter  = 'pdo_mysql';
...->host     = 'localhost';
...->dbname   = 'db_name';
...->username = 'someuser';
...->password = 'somepass';

or


...->adapter          = 'pdo_mysql';
...->params->host     = 'localhost';
...->params->dbname   = 'db_name';
...->params->username = 'someuser';
...->params->password = 'somepass';

For one, it looks like you're not specifying an adapter.

Let me know if this helps...

Jordan's comment illustrates how to supply configuration data as a Zend_Config object. Resolving as not an issue. Please feel free to reopen with additional information (e.g., the relevant parts of the configuration file, exception messages) if this does not work for you.

Bug confirmed ! It can be reproduced very easily :


$configSQL = new Zend_Config_Ini('sql.ini', 'master');
$db = Zend_Db::factory($configSQL );

[master]
adapter="pdo_mysql"
host="localhost"
username="me"
password="myself"
dbname="mydb"

Exception raised : Uncaught exception 'Zend_Db_Adapter_Exception' with message 'Configuration array must have a key for 'dbname' that names the database instance' in D:\MyProject\Zend\Db\Adapter\Abstract.php:243

a var_dump($config) in Zend\Db\Adapter\Abstract.php:242 gives us :


array(0) { } 

So, we have to find out why $config is empty. Solution is in Zend/Db.php:192


if ($adapter instanceof Zend_Config) {
            if (isset($adapter->params)) {
                $config = $adapter->params->toArray();
            }
...

$adapter->params is not set for Zend_Config_Ini objects. My advice is to add an else like this :


if ($adapter instanceof Zend_Config) {
            if (isset($adapter->params)) {
                $config = $adapter->params->toArray();
            } else {
               $config = $adapter->toArray();
           }
           [...]
}

This patch is working for me.

Pasting the example from the documentation:


<?php
require_once 'Zend/Config.php';
require_once 'Zend/Db.php';

$config = new Zend_Config(
    array(
        'database' => array(
            'adapter' => 'Mysqli',
            'params' => array(
                'dbname' => 'test',
                'username' => 'webuser',
                'password' => 'secret',
            )
        )
    )
);

$db = Zend_Db::factory($config->database);
));

Translating this to ini format would result in:

[someSection]
database.adapter = "Mysqli"
database.params.dbname = "test"
database.params.username = "webuser"
database.params.password = "secret"

And you would pass {{$config->database}} to the {{Zend_Db::factory()}}

Ok, so that would mean that docs for Zend_Config_Ini and Zend_Config_XML have errors.

I created both the XML file and the INI file based on these examples:

http://framework.zend.com/manual/en/…

<?xml version="1.0"?> www.example.compdo_mysqldb.example.comdbusersecretdbnamedev.example.comdevuserdevsecret

http://framework.zend.com/manual/en/…

[production] webhost = www.example.com database.type = pdo_mysql database.host = db.example.com database.username = dbuser database.password = secret database.name = dbname

; Staging site configuration data inherits from production and ; overrides values as necessary [staging : production] database.host = dev.example.com database.username = devuser database.password = devsecret

And as you can see, they dont have the "params" attribute

Well, I wouldn't say that these examples are errors, since they do not show interaction with Zend_Db, but I do think they are misleading. I'll update the docs shortly to avoid the confusion. :)

Thanks for the report!

Thanks

{quote}Zend_Db::factory() allows you to use the following two formats for Zend_Config_*: ...->adapter = 'pdo_mysql'; ...->host = 'localhost'; ...->dbname = 'db_name'; ...->username = 'someuser'; ...->password = 'somepass';{quote}

This comment is not true. Having a similar issue and working through the source code for Zend/Db.php, it shows the only acceptable format is:

{quote}adapter = ''; params.host = ''; params.dbname = ''; params.username = ''; params.password = '';{quote} Not including "params" for the other parameters (other than adapter) will have the entire array replaced by the name of the adapter.

This can be seen in the source file: Zend/Db.php line 209