8000 [Routing] adds _fragment special option to url generation for documen… · symfony/symfony@5f00a59 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5f00a59

Browse files
committed
[Routing] adds _fragment special option to url generation for document fragment
1 parent 99de3fd commit 5f00a59

File tree

5 files changed

+53
-4
lines changed

5 files changed

+53
-4
lines changed

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,24 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa
268268
$url = $schemeAuthority.$this->context->getBaseUrl().$url;
269269
}
270270

271-
// add a query string if needed
271+
// extract unused parameters
272272
$extra = array_diff_key($parameters, $variables, $defaults);
273+
274+
// extract fragment
275+
$fragment = isset($extra['_fragment']) ? $extra['_fragment'] : false;
276+
unset($extra['_fragment']);
277+
278+
// add a query string if needed
273279
if ($extra && $query = http_build_query($extra, '', '&')) {
274280
// "/" and "?" can be left decoded for better user experience, see
275281
// http://tools.ietf.org/html/rfc3986#section-3.4
276282
$url .= '?'.strtr($query, array('%2F' => '/'));
277283
}
278284

285+
if (strlen($fragment)) {
286+
$url .= '#'.strtr(rawurlencode($fragment), array('%2F' => '/', '%3F' => '?'));
287+
}
288+
279289
return $url;
280290
}
281291

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
6969
*
7070
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
7171
*
72+
* The special parameter _fragment will be used as the document fragment suffixed to the final URL.
73+
*
7274
* @param string $name The name of the route
7375
* @param mixed $parameters An array of parameters
7476
* @param bool|string $referenceType The type of reference to be generated (one of the constants)

src/Symfony/Component/Routing/RouteCompiler.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ class RouteCompiler implements RouteCompilerInterface
3131
/**
3232
* {@inheritdoc}
3333
*
34-
* @throws \LogicException If a variable is referenced more than once
35-
* @throws \DomainException If a variable name is numeric because PHP raises an error for such
36-
* subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
34+
* @throws \InvalidArgumentException If a path variable is named _fragment
35+
* @throws \LogicException If a variable is referenced more than once
36+
* @throws \DomainException If a variable name is numeric because PHP raises an error for such
37+
* subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
3738
*/
3839
public static function compile(Route $route)
3940
{
@@ -59,6 +60,13 @@ public static function compile(Route $route)
5960
$staticPrefix = $result['staticPrefix'];
6061

6162
$pathVariables = $result['variables'];
63+
64+
foreach ($pathVariables as $pathParam) {
65+
if ('_fragment' === $pathParam) {
66+
throw new \InvalidArgumentException(sprintf('Route pattern "%s" cannot contain "_fragment" as a path parameter.', $route->getPath()));
67+
}
68+
}
69+
6270
$variables = array_merge($variables, $pathVariables);
6371

6472
$tokens = $result['tokens'];

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,25 @@ public function provideRelativePaths()
622622
);
623623
}
624624

625+
public function testFragmentsCanBeAppendedToUrls()
626+
{
627+
$routes = $this->getRoutes('test', new Route('/testing'));
628+
629+
$url = $this->getGenerator($routes)->generate('test', array('_fragment' => 'frag ment'), true);
630+
$this->assertEquals('http://localhost/app.php/testing#frag%20ment', $url);
631+
632+
$url = $this->getGenerator($routes)->generate('test', array('_fragment' => '0'), true);
633+
$this->assertEquals('http://localhost/app.php/testing#0', $url);
634+
}
635+
636+
public function testFragmentsDoNotEscapeValidCharacters()
637+
{
638+
$routes = $this->getRoutes('test', new Route('/testing'));
639+
$url = $this->getGenerator($routes)->generate('test', array('_fragment' => '?/'), true);
640+
641+
$this->assertEquals('http://localhost/app.php/testing#?/', $url);
642+
}
643+
625644
protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
626645
{
627646
$context = new RequestContext('/app.php');

src/Symfony/Component/Routing/Tests/RouteCompilerTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ public function testRouteWithSameVariableTwice()
161161
$compiled = $route->compile();
162162
}
163163

164+
/**
165+
* @expectedException \InvalidArgumentException
166+
*/
167+
public function testRouteWithFragmentAsPathParameter()
168+
{
169+
$route = new Route('/{_fragment}');
170+
171+
$compiled = $route->compile();
172+
}
173+
164174
/**
165175
* @dataProvider getNumericVariableNames
166176
* @expectedException \DomainException

0 commit comments

Comments
 (0)
0