diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index 32d51181998db..62114e9fc84c5 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -22,6 +22,7 @@ class RouteCompiler implements RouteCompilerInterface protected $route; protected $variables; protected $firstOptional; + protected $optionals; protected $segments; protected $tokens; protected $staticPrefix; @@ -38,6 +39,7 @@ public function compile(Route $route) { $this->route = $route; $this->firstOptional = 0; + $this->optionals = array(); $this->segments = array(); $this->variables = array(); $this->tokens = array(); @@ -91,11 +93,10 @@ protected function preCompile() */ protected function postCompile() { - // all segments after the last static segment are optional - // be careful, the n-1 is optional only if n is empty for ($i = $this->firstOptional, $max = count($this->segments); $i < $max; $i++) { - $this->segments[$i] = (0 == $i ? '/?' : '').str_repeat(' ', $i - $this->firstOptional).'(?:'.$this->segments[$i]; - $this->segments[] = str_repeat(' ', $max - $i - 1).')?'; + if (in_array($i, $this->optionals)) { + $this->segments[$i] = (0 == $i ? '/?' : '').'(?:'.$this->segments[$i].')?'; + } } $this->staticPrefix = ''; @@ -211,9 +212,10 @@ protected function compileForVariable($separator, $name, $variable) $this->segments[] = preg_quote($separator, '#').'(?P<'.$variable.'>'.$requirement.')'; $this->variables[$variable] = $name; - - if (!$this->route->getDefault($variable)) { - $this->firstOptional = count($this->segments); + + $this->firstOptional = 0; + if (null !== $this->route->getDefault($variable)) { + $this->optionals[] = count($this->segments)-1; } } diff --git a/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php b/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php index 9421e469d5bd3..fabb42386d463 100644 --- a/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php +++ b/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php @@ -70,7 +70,7 @@ public function provideCompileData() array( 'Route with several variables that have default values', array('/foo/{bar}/{foobar}', array('bar' => 'bar', 'foobar' => 'foobar')), - '/foo', '#^/foo(?:/(?P[^/\.]+?) (?:/(?P[^/\.]+?) )?)?$#x', array('bar' => '{bar}', 'foobar' => '{foobar}'), array( + '/foo', '#^/foo(?:/(?P[^/\.]+?))?(?:/(?P[^/\.]+?))?$#x', array('bar' => '{bar}', 'foobar' => '{foobar}'), array( array('variable', '/', '{foobar}', 'foobar'), array('variable', '/', '{bar}', 'bar'), array('text', '/', 'foo', null), @@ -79,12 +79,31 @@ public function provideCompileData() array( 'Route with several variables but some of them have no default values', array('/foo/{bar}/{foobar}', array('bar' => 'bar')), - '/foo', '#^/foo/(?P[^/\.]+?)/(?P[^/\.]+?)$#x', array('bar' => '{bar}', 'foobar' => '{foobar}'), array( + '/foo', '#^/foo(?:/(?P[^/\.]+?))?/(?P[^/\.]+?)$#x', array('bar' => '{bar}', 'foobar' => '{foobar}'), array( array('variable', '/', '{foobar}', 'foobar'), array('variable', '/', '{bar}', 'bar'), array('text', '/', 'foo', null), )), + array( + 'Route with several variables that some of them have no default values and some of them have empty defaults', + array('/foo/{bar}/{foobar}/{foofoobar}', array('bar' => 'bar', 'foobar' => '')), + '/foo', '#^/foo(?:/(?P[^/\.]+?))?(?:/(?P[^/\.]+?))?/(?P[^/\.]+?)$#x', array('bar' => '{bar}', 'foobar' => '{foobar}', 'foofoobar' => '{foofoobar}'), array( + array('variable', '/', '{foofoobar}', 'foofoobar'), + array('variable', '/', '{foobar}', 'foobar'), + array('variable', '/', '{bar}', 'bar'), + array('text', '/', 'foo', null), + )), + + array( + 'Route with several variables that some of them have no default values and one of them is first segment', + array('/{bar}/{foobar}/{foofoobar}', array('bar' => 'bar', 'foobar' => 'foobar')), + '', '#^/?(?:/(?P[^/\.]+?))?(?:/(?P[^/\.]+?))?/(?P[^/\.]+?)$#x', array('bar' => '{bar}', 'foobar' => '{foobar}', 'foofoobar' => '{foofoobar}'), array( + array('variable', '/', '{foofoobar}', 'foofoobar'), + array('variable', '/', '{foobar}', 'foobar'), + array('variable', '/', '{bar}', 'bar') + )), + array( 'Route with a custom token', array('/=foo', array(), array(), array('compiler_class' => 'Symfony\\Tests\\Component\\Routing\\RouteCompiler')),