[Routing] remove capturing groups from requirements, they break the merged regex
This commit is contained in:
parent
3e999880ed
commit
8444022426
@ -180,6 +180,7 @@ class RouteCompiler implements RouteCompilerInterface
|
|||||||
if (!$useUtf8 && $needsUtf8) {
|
if (!$useUtf8 && $needsUtf8) {
|
||||||
throw new \LogicException(sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".', $varName, $pattern));
|
throw new \LogicException(sprintf('Cannot mix UTF-8 requirement with non-UTF-8 charset for variable "%s" in pattern "%s".', $varName, $pattern));
|
||||||
}
|
}
|
||||||
|
$regexp = self::transformCapturingGroupsToNonCapturings($regexp);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName);
|
$tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName);
|
||||||
@ -247,7 +248,7 @@ class RouteCompiler implements RouteCompilerInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next static character in the Route pattern that will serve as a separator (or the empty string when none available)
|
* Returns the next static character in the Route pattern that will serve as a separator (or the empty string when none available).
|
||||||
*/
|
*/
|
||||||
private static function findNextSeparator(string $pattern, bool $useUtf8): string
|
private static function findNextSeparator(string $pattern, bool $useUtf8): string
|
||||||
{
|
{
|
||||||
@ -304,4 +305,25 @@ class RouteCompiler implements RouteCompilerInterface
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function transformCapturingGroupsToNonCapturings(string $regexp): string
|
||||||
|
{
|
||||||
|
for ($i = 0; $i < \strlen($regexp); ++$i) {
|
||||||
|
if ('\\' === $regexp[$i]) {
|
||||||
|
++$i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('(' !== $regexp[$i] || !isset($regexp[$i + 2])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('*' === $regexp[++$i] || '?' === $regexp[$i]) {
|
||||||
|
++$i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$regexp = substr_replace($regexp, '?:', $i, 0);
|
||||||
|
$i += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $regexp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -587,6 +587,15 @@ class UrlMatcherTest extends TestCase
|
|||||||
$this->assertEquals(array('_route' => 'b', 'a' => 'é'), $matcher->match('/é'));
|
$this->assertEquals(array('_route' => 'b', 'a' => 'é'), $matcher->match('/é'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRequirementWithCapturingGroup()
|
||||||
|
{
|
||||||
|
$coll = new RouteCollection();
|
||||||
|
$coll->add('a', new Route('/{a}/{b}', array(), array('a' => '(a|b)')));
|
||||||
|
|
||||||
|
$matcher = $this->getUrlMatcher($coll);
|
||||||
|
$this->assertEquals(array('_route' => 'a', 'a' => 'a', 'b' => 'b'), $matcher->match('/a/b'));
|
||||||
|
}
|
||||||
|
|
||||||
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
|
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
|
||||||
{
|
{
|
||||||
return new UrlMatcher($routes, $context ?: new RequestContext());
|
return new UrlMatcher($routes, $context ?: new RequestContext());
|
||||||
|
@ -110,8 +110,8 @@ class RouteCompilerTest extends TestCase
|
|||||||
array(
|
array(
|
||||||
'Route with an optional variable as the first segment with requirements',
|
'Route with an optional variable as the first segment with requirements',
|
||||||
array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
|
array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
|
||||||
'', '#^/(?P<bar>(foo|bar))?$#sD', array('bar'), array(
|
'', '#^/(?P<bar>(?:foo|bar))?$#sD', array('bar'), array(
|
||||||
array('variable', '/', '(foo|bar)', 'bar'),
|
array('variable', '/', '(?:foo|bar)', 'bar'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -146,10 +146,10 @@ class RouteCompilerTest extends TestCase
|
|||||||
array(
|
array(
|
||||||
'Route without separator between variables',
|
'Route without separator between variables',
|
||||||
array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')),
|
array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')),
|
||||||
'', '#^/(?P<w>[^/\.]+)(?P<x>[^/\.]+)(?P<y>(y|Y))(?:(?P<z>[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#sD', array('w', 'x', 'y', 'z', '_format'), array(
|
'', '#^/(?P<w>[^/\.]+)(?P<x>[^/\.]+)(?P<y>(?:y|Y))(?:(?P<z>[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#sD', array('w', 'x', 'y', 'z', '_format'), array(
|
||||||
array('variable', '.', '[^/]++', '_format'),
|
array('variable', '.', '[^/]++', '_format'),
|
||||||
array('variable', '', '[^/\.]++', 'z'),
|
array('variable', '', '[^/\.]++', 'z'),
|
||||||
array('variable', '', '(y|Y)', 'y'),
|
array('variable', '', '(?:y|Y)', 'y'),
|
||||||
array('variable', '', '[^/\.]+', 'x'),
|
array('variable', '', '[^/\.]+', 'x'),
|
||||||
array('variable', '/', '[^/\.]+', 'w'),
|
array('variable', '/', '[^/\.]+', 'w'),
|
||||||
),
|
),
|
||||||
@ -380,6 +380,25 @@ class RouteCompilerTest extends TestCase
|
|||||||
$route = new Route(sprintf('/{%s}', str_repeat('a', RouteCompiler::VARIABLE_MAXIMUM_LENGTH + 1)));
|
$route = new Route(sprintf('/{%s}', str_repeat('a', RouteCompiler::VARIABLE_MAXIMUM_LENGTH + 1)));
|
||||||
$route->compile();
|
$route->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideRemoveCapturingGroup
|
||||||
|
*/
|
||||||
|
public function testRemoveCapturingGroup($regex, $requirement)
|
||||||
|
{
|
||||||
|
$route = new Route('/{foo}', array(), array('foo' => $requirement));
|
||||||
|
|
||||||
|
$this->assertSame($regex, $route->compile()->getRegex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideRemoveCapturingGroup()
|
||||||
|
{
|
||||||
|
yield array('#^/(?P<foo>a(?:b|c)(?:d|e)f)$#sD', 'a(b|c)(d|e)f');
|
||||||
|
yield array('#^/(?P<foo>a\(b\)c)$#sD', 'a\(b\)c');
|
||||||
|
yield array('#^/(?P<foo>(?:b))$#sD', '(?:b)');
|
||||||
|
yield array('#^/(?P<foo>(?(b)b))$#sD', '(?(b)b)');
|
||||||
|
yield array('#^/(?P<foo>(*F))$#sD', '(*F)');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Utf8RouteCompiler extends RouteCompiler
|
class Utf8RouteCompiler extends RouteCompiler
|
||||||
|
Reference in New Issue
Block a user