diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index 5cebd224f76b8..52893c373cac4 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -37,7 +37,6 @@ 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]; @@ -45,9 +44,10 @@ public function compile(Route $route) $regexp = $req; } else { if ($pos !== $len) { - $seps[] = $pattern[$pos]; + $regexp = sprintf('[^%s]+', preg_quote($pattern[$pos], '#')); + } else { + $regexp = '[^/]+'; } - $regexp = sprintf('[^%s]+?', preg_quote(implode('', array_unique($seps)), '#')); } $tokens[] = array('variable', $match[0][0][0], $regexp, $var); diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache index 9f4a7b49f4486..7b18437b8b02a 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.apache +++ b/tests/Symfony/Tests/Component/Routing/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,18 +35,18 @@ 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} !^(POST)$ [NC] RewriteRule .* - [S=2,E=_ROUTING__allow_POST: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] # baz6 diff --git a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php index 7932944a34506..b7b7b41d5a465 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher1.php +++ b/tests/Symfony/Tests/Component/Routing/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/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php b/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php index d0f1e31381804..e1de4348c44c9 100644 --- a/tests/Symfony/Tests/Component/Routing/Fixtures/dumper/url_matcher2.php +++ b/tests/Symfony/Tests/Component/Routing/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; @@ -94,7 +94,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; @@ -121,25 +121,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; } @@ -157,7 +157,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; } @@ -165,13 +165,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/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php b/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php index 8acff1686d7b3..e04328212f31d 100644 --- a/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php +++ b/tests/Symfony/Tests/Component/Routing/Matcher/UrlMatcherTest.php @@ -205,4 +205,15 @@ public function testMatchRegression() } catch (ResourceNotFoundException $e) { } } + + 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/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php b/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php index 08120e7848fa4..1c17b2b4edb75 100644 --- a/tests/Symfony/Tests/Component/Routing/RouteCompilerTest.php +++ b/tests/Symfony/Tests/Component/Routing/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'), + )), ); }