ZF-6720: Zend_Config_Writer has no option to get a string of the config data, it can only output to file

Description

Zend_Config_Writer has no option to obtain a string of the configuration data it will write to a file. There are instances where you would like to work with the string instead of simply writing it to a file. You might want to store the config data in something other than a file, or expose them through a web service.

Comments

Why would you want to store a configuration as XML (which kinda is a database) in another database?

There are many valid reasons (think user-specific configs, that are not predefined), xml is a handier format for storing trees than relational databases anyway. Databases aren't the only application here. I have a service layer which needs access to configuration that is the result of merged configs for which I need an xml string.

It's not the sense of a writer to output strings. If you want to store a config object in a database, simply do serialize($config) or something similar.

Closing the issue with this reply is absolutely not satisfactory and downright insulting, please be professional.

There are many valid reasons one could have to obtain just string and do the actual writing to a i/o stream separately. Creating a web-service which exposes (parts of) a configuration was the one I ran into. I can also see a use case, for xml configs, where one would do XSLT upon the string. Your idea that xml is "kinda a database" is a fallacy as a file-system is one too.

The need to store configurations (that are variable) in a standardized format in a database is the most obvious use case. Your proposed solution to use a serialized config object is extremely poor design and would pin all future queries against that database to a php implementation. While it is true that one could model an actual variable configuration layer in a relational database, ZF offers no support for db based configs.

The fact that the writer already has all the necessary functionality to produce strings makes a fix for this issue easy. Furthermore it could be implemented without breaking the API, although I must say that the file-centric implementation is poorly thought out anyway. What is the rationale behind the limitation towards file-based config writing?

Speaking of poor design, it is pretty wrong as well to store XML in a database when you could do it in the correct way. I have created a Zend_Config_Db proposal some time ago, but since there was never much feedback, I had froozen it. If you are actually interested in storing configurations in a database, you should comment on that proposal.

http://framework.zend.com/wiki/x/jwAa

I have to agree with Ben.

It is not the purpose that has driven the design of the config writers, and if it were, then this issue should be for Zend_Config_Writer and not Zend_Config_Writer_Xml.

It does sound as though the means to your end would be better suited with something like SimpleXML, or one of the other many native PHP XML libraries.

Agreed, Zend_Config_Db is the ultimate solution for db-based configs. However, that is a completely separate issue from the one at hand here. Ryan makes a fair point that this issue is more related to Zend_Config_Writer in general than Zend_Config_Writer_Xml. Xml output is probably the more requested, but that does not mean that I might not want to expose my configurations in ini format for instance.

Also, for ben, I would suggest you read http://dev.mysql.com/tech-resources/articles/… for some background info about how xml is used in conjunction with relational databases (a quick google should turn up more about this subject).

Updated the description a little to reflect the fact that this applies to Zend_Config_Writer in general, not just Zend_Config_Writer_Xml

I need something similar. I made some modules that you can install. It will execute some SQL-statements, copy some files and it also needs to merge some config-files. I can't and I also don't want to write the merged config to the filesystem. I want to output the config and after a manual check, I will copy and paste the new config in the right file (sometimes, i don't want the changes to be made). Almost everything is already written to make this happen. Just add a toString method or something and copy almost everything from the write method in the new method. The write method will then call the toString method and write everything to the file.

Here is a hacked extension that allows you to return an XML string.

If the ''file aspects'' were separated/refactored from the ''xml generation'' aspects in the write() method of the parent class, then the extension would be a lot less smelly.

Apologies for breaking code-style convention - i think my way is nicer and easier read...funny that.

Any way this does the job i think:

 
require_once 'Zend/Config/Writer/Xml.php';

/**
 * i basically copied the write method and removed the bits relating to files
 */
class MYzendx_Config_Writer_XmlString extends Zend_Config_Writer_Xml
    {
    /**
    * 
    * returns a string
    *
    * @param  Zend_Config $config
    *
    *
    * @return string
    */
    public function writeString(Zend_Config $config = null)
        {

        if ($config !== null)
            {
            $this->setConfig($config);
            }


        if ($this->_config === null)
            {
            require_once 'Zend/Config/Exception.php';
            throw new Zend_Config_Exception('No config was set');
            }

        $xml         = new SimpleXMLElement('');
        $extends     = $this->_config->getExtends();
        $sectionName = $this->_config->getSectionName();

        if (is_string($sectionName))
            {
            $child = $xml->addChild($sectionName);

            $this->_addBranch($this->_config, $child);
            }
         else   {
            foreach ($this->_config as $sectionName => $data)
                {
                if (!($data instanceof Zend_Config)) {
                continue;
                }
            $child = $xml->addChild($sectionName);

            if (isset($extends[$sectionName]))
                {
                $child->addAttribute('extends', $extends[$sectionName]);
                }

            $this->_addBranch($data, $child);
            }
        }

        $dom = dom_import_simplexml($xml)->ownerDocument;
        $dom->formatOutput = true;

        $xmlString = $dom->saveXML();

        return $xmlString;
        }

    //i thought i'd add this bit just for the record

    /**
    * Defined by Zend_Config_Writer
    *
    * @param  string      $filename
    * @param  Zend_Config $config
    * @throws Zend_Config_Exception When filename was not set
    * @throws Zend_Config_Exception When filename is not writable
    * @return void
    */
    /*
    public function write($filename = null, Zend_Config $config = null)
        {
        if ($filename !== null)
            {
            $this->setFilename($filename);
            }

        //----------modification start

        if ($this->_filename === null)
            {
            require_once 'Zend/Config/Exception.php';
            throw new Zend_Config_Exception('No filename was set');
            }

        $xmlString = $this->writeString($config);


        //----------modification end

        $result = @file_put_contents($this->_filename, $xmlString);

        if ($result === false)
            {
            require_once 'Zend/Config/Exception.php';
            throw new Zend_Config_Exception('Could not write to file "' . $this->_filename . '"');
            }
        }
    */

    }