[Routing] add support for path-relative and scheme-relative URL generation
This commit is contained in:
parent
18c520a5e8
commit
75f59ebe01
@ -40,14 +40,14 @@ class RoutingExtension extends \Twig_Extension
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPath($name, $parameters = array())
|
public function getPath($name, $parameters = array(), $relative = false)
|
||||||
{
|
{
|
||||||
return $this->generator->generate($name, $parameters, false);
|
return $this->generator->generate($name, $parameters, $relative ? UrlGeneratorInterface::RELATIVE_PATH : UrlGeneratorInterface::ABSOLUTE_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getUrl($name, $parameters = array())
|
public function getUrl($name, $parameters = array(), $schemeRelative = false)
|
||||||
{
|
{
|
||||||
return $this->generator->generate($name, $parameters, true);
|
return $this->generator->generate($name, $parameters, $schemeRelative ? UrlGeneratorInterface::NETWORK_PATH : UrlGeneratorInterface::ABSOLUTE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
@ -19,8 +20,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
|||||||
use Symfony\Component\Form\FormTypeInterface;
|
use Symfony\Component\Form\FormTypeInterface;
|
||||||
use Symfony\Component\Form\Form;
|
use Symfony\Component\Form\Form;
|
||||||
use Symfony\Component\Form\FormBuilder;
|
use Symfony\Component\Form\FormBuilder;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use Doctrine\Bundle\DoctrineBundle\Registry;
|
use Doctrine\Bundle\DoctrineBundle\Registry;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller is a simple implementation of a Controller.
|
* Controller is a simple implementation of a Controller.
|
||||||
@ -36,13 +37,13 @@ class Controller extends ContainerAware
|
|||||||
*
|
*
|
||||||
* @param string $route The name of the route
|
* @param string $route The name of the route
|
||||||
* @param mixed $parameters An array of parameters
|
* @param mixed $parameters An array of parameters
|
||||||
* @param Boolean $absolute Whether to generate an absolute URL
|
* @param string $referenceType The type of reference (see UrlGeneratorInterface)
|
||||||
*
|
*
|
||||||
* @return string The generated URL
|
* @return string The generated URL
|
||||||
*/
|
*/
|
||||||
public function generateUrl($route, $parameters = array(), $absolute = false)
|
public function generateUrl($route, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
|
||||||
{
|
{
|
||||||
return $this->container->get('router')->generate($route, $parameters, $absolute);
|
return $this->container->get('router')->generate($route, $parameters, $referenceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,8 +12,9 @@
|
|||||||
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
namespace Symfony\Bundle\FrameworkBundle\Controller;
|
||||||
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerAware;
|
use Symfony\Component\DependencyInjection\ContainerAware;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirects a request to another URL.
|
* Redirects a request to another URL.
|
||||||
@ -45,7 +46,7 @@ class RedirectController extends ContainerAware
|
|||||||
$attributes = $this->container->get('request')->attributes->get('_route_params');
|
$attributes = $this->container->get('request')->attributes->get('_route_params');
|
||||||
unset($attributes['route'], $attributes['permanent']);
|
unset($attributes['route'], $attributes['permanent']);
|
||||||
|
|
||||||
return new RedirectResponse($this->container->get('router')->generate($route, $attributes, true), $permanent ? 301 : 302);
|
return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $permanent ? 301 : 302);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,13 +38,13 @@ class RouterHelper extends Helper
|
|||||||
*
|
*
|
||||||
* @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 Boolean $absolute Whether to generate an absolute URL
|
* @param string $referenceType The type of reference (see UrlGeneratorInterface)
|
||||||
*
|
*
|
||||||
* @return string The generated URL
|
* @return string The generated URL
|
||||||
*/
|
*/
|
||||||
public function generate($name, $parameters = array(), $absolute = false)
|
public function generate($name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH)
|
||||||
{
|
{
|
||||||
return $this->generator->generate($name, $parameters, $absolute);
|
return $this->generator->generate($name, $parameters, $referenceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,36 +55,40 @@ class LogoutUrlHelper extends Helper
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the relative logout URL for the firewall.
|
* Generates the absolute logout path for the firewall.
|
||||||
*
|
*
|
||||||
* @param string $key The firewall key
|
* @param string $key The firewall key
|
||||||
* @return string The relative logout URL
|
*
|
||||||
|
* @return string The logout path
|
||||||
*/
|
*/
|
||||||
public function getLogoutPath($key)
|
public function getLogoutPath($key)
|
||||||
{
|
{
|
||||||
return $this->generateLogoutUrl($key, false);
|
return $this->generateLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the absolute logout URL for the firewall.
|
* Generates the absolute logout URL for the firewall.
|
||||||
*
|
*
|
||||||
* @param string $key The firewall key
|
* @param string $key The firewall key
|
||||||
* @return string The absolute logout URL
|
*
|
||||||
|
* @return string The logout URL
|
||||||
*/
|
*/
|
||||||
public function getLogoutUrl($key)
|
public function getLogoutUrl($key)
|
||||||
{
|
{
|
||||||
return $this->generateLogoutUrl($key, true);
|
return $this->generateLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the logout URL for the firewall.
|
* Generates the logout URL for the firewall.
|
||||||
*
|
*
|
||||||
* @param string $key The firewall key
|
* @param string $key The firewall key
|
||||||
* @param Boolean $absolute Whether to generate an absolute URL
|
* @param string $referenceType The type of reference (see UrlGeneratorInterface)
|
||||||
|
*
|
||||||
* @return string The logout URL
|
* @return string The logout URL
|
||||||
|
*
|
||||||
* @throws \InvalidArgumentException if no LogoutListener is registered for the key
|
* @throws \InvalidArgumentException if no LogoutListener is registered for the key
|
||||||
*/
|
*/
|
||||||
private function generateLogoutUrl($key, $absolute)
|
private function generateLogoutUrl($key, $referenceType)
|
||||||
{
|
{
|
||||||
if (!array_key_exists($key, $this->listeners)) {
|
if (!array_key_exists($key, $this->listeners)) {
|
||||||
throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key));
|
throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key));
|
||||||
@ -97,13 +101,13 @@ class LogoutUrlHelper extends Helper
|
|||||||
if ('/' === $logoutPath[0]) {
|
if ('/' === $logoutPath[0]) {
|
||||||
$request = $this->container->get('request');
|
$request = $this->container->get('request');
|
||||||
|
|
||||||
$url = ($absolute ? $request->getUriForPath($logoutPath) : $request->getBasePath() . $logoutPath);
|
$url = UrlGeneratorInterface::ABSOLUTE_URL === $referenceType ? $request->getUriForPath($logoutPath) : $request->getBasePath() . $logoutPath;
|
||||||
|
|
||||||
if (!empty($parameters)) {
|
if (!empty($parameters)) {
|
||||||
$url .= '?' . http_build_query($parameters);
|
$url .= '?' . http_build_query($parameters);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$url = $this->router->generate($logoutPath, $parameters, $absolute);
|
$url = $this->router->generate($logoutPath, $parameters, $referenceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security;
|
namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\FormLoginBundle\Security;
|
||||||
|
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
use Symfony\Component\Routing\RouterInterface;
|
use Symfony\Component\Routing\RouterInterface;
|
||||||
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
|
||||||
|
|
||||||
class LocalizedFormFailureHandler implements AuthenticationFailureHandlerInterface
|
class LocalizedFormFailureHandler implements AuthenticationFailureHandlerInterface
|
||||||
@ -28,6 +29,6 @@ class LocalizedFormFailureHandler implements AuthenticationFailureHandlerInterfa
|
|||||||
|
|
||||||
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
|
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
|
||||||
{
|
{
|
||||||
return new RedirectResponse($this->router->generate('localized_login_path', array(), true));
|
return new RedirectResponse($this->router->generate('localized_login_path', array(), UrlGeneratorInterface::ABSOLUTE_URL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ EOF;
|
|||||||
private function generateGenerateMethod()
|
private function generateGenerateMethod()
|
||||||
{
|
{
|
||||||
return <<<EOF
|
return <<<EOF
|
||||||
public function generate(\$name, \$parameters = array(), \$absolute = false)
|
public function generate(\$name, \$parameters = array(), \$referenceType = self::ABSOLUTE_PATH)
|
||||||
{
|
{
|
||||||
if (!isset(self::\$declaredRoutes[\$name])) {
|
if (!isset(self::\$declaredRoutes[\$name])) {
|
||||||
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', \$name));
|
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', \$name));
|
||||||
@ -116,7 +116,7 @@ EOF;
|
|||||||
|
|
||||||
list(\$variables, \$defaults, \$requirements, \$tokens, \$hostnameTokens) = self::\$declaredRoutes[\$name];
|
list(\$variables, \$defaults, \$requirements, \$tokens, \$hostnameTokens) = self::\$declaredRoutes[\$name];
|
||||||
|
|
||||||
return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$absolute, \$hostnameTokens);
|
return \$this->doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$referenceType, \$hostnameTokens);
|
||||||
}
|
}
|
||||||
EOF;
|
EOF;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public function generate($name, $parameters = array(), $absolute = false)
|
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
|
||||||
{
|
{
|
||||||
if (null === $route = $this->routes->get($name)) {
|
if (null === $route = $this->routes->get($name)) {
|
||||||
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
|
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
|
||||||
@ -136,15 +136,40 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
// the Route has a cache of its own and is not recompiled as long as it does not get modified
|
// the Route has a cache of its own and is not recompiled as long as it does not get modified
|
||||||
$compiledRoute = $route->compile();
|
$compiledRoute = $route->compile();
|
||||||
|
|
||||||
return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $absolute, $compiledRoute->getHostnameTokens());
|
return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostnameTokens());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method converts the reference type to the new value introduced in Symfony 2.2. It can be used by
|
||||||
|
* other UrlGenerator implementations to be BC with Symfony 2.1. Reference type was a Boolean called
|
||||||
|
* $absolute in Symfony 2.1 and only supported two reference types.
|
||||||
|
*
|
||||||
|
* @param Boolean $absolute Whether to generate an absolute URL
|
||||||
|
*
|
||||||
|
* @return string The new reference type
|
||||||
|
*
|
||||||
|
* @deprecated Deprecated since version 2.2, to be removed in 2.3.
|
||||||
|
*/
|
||||||
|
public static function convertReferenceType($absolute)
|
||||||
|
{
|
||||||
|
if (false === $absolute) {
|
||||||
|
return self::ABSOLUTE_PATH;
|
||||||
|
}
|
||||||
|
if (true === $absolute) {
|
||||||
|
return self::ABSOLUTE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $absolute;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws MissingMandatoryParametersException When route has some missing mandatory parameters
|
* @throws MissingMandatoryParametersException When route has some missing mandatory parameters
|
||||||
* @throws InvalidParameterException When a parameter value is not correct
|
* @throws InvalidParameterException When a parameter value is not correct
|
||||||
*/
|
*/
|
||||||
protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute, $hostnameTokens)
|
protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostnameTokens)
|
||||||
{
|
{
|
||||||
|
$referenceType = self::convertReferenceType($referenceType);
|
||||||
|
|
||||||
$variables = array_flip($variables);
|
$variables = array_flip($variables);
|
||||||
$mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
|
$mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
|
||||||
|
|
||||||
@ -186,8 +211,8 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
$url = '/';
|
$url = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not encode the contexts base url as it is already encoded (see Symfony\Component\HttpFoundation\Request)
|
// the contexts base url is already encoded (see Symfony\Component\HttpFoundation\Request)
|
||||||
$url = $this->context->getBaseUrl().strtr(rawurlencode($url), $this->decodedChars);
|
$url = strtr(rawurlencode($url), $this->decodedChars);
|
||||||
|
|
||||||
// the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
|
// the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
|
||||||
// so we need to encode them as they are not used for this purpose here
|
// so we need to encode them as they are not used for this purpose here
|
||||||
@ -199,16 +224,11 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
$url = substr($url, 0, -1) . '%2E';
|
$url = substr($url, 0, -1) . '%2E';
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a query string if needed
|
$schemeAuthority = '';
|
||||||
$extra = array_diff_key($parameters, $variables);
|
|
||||||
if ($extra && $query = http_build_query($extra, '', '&')) {
|
|
||||||
$url .= '?'.$query;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($host = $this->context->getHost()) {
|
if ($host = $this->context->getHost()) {
|
||||||
$scheme = $this->context->getScheme();
|
$scheme = $this->context->getScheme();
|
||||||
if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme != $req) {
|
if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) {
|
||||||
$absolute = true;
|
$referenceType = self::ABSOLUTE_URL;
|
||||||
$scheme = $req;
|
$scheme = $req;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,18 +251,20 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
}
|
}
|
||||||
|
|
||||||
$routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
|
$routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
|
||||||
} elseif ('text' === $token[0]) {
|
} else {
|
||||||
$routeHost = $token[1].$routeHost;
|
$routeHost = $token[1].$routeHost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($routeHost != $host) {
|
if ($routeHost !== $host) {
|
||||||
$host = $routeHost;
|
$host = $routeHost;
|
||||||
$absolute = true;
|
if (self::ABSOLUTE_URL !== $referenceType) {
|
||||||
|
$referenceType = self::NETWORK_PATH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($absolute) {
|
if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
|
||||||
$port = '';
|
$port = '';
|
||||||
if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
|
if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
|
||||||
$port = ':'.$this->context->getHttpPort();
|
$port = ':'.$this->context->getHttpPort();
|
||||||
@ -250,10 +272,74 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt
|
|||||||
$port = ':'.$this->context->getHttpsPort();
|
$port = ':'.$this->context->getHttpsPort();
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = $scheme.'://'.$host.$port.$url;
|
$schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://";
|
||||||
|
$schemeAuthority .= $host.$port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self::RELATIVE_PATH === $referenceType) {
|
||||||
|
$url = self::getRelativePath($this->context->getPathInfo(), $url);
|
||||||
|
} else {
|
||||||
|
$url = $schemeAuthority.$this->context->getBaseUrl().$url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a query string if needed
|
||||||
|
$extra = array_diff_key($parameters, $variables);
|
||||||
|
if ($extra && $query = http_build_query($extra, '', '&')) {
|
||||||
|
$url .= '?'.$query;
|
||||||
|
}
|
||||||
|
|
||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the target path as relative reference from the base path.
|
||||||
|
*
|
||||||
|
* Only the URIs path component (no schema, hostname etc.) is relevant and must be given, starting with a slash.
|
||||||
|
* Both paths must be absolute and not contain relative parts.
|
||||||
|
* Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
|
||||||
|
* Furthermore, they can be used to reduce the link size in documents.
|
||||||
|
*
|
||||||
|
* Example target paths, given a base path of "/a/b/c/d":
|
||||||
|
* - "/a/b/c/d" -> ""
|
||||||
|
* - "/a/b/c/" -> "./"
|
||||||
|
* - "/a/b/" -> "../"
|
||||||
|
* - "/a/b/c/other" -> "other"
|
||||||
|
* - "/a/x/y" -> "../../x/y"
|
||||||
|
*
|
||||||
|
* @param string $basePath The base path
|
||||||
|
* @param string $targetPath The target path
|
||||||
|
*
|
||||||
|
* @return string The relative target path
|
||||||
|
*/
|
||||||
|
public static function getRelativePath($basePath, $targetPath)
|
||||||
|
{
|
||||||
|
if ($basePath === $targetPath) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
|
||||||
|
$targetDirs = explode('/', isset($targetPath[0]) && '/' === $targetPath[0] ? substr($targetPath, 1) : $targetPath);
|
||||||
|
array_pop($sourceDirs);
|
||||||
|
$targetFile = array_pop($targetDirs);
|
||||||
|
|
||||||
|
foreach ($sourceDirs as $i => $dir) {
|
||||||
|
if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
|
||||||
|
unset($sourceDirs[$i], $targetDirs[$i]);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$targetDirs[] = $targetFile;
|
||||||
|
$path = str_repeat('../', count($sourceDirs)) . implode('/', $targetDirs);
|
||||||
|
|
||||||
|
// A reference to the same base directory or an empty subdirectory must be prefixed with "./".
|
||||||
|
// This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
|
||||||
|
// as the first segment of a relative-path reference, as it would be mistaken for a scheme name
|
||||||
|
// (see http://tools.ietf.org/html/rfc3986#section-4.2).
|
||||||
|
return '' === $path || '/' === $path[0]
|
||||||
|
|| false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
|
||||||
|
? "./$path" : $path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,25 @@ use Symfony\Component\Routing\Exception\RouteNotFoundException;
|
|||||||
* UrlGeneratorInterface is the interface that all URL generator classes must implement.
|
* UrlGeneratorInterface is the interface that all URL generator classes must implement.
|
||||||
*
|
*
|
||||||
* @author Fabien Potencier <fabien@symfony.com>
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Tobias Schultze <http://tobion.de>
|
||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
interface UrlGeneratorInterface extends RequestContextAwareInterface
|
interface UrlGeneratorInterface extends RequestContextAwareInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* These constants define the different types of resource references that are declared
|
||||||
|
* in RFC 3986: http://tools.ietf.org/html/rfc3986
|
||||||
|
* We are using the term "URL" instead of "URI" as this is more common in web applications
|
||||||
|
* and we do not need to distinguish them as the difference is mostly semantical and
|
||||||
|
* less technical. Generating URIs, i.e. representation-independent resource identifiers,
|
||||||
|
* is still possible.
|
||||||
|
*/
|
||||||
|
const ABSOLUTE_URL = 'url';
|
||||||
|
const ABSOLUTE_PATH = 'path';
|
||||||
|
const RELATIVE_PATH = 'relative';
|
||||||
|
const NETWORK_PATH = 'network';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a URL from the given parameters.
|
* Generates a URL from the given parameters.
|
||||||
*
|
*
|
||||||
@ -31,7 +45,7 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
|
|||||||
*
|
*
|
||||||
* @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 Boolean $absolute Whether to generate an absolute URL
|
* @param string $referenceType The type of reference to be generated (see defined constants)
|
||||||
*
|
*
|
||||||
* @return string The generated URL
|
* @return string The generated URL
|
||||||
*
|
*
|
||||||
@ -39,5 +53,5 @@ interface UrlGeneratorInterface extends RequestContextAwareInterface
|
|||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function generate($name, $parameters = array(), $absolute = false);
|
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ use Symfony\Component\HttpFoundation\Request;
|
|||||||
class RequestContext
|
class RequestContext
|
||||||
{
|
{
|
||||||
private $baseUrl;
|
private $baseUrl;
|
||||||
|
private $pathInfo;
|
||||||
private $method;
|
private $method;
|
||||||
private $host;
|
private $host;
|
||||||
private $scheme;
|
private $scheme;
|
||||||
@ -46,7 +47,7 @@ class RequestContext
|
|||||||
*
|
*
|
||||||
* @api
|
* @api
|
||||||
*/
|
*/
|
||||||
public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443)
|
public function __construct($baseUrl = '', $method = 'GET', $host = 'localhost', $scheme = 'http', $httpPort = 80, $httpsPort = 443, $path = '/')
|
||||||
{
|
{
|
||||||
$this->baseUrl = $baseUrl;
|
$this->baseUrl = $baseUrl;
|
||||||
$this->method = strtoupper($method);
|
$this->method = strtoupper($method);
|
||||||
@ -54,11 +55,13 @@ class RequestContext
|
|||||||
$this->scheme = strtolower($scheme);
|
$this->scheme = strtolower($scheme);
|
||||||
$this->httpPort = $httpPort;
|
$this->httpPort = $httpPort;
|
||||||
$this->httpsPort = $httpsPort;
|
$this->httpsPort = $httpsPort;
|
||||||
|
$this->pathInfo = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fromRequest(Request $request)
|
public function fromRequest(Request $request)
|
||||||
{
|
{
|
||||||
$this->setBaseUrl($request->getBaseUrl());
|
$this->setBaseUrl($request->getBaseUrl());
|
||||||
|
$this->setPathInfo($request->getPathInfo());
|
||||||
$this->setMethod($request->getMethod());
|
$this->setMethod($request->getMethod());
|
||||||
$this->setHost($request->getHost());
|
$this->setHost($request->getHost());
|
||||||
$this->setScheme($request->getScheme());
|
$this->setScheme($request->getScheme());
|
||||||
@ -88,6 +91,26 @@ class RequestContext
|
|||||||
$this->baseUrl = $baseUrl;
|
$this->baseUrl = $baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the path info.
|
||||||
|
*
|
||||||
|
* @return string The path info
|
||||||
|
*/
|
||||||
|
public function getPathInfo()
|
||||||
|
{
|
||||||
|
return $this->pathInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the path info.
|
||||||
|
*
|
||||||
|
* @param string $pathInfo The path info
|
||||||
|
*/
|
||||||
|
public function setPathInfo($pathInfo)
|
||||||
|
{
|
||||||
|
$this->pathInfo = $pathInfo;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the HTTP method.
|
* Gets the HTTP method.
|
||||||
*
|
*
|
||||||
|
@ -202,9 +202,9 @@ class Router implements RouterInterface
|
|||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function generate($name, $parameters = array(), $absolute = false)
|
public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
|
||||||
{
|
{
|
||||||
return $this->getGenerator()->generate($name, $parameters, $absolute);
|
return $this->getGenerator()->generate($name, $parameters, $referenceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -379,7 +379,6 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
public function testDefaultRequirementOfVariableDisallowsNextSeparator()
|
public function testDefaultRequirementOfVariableDisallowsNextSeparator()
|
||||||
{
|
{
|
||||||
|
|
||||||
$routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
|
$routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
|
||||||
$this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
|
$this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
|
||||||
}
|
}
|
||||||
@ -388,7 +387,7 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
|
$routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
|
||||||
|
|
||||||
$this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
|
$this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' =>'Fabien', 'locale' => 'fr')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWithHostnameSameAsContext()
|
public function testWithHostnameSameAsContext()
|
||||||
@ -440,6 +439,120 @@ class UrlGeneratorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertNull($generator->generate('test', array('foo' => 'baz'), false));
|
$this->assertNull($generator->generate('test', array('foo' => 'baz'), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideRelativePaths
|
||||||
|
*/
|
||||||
|
public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
|
||||||
|
{
|
||||||
|
$this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function provideRelativePaths()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array(
|
||||||
|
'/same/dir/',
|
||||||
|
'/same/dir/',
|
||||||
|
''
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/same/file',
|
||||||
|
'/same/file',
|
||||||
|
''
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/',
|
||||||
|
'/file',
|
||||||
|
'file'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/',
|
||||||
|
'/dir/file',
|
||||||
|
'dir/file'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/dir/file.html',
|
||||||
|
'/dir/different-file.html',
|
||||||
|
'different-file.html'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/same/dir/extra-file',
|
||||||
|
'/same/dir/',
|
||||||
|
'./'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/parent/dir/',
|
||||||
|
'/parent/',
|
||||||
|
'../'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/parent/dir/extra-file',
|
||||||
|
'/parent/',
|
||||||
|
'../'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/a/b/',
|
||||||
|
'/x/y/z/',
|
||||||
|
'../../x/y/z/'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/a/b/c/d/e',
|
||||||
|
'/a/c/d',
|
||||||
|
'../../../c/d'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/a/b/c//',
|
||||||
|
'/a/b/c/',
|
||||||
|
'../'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/a/b/c/',
|
||||||
|
'/a/b/c//',
|
||||||
|
'.//'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/root/a/b/c/',
|
||||||
|
'/root/x/b/c/',
|
||||||
|
'../../../x/b/c/'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/a/b/c/d/',
|
||||||
|
'/a',
|
||||||
|
'../../../../a'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/special-chars/sp%20ce/1€/mäh/e=mc²',
|
||||||
|
'/special-chars/sp%20ce/1€/<µ>/e=mc²',
|
||||||
|
'../<µ>/e=mc²'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'not-rooted',
|
||||||
|
'dir/file',
|
||||||
|
'dir/file'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'//dir/',
|
||||||
|
'',
|
||||||
|
'../../'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/dir/',
|
||||||
|
'/dir/file:with-colon',
|
||||||
|
'./file:with-colon'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/dir/',
|
||||||
|
'/dir/subdir/file:with-colon',
|
||||||
|
'subdir/file:with-colon'
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'/dir/',
|
||||||
|
'/dir/:subdir/',
|
||||||
|
'./:subdir/'
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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');
|
||||||
|
@ -67,8 +67,8 @@ class HttpUtils
|
|||||||
public function createRequest(Request $request, $path)
|
public function createRequest(Request $request, $path)
|
||||||
{
|
{
|
||||||
$newRequest = Request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all());
|
$newRequest = Request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all());
|
||||||
if ($session = $request->getSession()) {
|
if ($request->hasSession()) {
|
||||||
$newRequest->setSession($session);
|
$newRequest->setSession($request->getSession());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
|
if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
|
||||||
@ -127,15 +127,10 @@ class HttpUtils
|
|||||||
return $request->getUriForPath($path);
|
return $request->getUriForPath($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->generateUrl($path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function generateUrl($route, $absolute = false)
|
|
||||||
{
|
|
||||||
if (null === $this->urlGenerator) {
|
if (null === $this->urlGenerator) {
|
||||||
throw new \LogicException('You must provide a UrlGeneratorInterface instance to be able to use routes.');
|
throw new \LogicException('You must provide a UrlGeneratorInterface instance to be able to use routes.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->urlGenerator->generate($route, array(), $absolute);
|
return $this->urlGenerator->generate($path, array(), UrlGeneratorInterface::ABSOLUTE_URL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user