Issues

ZF2-437: Router HTTP Segment does not handle defaults correctly when matching

Description

This might be same problem as (ZF2-408), but didn't want to piggyback in case it isn't.

When reassembling a URL from a routematch that contains defaults, it does not reconstruct the URL properly. My router config:

'media' => array (
    'type' => 'Zend\Mvc\Router\Http\Segment',
    'options' => array (
        'route' => '/media[/:title][/:mediatype][/:item][/]',
        'constraints' => array (
            'mediatype' => ('videos|screenshots'),
            'title' => ('shakespeare|pinter')
        ),
        'defaults' => array (
            'mediatype' => '',
            'action' => 'index',
            'controller' => 'MyModule\Controller\MediaController',
        ),
    ),
),

If I enter a url of {{/media/videos/}}, my RouteMatch looks like this:

object(Zend\Mvc\Router\Http\RouteMatch)[190]
  protected 'length' => int 25
  protected 'params' => 
    array
      'subpage' => string 'videos' (length=11)
      'action' => string 'index' (length=5)
      'controller' => string 'MyModule\Controller\MediaController' (length=35)
      'title' => string '' (length=0)
  protected 'matchedRouteName' => null

This URL works and is accessible. However, if I am assembling this URL using this RouteMatch object, i.e. for a redirect, e.g.:

$router = $event->getRouter();
$params = $routeMatch->getParams();
$redirectUrl = $router->assemble($params, array(
   'name' => $routeMatch->getMatchedRouteName()
));

$redirectUrl ends up looking like: {{/media//videos/}}. This is because title is present as an empty string instead of being null or not present at all. I have tried setting title => null in the defaults config, but this doesn't do anything. Nor do I want to be explicit in the redirector because it serves as a sitewide redirector.

Having looked at the source, it looks to me like the problem lies with the array_merge in match() when it's building the RouteMatch object (see https://github.com/zendframework/zf2/… line 337). The regexp returns this:

array
  0 => string '/media/videos/' (length=15)
  'param1' => string '' (length=0)
  1 => string '' (length=0)
  'param2' => string 'videos' (length=6)
  2 => string 'videos' (length=6)

So you get empty strings for the optional parameters when they're not found. These are then combined with the defaults and unfortunately override the defaults, so in the case above the "title" parameter will be empty string. To give the arguments that "optional" feel, if the regexp returns an empty string it should unset or return null in the RouteMatch that it builds.

Comments

It is in fact the same issue.