diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index 5cebd224f76b8..9a70e271a3ea4 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -37,17 +37,13 @@ public function compile(Route $route) if ($text = substr($pattern, $pos, $match[0][1] - $pos)) { $tokens[] = array('text', $text); } - $seps = array($pattern[$pos]); $pos = $match[0][1] + strlen($match[0][0]); $var = $match[1][0]; if ($req = $route->getRequirement($var)) { $regexp = $req; } else { - if ($pos !== $len) { - $seps[] = $pattern[$pos]; - } - $regexp = sprintf('[^%s]+?', preg_quote(implode('', array_unique($seps)), '#')); + $regexp = $pos === $len ? '.+' : sprintf('[^%s]+', preg_quote($pattern[$pos], '#')); } $tokens[] = array('variable', $match[0][0][0], $regexp, $var); diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache index c840a7346807b..29a9e37b66aff 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.apache @@ -7,17 +7,17 @@ RewriteCond %{REQUEST_URI} ^/foo/(baz|symfony)$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:foo,E=_ROUTING_bar:%1,E=_ROUTING_def:test] # bar -RewriteCond %{REQUEST_URI} ^/bar/([^/]+?)$ +RewriteCond %{REQUEST_URI} ^/bar/(.+)$ RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC] RewriteRule .* - [S=1,E=_ROUTING__allow_GET:1,E=_ROUTING__allow_HEAD:1] -RewriteCond %{REQUEST_URI} ^/bar/([^/]+?)$ +RewriteCond %{REQUEST_URI} ^/bar/(.+)$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:bar,E=_ROUTING_foo:%1] # baragain -RewriteCond %{REQUEST_URI} ^/baragain/([^/]+?)$ +RewriteCond %{REQUEST_URI} ^/baragain/(.+)$ RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD)$ [NC] RewriteRule .* - [S=1,E=_ROUTING__allow_GET:1,E=_ROUTING__allow_POST:1,E=_ROUTING__allow_HEAD:1] -RewriteCond %{REQUEST_URI} ^/baragain/([^/]+?)$ +RewriteCond %{REQUEST_URI} ^/baragain/(.+)$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baragain,E=_ROUTING_foo:%1] # baz @@ -35,25 +35,25 @@ RewriteCond %{REQUEST_URI} ^/test/baz3/$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz3] # baz4 -RewriteCond %{REQUEST_URI} ^/test/([^/]+?)$ +RewriteCond %{REQUEST_URI} ^/test/([^/]+)$ RewriteRule .* $0/ [QSA,L,R=301] -RewriteCond %{REQUEST_URI} ^/test/([^/]+?)/$ +RewriteCond %{REQUEST_URI} ^/test/([^/]+)/$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz4,E=_ROUTING_foo:%1] # baz5 -RewriteCond %{REQUEST_URI} ^/test/([^/]+?)/$ +RewriteCond %{REQUEST_URI} ^/test/([^/]+)/$ RewriteCond %{REQUEST_METHOD} !^(GET|HEAD)$ [NC] RewriteRule .* - [S=2,E=_ROUTING__allow_GET:1,E=_ROUTING__allow_HEAD:1] -RewriteCond %{REQUEST_URI} ^/test/([^/]+?)$ +RewriteCond %{REQUEST_URI} ^/test/([^/]+)$ RewriteRule .* $0/ [QSA,L,R=301] -RewriteCond %{REQUEST_URI} ^/test/([^/]+?)/$ +RewriteCond %{REQUEST_URI} ^/test/([^/]+)/$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz5,E=_ROUTING_foo:%1] # baz5unsafe -RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+?)/$ +RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+)/$ RewriteCond %{REQUEST_METHOD} !^(POST)$ [NC] RewriteRule .* - [S=1,E=_ROUTING__allow_POST:1] -RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+?)/$ +RewriteCond %{REQUEST_URI} ^/testunsafe/([^/]+)/$ RewriteRule .* app.php [QSA,L,E=_ROUTING__route:baz5unsafe,E=_ROUTING_foo:%1] # baz6 diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php index 7932944a34506..b0b6f0a82e85d 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php @@ -31,7 +31,7 @@ public function match($pathinfo) } // bar - if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?P.+)$#xs', $pathinfo, $matches)) { if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) { $allow = array_merge($allow, array('GET', 'HEAD')); goto not_bar; @@ -42,7 +42,7 @@ public function match($pathinfo) not_bar: // barhead - if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P.+)$#xs', $pathinfo, $matches)) { if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) { $allow = array_merge($allow, array('GET', 'HEAD')); goto not_barhead; @@ -68,13 +68,13 @@ public function match($pathinfo) } // baz4 - if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+?)/$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+)/$#xs', $pathinfo, $matches)) { $matches['_route'] = 'baz4'; return $matches; } // baz5 - if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+?)/$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+)/$#xs', $pathinfo, $matches)) { if ($this->context->getMethod() != 'POST') { $allow[] = 'POST'; goto not_baz5; @@ -85,7 +85,7 @@ public function match($pathinfo) not_baz5: // baz.baz6 - if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+?)/$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+)/$#xs', $pathinfo, $matches)) { if ($this->context->getMethod() != 'PUT') { $allow[] = 'PUT'; goto not_bazbaz6; @@ -109,25 +109,25 @@ public function match($pathinfo) if (0 === strpos($pathinfo, '/a')) { if (0 === strpos($pathinfo, '/a/b\'b')) { // foo1 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo1'; return $matches; } // bar1 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'bar1'; return $matches; } // foo2 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo2'; return $matches; } // bar2 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'bar2'; return $matches; } @@ -145,7 +145,7 @@ public function match($pathinfo) } // foo4 - if (preg_match('#^/aba/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/aba/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo4'; return $matches; } @@ -153,13 +153,13 @@ public function match($pathinfo) } // foo3 - if (preg_match('#^/(?P<_locale>[^/]+?)/b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/(?P<_locale>[^/]+)/b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo3'; return $matches; } // bar3 - if (preg_match('#^/(?P<_locale>[^/]+?)/b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/(?P<_locale>[^/]+)/b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'bar3'; return $matches; } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php index b438ba243e2dd..9cd481a55bda7 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php @@ -31,7 +31,7 @@ public function match($pathinfo) } // bar - if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/bar') && preg_match('#^/bar/(?P.+)$#xs', $pathinfo, $matches)) { if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) { $allow = array_merge($allow, array('GET', 'HEAD')); goto not_bar; @@ -42,7 +42,7 @@ public function match($pathinfo) not_bar: // barhead - if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/barhead') && preg_match('#^/barhead/(?P.+)$#xs', $pathinfo, $matches)) { if (!in_array($this->context->getMethod(), array('GET', 'HEAD'))) { $allow = array_merge($allow, array('GET', 'HEAD')); goto not_barhead; @@ -71,7 +71,7 @@ public function match($pathinfo) } // baz4 - if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+?)/?$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+)/?$#xs', $pathinfo, $matches)) { if (substr($pathinfo, -1) !== '/') { return $this->redirect($pathinfo.'/', 'baz4'); } @@ -80,7 +80,7 @@ public function match($pathinfo) } // baz5 - if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+?)/$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+)/$#xs', $pathinfo, $matches)) { if ($this->context->getMethod() != 'POST') { $allow[] = 'POST'; goto not_baz5; @@ -91,7 +91,7 @@ public function match($pathinfo) not_baz5: // baz.baz6 - if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+?)/$#xs', $pathinfo, $matches)) { + if (0 === strpos($pathinfo, '/test') && preg_match('#^/test/(?P[^/]+)/$#xs', $pathinfo, $matches)) { if ($this->context->getMethod() != 'PUT') { $allow[] = 'PUT'; goto not_bazbaz6; @@ -115,25 +115,25 @@ public function match($pathinfo) if (0 === strpos($pathinfo, '/a')) { if (0 === strpos($pathinfo, '/a/b\'b')) { // foo1 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo1'; return $matches; } // bar1 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'bar1'; return $matches; } // foo2 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo2'; return $matches; } // bar2 - if (preg_match('#^/a/b\'b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/a/b\'b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'bar2'; return $matches; } @@ -151,7 +151,7 @@ public function match($pathinfo) } // foo4 - if (preg_match('#^/aba/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/aba/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo4'; return $matches; } @@ -159,13 +159,13 @@ public function match($pathinfo) } // foo3 - if (preg_match('#^/(?P<_locale>[^/]+?)/b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/(?P<_locale>[^/]+)/b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'foo3'; return $matches; } // bar3 - if (preg_match('#^/(?P<_locale>[^/]+?)/b/(?P[^/]+?)$#xs', $pathinfo, $matches)) { + if (preg_match('#^/(?P<_locale>[^/]+)/b/(?P.+)$#xs', $pathinfo, $matches)) { $matches['_route'] = 'bar3'; return $matches; } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 14db7171cbaa3..3c1fb89693679 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -187,14 +187,14 @@ public function testMatchOverridenRoute() $this->assertEquals(array(), $matcher->match('/foo')); } - public function testMatchRegression() + public function testMatchWhenNoSepatorSpecified() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}')); $coll->add('bar', new Route('/foo/bar/{foo}')); $matcher = new UrlMatcher($coll, new RequestContext()); - $this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar')); + $this->assertEquals(array('foo' => 'bar/bar', '_route' => 'foo'), $matcher->match('/foo/bar/bar')); $collection = new RouteCollection(); $collection->add('foo', new Route('/{bar}')); @@ -216,4 +216,15 @@ public function testSchemeRequirement() $matcher = new UrlMatcher($coll, new RequestContext()); $matcher->match('/foo'); } + + public function testSeparators() + { + $coll = new RouteCollection(); + $coll->add('foo', new Route('/foo-{bar}-{baz}')); + $matcher = new UrlMatcher($coll, new RequestContext()); + $this->assertEquals( + array('bar' => 'b/ar', 'baz' => 'b-az', '_route' => 'foo'), + $matcher->match('/foo-b/ar-b-az') + ); + } } diff --git a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php index 6f1f639061519..43b84616bd81f 100644 --- a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php @@ -43,51 +43,51 @@ public function provideCompileData() array( 'Route with a variable', array('/foo/{bar}'), - '/foo', '#^/foo/(?P[^/]+?)$#xs', array('bar'), array( - array('variable', '/', '[^/]+?', 'bar'), + '/foo', '#^/foo/(?P.+)$#xs', array('bar'), array( + array('variable', '/', '.+', 'bar'), array('text', '/foo'), )), array( 'Route with a variable that has a default value', array('/foo/{bar}', array('bar' => 'bar')), - '/foo', '#^/foo(?:/(?P[^/]+?))?$#xs', array('bar'), array( - array('variable', '/', '[^/]+?', 'bar'), + '/foo', '#^/foo(?:/(?P.+))?$#xs', array('bar'), array( + array('variable', '/', '.+', 'bar'), array('text', '/foo'), )), array( 'Route with several variables', array('/foo/{bar}/{foobar}'), - '/foo', '#^/foo/(?P[^/]+?)/(?P[^/]+?)$#xs', array('bar', 'foobar'), array( - array('variable', '/', '[^/]+?', 'foobar'), - array('variable', '/', '[^/]+?', 'bar'), + '/foo', '#^/foo/(?P[^/]+)/(?P.+)$#xs', array('bar', 'foobar'), array( + array('variable', '/', '.+', 'foobar'), + array('variable', '/', '[^/]+', 'bar'), array('text', '/foo'), )), array( 'Route with several variables that have default values', array('/foo/{bar}/{foobar}', array('bar' => 'bar', 'foobar' => '')), - '/foo', '#^/foo(?:/(?P[^/]+?)(?:/(?P[^/]+?))?)?$#xs', array('bar', 'foobar'), array( - array('variable', '/', '[^/]+?', 'foobar'), - array('variable', '/', '[^/]+?', 'bar'), + '/foo', '#^/foo(?:/(?P[^/]+)(?:/(?P.+))?)?$#xs', array('bar', 'foobar'), array( + array('variable', '/', '.+', 'foobar'), + array('variable', '/', '[^/]+', 'bar'), array('text', '/foo'), )), array( 'Route with several variables but some of them have no default values', array('/foo/{bar}/{foobar}', array('bar' => 'bar')), - '/foo', '#^/foo/(?P[^/]+?)/(?P[^/]+?)$#xs', array('bar', 'foobar'), array( - array('variable', '/', '[^/]+?', 'foobar'), - array('variable', '/', '[^/]+?', 'bar'), + '/foo', '#^/foo/(?P[^/]+)/(?P.+)$#xs', array('bar', 'foobar'), array( + array('variable', '/', '.+', 'foobar'), + array('variable', '/', '[^/]+', 'bar'), array('text', '/foo'), )), array( 'Route with an optional variable as the first segment', array('/{bar}', array('bar' => 'bar')), - '', '#^/(?:(?P[^/]+?))?$#xs', array('bar'), array( - array('variable', '/', '[^/]+?', 'bar'), + '', '#^/(?:(?P.+))?$#xs', array('bar'), array( + array('variable', '/', '.+', 'bar'), )), array( @@ -96,6 +96,15 @@ public function provideCompileData() '', '#^/(?:(?P(foo|bar)))?$#xs', array('bar'), array( array('variable', '/', '(foo|bar)', 'bar'), )), + + array( + 'Route with different separators', + array('/foo-{bar}-{baz}'), + '/foo', '#^/foo\-(?P[^\-]+)\-(?P.+)$#xs', array('bar', 'baz'), array( + array('variable', '-', '.+', 'baz'), + array('variable', '-', '[^\-]+', 'bar'), + array('text', '/foo'), + )), ); }