Issues

ZF-5888: Zend_Config_Writer_* not properly handling unsectioned data

Description

When trying to write a Zend_Config that contains unsectioned elements, Zend_Config_Writer_Xml will omit these elements in the resulting XML file. This issue related to http://framework.zend.com/issues/browse/ZF-5544. Unlike Zend_Config_Writer_Ini Zend_Config_Writer_Xml will not throw an Exception though.

Since a Zend_Config can contain unsectioned elements, the behavior of both writers is unexpected. Both writers should be able to write Zend_Configs without a global section defined for them. Zend_Config_Writer_Xml already wraps all data inside a {{}} root element, so any unsectioned elements can reside below this element without breaking validity of the XML file. If global sections are required by ZF, the writers should at least both throw an Exception.

Example


        // Code from Example 7.2. Using Zend_Config with a PHP Configuration File
        $myValues = array(
            'webhost'  => 'www.example.com',
            'database' => array(
                'adapter' => 'pdo_mysql',
                'params'  => array(
                    'host'     => 'db.example.com',
                    'username' => 'dbuser',
                    'password' => 'secret',
                    'dbname'   => 'mydatabase'
                )
            )
        );
        $config = new Zend_Config($myValues);
        // will output the array as defined above
        Zend_Debug::dump($config->toArray());


        // write config to an XML file
        $writer = new Zend_Config_Writer_Xml(array('config'   => $config,
                                                   'filename' => 'test.xml'));
        // yields no error, but loses data
        $writer->write();
        // Read in XML file        
        $xml = new Zend_Config_Xml('test.xml');
        // Webhost is missing
        Zend_Debug::dump($xml->toArray());


        // Try to write an Ini file from the example config
        $writer = new Zend_Config_Writer_Ini(array('config'   => $config,
                                                   'filename' => 'test.ini'));
        // will throw an Exception as stated in ZF-5544
        $writer->write();

The resulting XML file


<?xml version="1.0"?>
pdo_mysqldb.example.comdbusersecretmydatabase

Comments

In fact, Zend_Config_Writers (except _Array) always expects the highest elements in Zend_Config to be the sections. What you are doing in your example is converting from an array config (which can never contain sections, thus Zend_Config_Writer_Array works fine with no sections) to a configuration format which requires sections when loaded with Zend_Config_Xml / Zend_Config_Ini. Thus this simply cannot work properly.

Zend_Config_Writer_Xml is natually omitting the webhost-key, as it is seen as an invalid section. That Zend_Config_Writer_Ini is throwing a catchable fatal error is surely wrong, it should have the same behaviour as Zend_Config_Writer_Xml at this point.

I'd rather have Zend_Config_Writer_Xml throw an Exception than simply ignoring my Config data then. Since any Zend_Config allows me to add unsectioned data at runtime when the Config was loaded with allowModification set to true, I'd expect a corresponding writer to be able to handle this data or give notice when it cannot. Especially when one Writer is able to handle that data and the other is not. Being able to set unsectioned elements at all is misleading in that case. If I cannot persist a Zend_Config without sections, then the interface should reflect that. Besides, neither Ini files, nor Xml files naturally require their data to be in sections and the Zend_Config readers work fine with unsectioned data. The data is accessible through the regular object notation. So either way, something is wrong.

Well, the difference is, that a runtime Zend_Config object itself does not have sections. Sections are just a construct of the _Xml and _Ini implementation. Thus Zend_Config_Writer has to guess that the highest level is the section definition. What actually could be done, would be an extra option for both the _Xml and _Ini writer to not treat the highest level as sections but as usual nodes. Tho still, this should not be the default.

Fixed with r14175 and merged into 1.7 release branch with r14176.