[Routing] fix trailing slash redirection when using RedirectableUrlMatcher

This commit is contained in:
Nicolas Grekas 2018-11-22 18:32:47 +01:00
parent f747ea90a3
commit dc4c3f6927
2 changed files with 35 additions and 3 deletions

View File

@ -118,16 +118,37 @@ class UrlMatcher implements UrlMatcherInterface, RequestMatcherInterface
*/
protected function matchCollection($pathinfo, RouteCollection $routes)
{
$supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;
foreach ($routes as $name => $route) {
$compiledRoute = $route->compile();
$staticPrefix = $compiledRoute->getStaticPrefix();
// check the static prefix of the URL first. Only use the more expensive preg_match when it matches
if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
// no-op
} elseif (!$supportsTrailingSlash) {
continue;
} elseif ('/' === substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) {
return;
} else {
continue;
}
$regex = $compiledRoute->getRegex();
if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
$regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
$hasTrailingSlash = true;
} else {
$hasTrailingSlash = false;
}
if (!preg_match($regex, $pathinfo, $matches)) {
continue;
}
if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
continue;
if ($hasTrailingSlash && '/' !== substr($pathinfo, -1)) {
return;
}
$hostMatches = array();

View File

@ -117,6 +117,17 @@ class RedirectableUrlMatcherTest extends UrlMatcherTest
$this->assertSame(array('_route' => 'foo'), $matcher->match('/foo'));
}
public function testFallbackPage()
{
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo/'));
$coll->add('bar', new Route('/{name}'));
$matcher = $this->getUrlMatcher($coll);
$matcher->expects($this->once())->method('redirect')->with('/foo/')->will($this->returnValue(array('_route' => 'foo')));
$this->assertSame(array('_route' => 'foo'), $matcher->match('/foo'));
}
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($routes, $context ?: new RequestContext()));