[Routing] adds _fragment special option to url generation for document fragment
This commit is contained in:
parent
fa01e848d0
commit
6d79a565e0
@ -257,14 +257,24 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
$url = $schemeAuthority.$this->context->getBaseUrl().$url;
|
$url = $schemeAuthority.$this->context->getBaseUrl().$url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a query string if needed
|
// extract unused parameters
|
||||||
$extra = array_diff_key($parameters, $variables, $defaults);
|
$extra = array_diff_key($parameters, $variables, $defaults);
|
||||||
|
|
||||||
|
// extract fragment
|
||||||
|
$fragment = isset($extra['_fragment']) ? $extra['_fragment'] : '';
|
||||||
|
unset($extra['_fragment']);
|
||||||
|
|
||||||
|
// add a query string if needed
|
||||||
if ($extra && $query = http_build_query($extra, '', '&')) {
|
if ($extra && $query = http_build_query($extra, '', '&')) {
|
||||||
// "/" and "?" can be left decoded for better user experience, see
|
// "/" and "?" can be left decoded for better user experience, see
|
||||||
// http://tools.ietf.org/html/rfc3986#section-3.4
|
// http://tools.ietf.org/html/rfc3986#section-3.4
|
||||||
$url .= '?'.strtr($query, array('%2F' => '/'));
|
$url .= '?'.strtr($query, array('%2F' => '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('' !== $fragment) {
|
||||||
|
$url .= '#'.strtr(rawurlencode($fragment), array('%2F' => '/', '%3F' => '?'));
|
||||||
|
}
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,6 +69,8 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
|
|||||||
*
|
*
|
||||||
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
|
* If there is no route with the given name, the generator must throw the RouteNotFoundException.
|
||||||
*
|
*
|
||||||
|
* The special parameter _fragment will be used as the document fragment suffixed to the final URL.
|
||||||
|
*
|
||||||
* @param string $name The name of the route
|
* @param string $name The name of the route
|
||||||
* @param mixed $parameters An array of parameters
|
* @param mixed $parameters An array of parameters
|
||||||
* @param int $referenceType The type of reference to be generated (one of the constants)
|
* @param int $referenceType The type of reference to be generated (one of the constants)
|
||||||
|
@ -31,6 +31,7 @@ class RouteCompiler implements RouteCompilerInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*
|
*
|
||||||
|
* @throws \InvalidArgumentException If a path variable is named _fragment
|
||||||
* @throws \LogicException If a variable is referenced more than once
|
* @throws \LogicException If a variable is referenced more than once
|
||||||
* @throws \DomainException If a variable name is numeric because PHP raises an error for such
|
* @throws \DomainException If a variable name is numeric because PHP raises an error for such
|
||||||
* subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
|
* subpatterns in PCRE and thus would break matching, e.g. "(?P<123>.+)".
|
||||||
@ -59,6 +60,13 @@ class RouteCompiler implements RouteCompilerInterface
|
|||||||
$staticPrefix = $result['staticPrefix'];
|
$staticPrefix = $result['staticPrefix'];
|
||||||
|
|
||||||
$pathVariables = $result['variables'];
|
$pathVariables = $result['variables'];
|
||||||
|
|
||||||
|
foreach ($pathVariables as $pathParam) {
|
||||||
|
if ('_fragment' === $pathParam) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('Route pattern "%s" cannot contain "_fragment" as a path parameter.', $route->getPath()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$variables = array_merge($variables, $pathVariables);
|
$variables = array_merge($variables, $pathVariables);
|
||||||
|
|
||||||
$tokens = $result['tokens'];
|
$tokens = $result['tokens'];
|
||||||
|
@ -622,6 +622,25 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testFragmentsCanBeAppendedToUrls()
|
||||||
|
{
|
||||||
|
$routes = $this->getRoutes('test', new Route('/testing'));
|
||||||
|
|
||||||
|
$url = $this->getGenerator($routes)->generate('test', array('_fragment' => 'frag ment'), true);
|
||||||
|
$this->assertEquals('/app.php/testing#frag%20ment', $url);
|
||||||
|
|
||||||
|
$url = $this->getGenerator($routes)->generate('test', array('_fragment' => '0'), true);
|
||||||
|
$this->assertEquals('/app.php/testing#0', $url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testFragmentsDoNotEscapeValidCharacters()
|
||||||
|
{
|
||||||
|
$routes = $this->getRoutes('test', new Route('/testing'));
|
||||||
|
$url = $this->getGenerator($routes)->generate('test', array('_fragment' => '?/'), true);
|
||||||
|
|
||||||
|
$this->assertEquals('/app.php/testing#?/', $url);
|
||||||
|
}
|
||||||
|
|
||||||
protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
|
protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
|
||||||
{
|
{
|
||||||
$context = new RequestContext('/app.php');
|
$context = new RequestContext('/app.php');
|
||||||
|
@ -175,6 +175,16 @@ class RouteCompilerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$compiled = $route->compile();
|
$compiled = $route->compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function testRouteWithFragmentAsPathParameter()
|
||||||
|
{
|
||||||
|
$route = new Route('/{_fragment}');
|
||||||
|
|
||||||
|
$compiled = $route->compile();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getNumericVariableNames
|
* @dataProvider getNumericVariableNames
|
||||||
* @expectedException \DomainException
|
* @expectedException \DomainException
|
||||||
|
Reference in New Issue
Block a user