Переглянути джерело

[Routing] fixed routing when a pattern has only one segment which is an optional variable

Fabien Potencier 14 роки тому
батько
коміт
d2a9b23c28

+ 15 - 8
src/Symfony/Component/Routing/RouteCompiler.php

@@ -71,15 +71,22 @@ class RouteCompiler implements RouteCompilerInterface
         // compute the matching regexp
         $regex = '';
         $indent = 1;
-        foreach ($tokens as $i => $token) {
-            if ('text' === $token[0]) {
-                $regex .= str_repeat(' ', $indent * 4).preg_quote($token[1], '#')."\n";
-            } else {
-                if ($i >= $firstOptional) {
-                    $regex .= str_repeat(' ', $indent * 4)."(?:\n";
-                    ++$indent;
+        if (1 === count($tokens) && 0 === $firstOptional) {
+            $token = $tokens[0];
+            ++$indent;
+            $regex .= str_repeat(' ', $indent * 4).sprintf("%s(?:\n", preg_quote($token[1], '#'));
+            $regex .= str_repeat(' ', $indent * 4).sprintf("(?P<%s>%s)\n", $token[3], $token[2]);
+        } else {
+            foreach ($tokens as $i => $token) {
+                if ('text' === $token[0]) {
+                    $regex .= str_repeat(' ', $indent * 4).preg_quote($token[1], '#')."\n";
+                } else {
+                    if ($i >= $firstOptional) {
+                        $regex .= str_repeat(' ', $indent * 4)."(?:\n";
+                        ++$indent;
+                    }
+                    $regex .= str_repeat(' ', $indent * 4).sprintf("%s(?P<%s>%s)\n", preg_quote($token[1], '#'), $token[3], $token[2]);
                 }
-                $regex .= str_repeat(' ', $indent * 4).sprintf("%s(?P<%s>%s)\n", preg_quote($token[1], '#'), $token[3], $token[2]);
             }
         }
         while (--$indent) {

+ 13 - 0
tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php

@@ -96,6 +96,19 @@ class UrlMatcherTest extends \PHPUnit_Framework_TestCase
         $this->assertInternalType('array', $matcher->match('/foo'));
         $matcher = new UrlMatcher($collection, new RequestContext('', 'head'), array());
         $this->assertInternalType('array', $matcher->match('/foo'));
+
+        // route with an optional variable as the first segment
+        $collection = new RouteCollection();
+        $collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar')));
+        $matcher = new UrlMatcher($collection, new RequestContext(), array());
+        $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo'));
+        $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo'));
+
+        $collection = new RouteCollection();
+        $collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar')));
+        $matcher = new UrlMatcher($collection, new RequestContext(), array());
+        $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo'));
+        $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/'));
     }
 
     public function testMatchRegression()

+ 14 - 0
tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php

@@ -82,6 +82,20 @@ class RouteCompilerTest extends \PHPUnit_Framework_TestCase
                     array('variable', '/', '[^/]*?', 'bar'),
                     array('text', '/foo'),
                 )),
+
+            array(
+                'Route with an optional variable as the first segment',
+                array('/{bar}', array('bar' => 'bar')),
+                '', '#^/(?:(?P<bar>[^/]*?))?$#x', array('bar'), array(
+                    array('variable', '/', '[^/]*?', 'bar'),
+                )),
+
+            array(
+                'Route with an optional variable as the first segment with requirements',
+                array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
+                '', '#^/(?:(?P<bar>(foo|bar)))?$#x', array('bar'), array(
+                    array('variable', '/', '(foo|bar)', 'bar'),
+                )),
         );
     }
 }