Skip to content

Navigation Menu

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 9fab3d6

Browse filesBrowse files
luchaninovnicolas-grekas
authored andcommitted
[Routing] Allow force-generation of trailing parameters using eg \"/exports/news.{!_format}\"
1 parent f2590d1 commit 9fab3d6
Copy full SHA for 9fab3d6

File tree

4 files changed

+48
-6
lines changed
Filter options

4 files changed

+48
-6
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Generator/UrlGenerator.php
+10-5Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,26 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
156156
$message = 'Parameter "{parameter}" for route "{route}" must match "{expected}" ("{given}" given) to generate a corresponding URL.';
157157
foreach ($tokens as $token) {
158158
if ('variable' === $token[0]) {
159-
if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
159+
$varName = $token[3];
160+
if ($important = ('!' === $varName[0])) {
161+
$varName = substr($varName, 1);
162+
}
163+
164+
if (!$optional || $important || !array_key_exists($varName, $defaults) || (null !== $mergedParams[$varName] && (string) $mergedParams[$varName] !== (string) $defaults[$varName])) {
160165
// check requirement
161-
if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) {
166+
if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$varName])) {
162167
if ($this->strictRequirements) {
163-
throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]])));
168+
throw new InvalidParameterException(strtr($message, array('{parameter}' => $varName, '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$varName])));
164169
}
165170

166171
if ($this->logger) {
167-
$this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]]));
172+
$this->logger->error($message, array('parameter' => $varName, 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$varName]));
168173
}
169174

170175
return;
171176
}
172177

173-
$url = $token[1].$mergedParams[$token[3]].$url;
178+
$url = $token[1].$mergedParams[$varName].$url;
174179
$optional = false;
175180
}
176181
} else {

‎src/Symfony/Component/Routing/RouteCompiler.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/RouteCompiler.php
+8-1Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private static function compilePattern(Route $route, $pattern, $isHost)
111111

112112
// Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable
113113
// in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself.
114-
preg_match_all('#\{\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
114+
preg_match_all('#\{!?\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
115115
foreach ($matches as $match) {
116116
$varName = substr($match[0][0], 1, -1);
117117
// get all static text preceding the current variable
@@ -184,6 +184,9 @@ private static function compilePattern(Route $route, $pattern, $isHost)
184184
}
185185

186186
$tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName);
187+
if ('!' === $varName[0]) {
188+
$varName = substr($varName, 1);
189+
}
187190
$variables[] = $varName;
188191
}
189192

@@ -283,6 +286,10 @@ private static function computeRegexp(array $tokens, int $index, int $firstOptio
283286
// Text tokens
284287
return preg_quote($token[1], self::REGEX_DELIMITER);
285288
} else {
289+
if ('variable' === $token[0] && '!' === $token[3][0]) {
290+
$token[3] = substr($token[3], 1);
291+
}
292+
286293
// Variable tokens
287294
if (0 === $index && 0 === $firstOptional) {
288295
// When the only token is an optional variable token, the separator is required

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php
+21Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,27 @@ public function testDefaultRequirementOfVariable()
397397
$this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
398398
}
399399

400+
public function testImportantVariable()
401+
{
402+
$routes = $this->getRoutes('test', (new Route('/{page}.{!_format}'))->addDefaults(array('_format' => 'mobile.html')));
403+
$generator = $this->getGenerator($routes);
404+
405+
$this->assertSame('/app.php/index.xml', $generator->generate('test', array('page' => 'index', '_format' => 'xml')));
406+
$this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
407+
$this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index')));
408+
}
409+
410+
/**
411+
* @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
412+
*/
413+
public function testImportantVariableWithNoDefault()
414+
{
415+
$routes = $this->getRoutes('test', new Route('/{page}.{!_format}'));
416+
$generator = $this->getGenerator($routes);
417+
418+
$generator->generate('test', array('page' => 'index'));
419+
}
420+
400421
/**
401422
* @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
402423
*/

‎src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,15 @@ public function testMatchSpecialRouteName()
177177
$this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar'));
178178
}
179179

180+
public function testMatchImportantVariable()
181+
{
182+
$collection = new RouteCollection();
183+
$collection->add('index', new Route('/index.{!_format}', array('_format' => 'xml')));
184+
185+
$matcher = $this->getUrlMatcher($collection);
186+
$this->assertEquals(array('_route' => 'index', '_format' => 'xml'), $matcher->match('/index.xml'));
187+
}
188+
180189
/**
181190
* @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException
182191
*/

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.