From 9aa09e1ff59843ad7aa35d63b9294ae4ed7318fa Mon Sep 17 00:00:00 2001 From: Nasim Date: Thu, 14 Jun 2018 10:55:32 +0200 Subject: [PATCH] [Routing] fix URL generation with look-around requirements --- .../Routing/Generator/UrlGenerator.php | 24 ++++++++++++++++--- .../Tests/Generator/UrlGeneratorTest.php | 24 +++++++++++++++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 6ed70cabdfc21..54ae73ccd41fe 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -140,14 +140,18 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa foreach ($tokens as $token) { if ('variable' === $token[0]) { if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) { + $variablePattern = $token[2]; + if ($this->hasLookAround($token[2])) { + $variablePattern = $this->removeLookAround($token[2]); + } // check requirement - if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) { + if (null !== $this->strictRequirements && !preg_match('#^'.$variablePattern.'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) { if ($this->strictRequirements) { - throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]]))); + throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $variablePattern, '{given}' => $mergedParams[$token[3]]))); } if ($this->logger) { - $this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]])); + $this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $variablePattern, 'given' => $mergedParams[$token[3]])); } return; @@ -318,4 +322,18 @@ public static function getRelativePath($basePath, $targetPath) || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos) ? "./$path" : $path; } + + private function hasLookAround($path) + { + if (false === $i = strpos($path, '(?')) { + return false; + } + + return false !== strpos($path, '(?=', $i) || false !== strpos($path, '(?<=', $i) || false !== strpos($path, '(?!', $i) || false !== strpos($path, '(?assertEquals('/app.php/testing#fragment', $url); } + public function testLookAheadPositiveInRequirements() + { + $routes = $this->getRoutes('test', new Route('/{foo}/b(ar/{baz}', array(), array('foo' => '.+(?=/b\\(ar/)', 'baz' => '.+?'))); + $this->assertSame('/app.php/a/b/b%28ar/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e'))); + } + + public function testLookAheadNegativeInRequirementss() + { + $routes = $this->getRoutes('test', new Route('/{foo}/bar/{baz}', array(), array('foo' => '.+(?!$)', 'baz' => '.+?'))); + $this->assertSame('/app.php/a/b/bar/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e'))); + } + + public function testLookBehindPositiveInRequirements() + { + $routes = $this->getRoutes('test', new Route('/bar/{foo}/bam/{baz}', array(), array('foo' => '(?<=/bar/).+', 'baz' => '.+?'))); + $this->assertSame('/app.php/bar/a/b/bam/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e'))); + } + + public function testLookBehindNegativeInRequirements() + { + $routes = $this->getRoutes('test', new Route('/bar/{foo}/bam/{baz}', array(), array('foo' => '(? '.+?'))); + $this->assertSame('/app.php/bar/a/b/bam/c/d/e', $this->getGenerator($routes)->generate('test', array('foo' => 'a/b', 'baz' => 'c/d/e'))); + } + protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null) { $context = new RequestContext('/app.php');