Issues

ZF2-6: Zend_Config_Xml: allow extending for lower levels

Issue Type: New Feature Created: 2009-01-30T05:54:32.000+0000 Last Updated: 2012-04-29T10:45:44.000+0000 Status: Resolved Fix version(s): Reporter: Jan Pieper (jpieper) Assignee: Ben Scholzen (dasprid) Tags: - Zend\Config

Related issues: Attachments: - zf-5660.diff

Description

It would be great if it is possible to define extends in lower xml structure levels. Take a look at this xml structure below.

<pre class="highlight">sliding7510

I am not sure what to do with staging.second-application.entries-per-page. Should it use entries-per-page=5 or entries-per-page=10?

I think this improvement will need a complete refactoring of Zend_Config(_Xml).

Comments

Posted by Jan Pieper (jpieper) on 2009-01-30T09:52:57.000+0000

corrected xml example.

Posted by Jan Pieper (jpieper) on 2009-02-02T16:04:44.000+0000

This evening I tried to solve this issue and I think I´ve found a good way. I used this modified xml structure:

<pre class="highlight">sliding75jumping10

My Zend_Config_Xml::__construct() is:

<pre class="highlight">public function __construct($filename, $section = null, $allowModifications = false)
{
    if (empty($filename)) {
        require_once 'Zend/Config/Exception.php';
        throw new Zend_Config_Exception('Filename is not set');
    }
    
    set_error_handler(array($this, '_loadFileErrorHandler'));
    $config = simplexml_load_file($filename); // Warnings and errors are suppressed
    restore_error_handler();
    
    // Check if there was a error while loading file
    if ($this->_loadFileErrorStr !== null) {
        require_once 'Zend/Config/Exception.php';
        throw new Zend_Config_Exception($this->_loadFileErrorStr);
    }
    
    $sections = array();
    if (is_array($section)) {
        $sections = $section;
    } elseif ($section !== null) {
        if (!isset($config->$section)) {
            require_once 'Zend/Config/Exception.php';
            throw new Zend_Config_Exception("Section '$section' cannot be found in $filename");
        }
        $sections = array($section);
    }
    
    parent::__construct(
        $this->_processExtendsRecursive($config, $sections),
        $allowModifications
    );

    $this->_loadedSection = $section;
}

And I replaced Zend_Config_Xml::_processExtends() with new Zend_Config_Xml::_processExtendsRecursive():

<pre class="highlight">protected function _processExtendsRecursive(SimpleXMLElement $element,
                                            array $sections = array(),
                                            $depth = 0)
{
    $config = array();
    foreach ($element->children() as $children)
    {
        $childs = $children->children();
        $config[$elementName = $children->getName()] = empty($childs)
            ? $this->_toArray($children)
            : $this->_processExtendsRecursive($children, array(), $depth+1);
        
        $attributes = $children->attributes();
        foreach ($attributes as $attribute => $value)
        {
            if ($attribute !== 'extends') {
                continue;
            }
            
            $extendedSection = (string)$value;
            if (!array_key_exists($extendedSection, $config)) {
                require_once 'Zend/Config/Exception.php';
                throw new Zend_Config_Exception("Section '$extendedSection' cannot be found");
            }
            
            $data = $config[$extendedSection];
            if (is_array($data) && is_array($config[$elementName])) {
                $config[$elementName] = $this->_arrayMergeRecursive(
                    $data, $config[$elementName]
                );
            } elseif (is_array($data)) {
                $config[$children->getName()] = $data;
            }
            
            if ($depth == 0) {
                $this->_assertValidExtend($elementName, $extendedSection);
            }
        }
    }
    
    if (!empty($sections)) {
        foreach ($config as $key => $value) {
            if (!in_array($key, $sections)) {
                unset($config[$key]);
            }
        }
    }
    
    if (empty($config)) {
        $config = (string)$element;
    }
    return $config;
}

Following script...

<pre class="highlight"><?php

require_once 'Zend/Config/Xml.php';
$config = new Zend_Config_Xml('zf-5660.xml');

require_once 'Zend/Debug.php';
Zend_Debug::dump($config->toArray());

...will output this:

<pre class="highlight">array(3) {
  ["production"] => array(2) {
    ["first-application"] => array(2) {
      ["paginator-type"] => string(7) "sliding"
      ["entries-per-page"] => string(1) "7"
    }
    ["second-application"] => array(2) {
      ["paginator-type"] => string(7) "sliding"
      ["entries-per-page"] => string(1) "5"
    }
  }
  ["staging"] => array(2) {
    ["first-application"] => array(2) {
      ["paginator-type"] => string(7) "jumping"
      ["entries-per-page"] => string(2) "10"
    }
    ["second-application"] => array(2) {
      ["paginator-type"] => string(7) "sliding"
      ["entries-per-page"] => string(1) "5"
    }
  }
  ["testing"] => array(2) {
    ["first-application"] => array(2) {
      ["paginator-type"] => string(7) "jumping"
      ["entries-per-page"] => string(2) "10"
    }
    ["second-application"] => array(2) {
      ["paginator-type"] => string(7) "sliding"
      ["entries-per-page"] => string(1) "5"
    }
  }
}

I also attached all these changes to Zend_Config_Xml to this issue: zf-5660.diff

Posted by Rob Allen (rob) on 2009-02-02T23:55:18.000+0000

Currently there is feature parity between XML and INI formats. How would this work with the INI file format?

Posted by Jan Pieper (jpieper) on 2009-02-03T01:12:53.000+0000

Yeah I already thought about how to realize this improvement for INI files but I have no really good idea because INI files have only one real dimension. Using "." in INI files to allow multidimensional INI configurations is no standard I think. You can use it for all other applications without any problems but they do not know that you want to define a multidimensional configuration.

<pre class="highlight">[foo]
foo.bar = test


<pre class="highlight"><?php

parse_ini_file('example.ini', true);

will result in:

<pre class="highlight">array(1) {
  ["foo"] =>
  array(1) {
    ["foo.bar"]=>
    string(4) "test"
  }
}

and not:

<pre class="highlight">array(1) {
  ["foo"] =>
  array(1) {
    ["foo"] =>
    array(1) {
      ["bar"]=>
      string(4) "test"
    }
  }
}

Without complete redefinition of our INI format, I think it will be very tricky to allow the same functionality to INI files.

Posted by Ben Scholzen (dasprid) on 2009-02-04T06:17:44.000+0000

This feature cannot be implemented until 2.0 for the following reason: At the moment, the "extend" attribute is only reserved for the section-, but no deeper element. Thus, this feature would break BC, as users could still have used the "extend" attribute in they config files (short param syntax).

Posted by Ben Scholzen (dasprid) on 2009-02-18T08:48:29.000+0000

After talking with Matthew about it, we decided that this break (for XML is allowed).

Posted by Rob Allen (rob) on 2009-03-21T13:04:03.000+0000

Personally, I'm not convinced this is a good idea as it introduces potential confusion and additional complexity when writing config files for relatively little gain.

e.g.

<pre class="highlight">
<var>one</var>
        bar<var>two</var>
    <var>three</var>
    baz

$config->app2->var now equals "three" rather than two as probably expected due to a typo.

However, having said that, if someone develops a patch with unit tests then if Matthew's happy for it to go in, then that's fine.

Posted by Thomas Weidner (thomas) on 2010-03-21T10:27:51.000+0000

Reassigned to component maintainer

Posted by Rob Allen (rob) on 2011-05-27T01:53:39.000+0000

We'll look at this again when refactoring ZF2. I personally think that being able to load a file into another file will solve this one more cleanly with less user confusion.

Posted by Rob Allen (rob) on 2012-04-28T16:14:38.000+0000

Ben: Any thoughts for ZF2?

Posted by Ben Scholzen (dasprid) on 2012-04-29T10:45:44.000+0000

As we are not supporting inheritance in ZF2 anymore, this issue will be closed.

Have you found an issue?

See the Overview section for more details.

Copyright

© 2006-2016 by Zend, a Rogue Wave Company. Made with by awesome contributors.

This website is built using zend-expressive and it runs on PHP 7.

Contacts