ZF-5558: CLONE -Zend_Controller_Router_Route_Regex won't assemble when used with xml config

Description

When setting a reverse route through an xml config file, the assemble method of the regex route fails. The _getMappedValues method expects it's map to be in index => key form:


$index = (!is_int($key)) ? array_search($key, $this->_map, true) : $key;

this will fail when used with xml, which doesn't support this, a sample config could contain:



        1
    
        2
    

By limitation of xml this is different from the ini config and manual setup. When parsing the url this isn't a problem, but the assemble method fails to get any parts from the _getMappedValues method to parse into the query string and throws an exception. It can easily solved by modifying the method a little:


$index = (!is_int($key)) ? array_search($key, $this->_map, true) : $key;
if (false !== $index) {
    $return[$index] = $values[$key];
} elseif (isset($this->_map[$key])) {
    //non-numerical setup
    $return[$key] = $this->_map[$key];
}

Comments

As Maurice described in Bug #3474 there is a problem, when you try tu use Zend_Controller_Route_Regex with $router->addConfig($config, 'routes');

The Zend_Config object is initialized with a XML-file.

Due to the limitation of the xml-config object that only strings are returned.

All the mappings 1 ... are not recognized.

Robert

My fix for this problem:

in File Zend/Controller/Router/Route/Regex.php:131


       } elseif ($reversed) {


                $index = (!is_int ($key)) ? array_search ($key, $this->_map, true) : $key;
                if (false !== $index) {
                    $return[$index] = $values[$key];
                } elseif (array_key_exists($key, $this->_map)) {
                    //non-numerical setup
                    $return[(int)$this->_map[$key]] = $key;
                }


      } elseif ($preserve) {
                $return[$key] = $value;
      }

so long

In my last comment was a little Error ...

now it works correct

in File Zend/Controller/Router/Route/Regex.php:131



} elseif ($reversed) {


                $index = (!is_int ($key)) ? array_search ($key, $this->_map, true) : $key;
                if (false !== $index) {
                    $return[$index] = $values[$key];
                } elseif (array_key_exists($key, $this->_map)) {
                    //non-numerical setup
                    $return[(int)$this->_map[$key]] = $values[$key];
                }


      } elseif ($preserve) {
                $return[$key] = $value;
      }

Why still not fixed in ZF 1.9.0?

My Solution for this:

Replace Zend/Config/Xml.php (L252-282) with this one:

// Search for children
        if (count($xmlObject->children()) > 0) {
            foreach ($xmlObject->children() as $key => $value) {
                if (count($value->children()) > 0 || count($value->children(self::XML_NAMESPACE)) > 0) {
                    $value = $this->_toArray($value);
                } else if (count($value->attributes()) > 0 || count($value->attributes(self::XML_NAMESPACE)) > 0) {
                    $attributes = $value->attributes();
                    $attributesNS = $value->attributes(self::XML_NAMESPACE);

                    // Old Zend_Config Style
                    if (!isset($attributes['value']) && isset($attributes['type'])) {
                        $value = $this->typeConvert($value, $attributes);
                    } elseif (isset($attributes['value'])&& isset($attributes['type'])) {
                        $value = $this->typeConvert($attributes['value'], $attributes);
                    // New Zend_Config Style (1.9+)
                    } elseif (!isset($attributesNS['value']) && isset($attributesNS['type'])) {
                        $value = $this->typeConvert($value, $attributesNS);
                    } elseif (isset($attributesNS['value']) && isset($attributesNS['type'])) {
                        $value = $this->typeConvert($attributesNS['value'], $attributesNS);
                    } elseif (isset($attributes['value'])) {
                        $value = (string) $attributes['value'];
                    } else {
                        $value = $this->_toArray($value);
                    }
                } else {
                     $value = $this->typeConvert($value, $value->attributes());
                }

                if (array_key_exists($key, $config)) {
                    if (!is_array($config[$key]) || !array_key_exists(0, $config[$key])) {
                        $config[$key] = array($config[$key]);
                    }

                    $config[$key][] = $value;
                } else {
                    $config[$key] = $value;
                }
            }
        } else if (!isset($xmlObject['extends']) && !isset($nsAttributes['extends']) && (count($config) === 0)) {
            // Object has no children nor attributes and doesn't use the extends
            // attribute: it's a string
            $config = (string) $xmlObject;
        }

And add the following new protected function:

/**
     * Cast the type in the given Format
     *
     * @param mixed $value
     * @param mixed $attributes
     * @return mixed - The converted Type
     */
    protected function typeConvert($value, $attributes = array()) {
        $value = trim((string) $value);
        if (count($attributes) && isset($attributes['type'])) {
            switch (strtolower($attributes['type'])) {
                case 'int':
                case 'integer':
                    return (int) $value;
                case 'bool':
                case 'boolean':
                    return ($value == 'true')?true:false;
                case 'float':
                    return (float)$value;
                default:
                    return (string) $value;
            }
        }
        return $value;
    }

Now you can set the Type in the Config-XML File.

[...]
foo bar3306truefoo bar123
  [....]

[...]

Now you can just simply add the type that you want ...

It's possible to write the value as attribute e.g. or to use 123 .. is both the same

If you use the ZF Namespace use or 123

But dont mix it up wont work

I'm use default method getVariables in a __construct:

{quote} public function __construct($route, $defaults = array(), $map = array(), $reverse = null) { ... $this->_map = $this->getVariables($this->_map); } {quote}

and all works fine

Fixed in r18294, see [ZF-7658].

Assigning issue to ~jpieper as he fixed it.