Issues

ZF-7368: Chain route fails to match with an optional route at the end

Description

Chained routes with optional params are not matched

Static route: "blog" route: ":page" - This route has default page variable specified as 1

Should match: - /blog - /blog/ - /blog/1 - /blog/2/

Currently doesn't match: - /blog - /blog/

It does not match this in the chain class due to checking of the separator to ensure it matches what was set internally. The problem is since it's optional, the separator doesn't exist to check it with the array....

At first glance, adding "$separator !== false &&" to the if statement seems to fix it, but I have not run the unit tests.


    public function match($request, $partial = null)
    {
        $path    = trim($request->getPathInfo(), '/');
        $subPath = $path;
        $values  = array();

        foreach ($this->_routes as $key => $route) {
            if ($key > 0 && $matchedPath !== null) {
                $separator = substr($subPath, 0, strlen($this->_separators[$key]));
                
                if ($separator !== false && $separator !== $this->_separators[$key]) {
                    return false;                
                }
                
                $subPath = substr($subPath, strlen($separator));
            }

Comments

I have the same problem, but I think the soultion must be something like this: 1) add this line before if statement if ($separator === false) $separator=''; or 2) remove line: $path = trim($request->getPathInfo(), '/');

then it works for my case: I'm using urls like /search/query/ /search/query/page3.html 1) $routerPage = new Zend_Controller_Router_Route_Regex(
'/(page(\d+).html)?', array( ), array( 2 => 'page' ) );

    $routerSearch = new Zend_Controller_Router_Route(  
                                            'search/:query',
                                            array(
                                                'controller' => 'list',
                                                'action' => 'search'
                                            ),
                                            array(
                                                'query' => '[^/]+'
                                            )
                                        );  

    $chainedRouterSearch = $routerSearch->chain($routerPage, '');
    $router->addRoute('search', $chainedRouterSearch);

2) Separator is '/' , removed from '(page(\d+).html)?' $routerPage = new Zend_Controller_Router_Route_Regex(
'(page(\d+).html)?', array( ), array( 2 => 'page' ) );

    $routerSearch = new Zend_Controller_Router_Route(  
                                            'search/:query',
                                            array(
                                                'controller' => 'list',
                                                'action' => 'search'
                                            ),
                                            array(
                                                'query' => '[^/]+'
                                            )
                                        );  

    $chainedRouterSearch = $routerSearch->chain($routerPage, '/');
    $router->addRoute('search', $chainedRouterSearch);

I have the same problem, but I think the soultion must be something like this: 1) add this line before if statement if ($separator === false) $separator=''; or 2) remove line: $path = trim($request->getPathInfo(), '/');

then it works for my case: I'm using urls like /search/query/ /search/query/page3.html

1)


        $routerPage = new Zend_Controller_Router_Route_Regex(  
                                                '(/page(\d+)\.html)?',
                                                array(
                                                ),
                                                array(
                                                    2 => 'page'
                                                )
                                            );      
                                            
        $routerSearch = new Zend_Controller_Router_Route(  
                                                'search/:query',
                                                array(
                                                    'controller' => 'list',
                                                    'action' => 'search'
                                                ),
                                                array(
                                                    'query' => '[^/]+'
                                                )
                                            );  

        $chainedRouterSearch = $routerSearch->chain($routerPage, '');
        $router->addRoute('search', $chainedRouterSearch);

2) Separator is '/' , removed from '(page(\d+).html)?'


        $routerPage = new Zend_Controller_Router_Route_Regex(  
                                                '(page(\d+)\.html)?',
                                                array(
                                                ),
                                                array(
                                                    2 => 'page'
                                                )
                                            );      
                                            
        $routerSearch = new Zend_Controller_Router_Route(  
                                                'search/:query',
                                                array(
                                                    'controller' => 'list',
                                                    'action' => 'search'
                                                ),
                                                array(
                                                    'query' => '[^/]+'
                                                )
                                            );  

        $chainedRouterSearch = $routerSearch->chain($routerPage, '/');
        $router->addRoute('search', $chainedRouterSearch); 

I have the same problem.

This is exactly the same problem I have reported in bug ZF-9030 only that deals with a module router at the end. But the problem remains... While creating the patch reported in that bug I actually never realised the problem also occurs with 'normal' optional parameters.

I would have assumed this issue to be solved along ZF-7848, ZF-8812 and ZF-9030, but there is still something wrong with matching to the default value. I wrote these two unit test (attachment) which of the first one does not pass:

Zend_Controller_Router_Route_ChainTest::testChainingStaticDynamicMatchToDefaultValue Failed asserting that matches expected

I'll look at this for the 1.11.1 release. Thanks for the unit tests -- those definitely help better isolate the issue!

I have located the issue. The attached patch includes both the fix and the tests. I suggest that the maintainer of this component or the reviewer would check the patch if they came up with more elegant solution.

Patch accepted, but I have no time right now to merge it, can somebody else take that part?

There is one tiny CS violation in the patch tho, where it says:


             }
             // Empty variable? Replace with the default value.
             elseif ($return[$var] == '' || $return[$var] === null) {

But it should be:


             } elseif ($return[$var] == '' || $return[$var] === null) {
                 // Empty variable? Replace with the default value.

Also, the patch partly contains tabs instead of 4-space groups, that should be fixed as well.

@Ben, sure I can.

Fixed in r23711