8000 [Routing] fix URL generation with look-around requirements · symfony/symfony@9aa09e1 · GitHub
[go: up one dir, main page]

Skip to content
Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9aa09e1

Browse files
nasimnabavinicolas-grekas
authored andcommitted
[Routing] fix URL generation with look-around requirements
1 parent 7f310b4 commit 9aa09e1

File tree

2 files changed

+45
-3
lines changed

2 files changed

+45
-3
lines changed

src/Symfony/Component/Routing/Generator/UrlGenerator.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,18 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
140140
foreach ($tokens as $token) {
141141
if ('variable' === $token[0]) {
142142
if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
143+
$variablePattern = $token[2];
144+
if ($this->hasLookAround($token[2])) {
145+
$variablePattern = $this->removeLookAround($token[2]);
146+
}
143147
// check requirement
144-
if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) {
148+
if (null !== $this->strictRequirements && !preg_match('#^'.$variablePattern.'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) {
145149
if ($this->strictRequirements) {
146-
throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]])));
150+
throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $variablePattern, '{given}' => $mergedParams[$token[3]])));
147151
}
148152

149153
if ($this->logger) {
150-
$this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]]));
154+
$this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $variablePattern, 'given' => $mergedParams[$token[3]]));
151155
}
152156

153157
return;
@@ -318,4 +322,18 @@ public static function getRelativePath($basePath, $targetPath)
318322
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
319323
? "./$path" : $path;
320324
}
325+
326+
private function hasLookAround($path)
327+
{
328+
if (false === $i = strpos($path, '(?')) {
329+
return false;
330+
}
331+
332+
return false !== strpos($path, '(?=', $i) || false !== strpos($path, '(?<=', $i) || false !== strpos($path, '(?!', $i) || false !== strpos($path, '(?<!', $i);
333+
}
334+
335+
private function removeLookAround($path)
336+
{
337+
return preg_replace('/\(\?(?:=|<=|!|<!)((?:[^()\\\\]+|\\\\.|\((?1)\))*)\)/', '', $path);
338+
}
321339
}

src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,30 @@ public function testFragmentsCanBeDefinedAsDefaults()
703703
$this->assertEquals('/app.php/testing#fragment', $url);
704704
}
705705

706+
public function testLookAheadPositiveInRequirements()
707+
{
708+
$routes = $this->getRoutes('test', new Route('/{foo}/b(ar/{baz}', array(), array('foo' => '.+(?=/b\\(ar/)', 'baz' => '.+?')));
709+
$this->assertSame('/app.php/a/b/b%28ar/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e')));
710+
}
711+
712+
public function testLookAheadNegativeInRequirementss()
713+
{
714+
$routes = $this->getRoutes('test', new Route('/{foo}/bar/{baz}', array(), array('foo' => '.+(?!$)', 'baz' => '.+?')));
715+
$this->assertSame('/app.php/a/b/bar/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e')));
716+
}
717+
718+
public function testLookBehindPositiveInRequirements()
719+
{
720+
$routes = $this->getRoutes('test', new Route('/bar/{foo}/bam/{baz}', array(), array('foo' => '(?<=/bar/).+', 'baz' => '.+?')));
721+
$this->assertSame('/app.php/bar/a/b/bam/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e')));
722+
}
723+
724+
public function testLookBehindNegativeInRequirements()
725+
{
726+
$routes = $this->getRoutes('test', new Route('/bar/{foo}/bam/{baz}', array(), array('foo' => '(?<!^).+', 'baz' => '.+?')));
727+
$this->assertSame('/app.php/bar/a/b/bam/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e')));
728+
}
729+
706730
protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
707731
{
708732
$context = new RequestContext('/app.php');

0 commit comments

Comments
 (0)
0