A Generator creates URL strings based on a specified route.
Expanded class hierarchy of UrlGenerator
class UrlGenerator extends ProviderBasedGenerator implements PathBasedGeneratorInterface {
/**
* A request object.
*
* @var \Symfony\Component\HttpFoundation\Request
*/
protected $request;
/**
* The path processor to convert the system path to one suitable for urls.
*
* @var \Drupal\Core\PathProcessor\OutboundPathProcessorInterface
*/
protected $pathProcessor;
/**
* The base path to use for urls.
*
* @var string
*/
protected $basePath;
/**
* The base url to use for urls.
*
* @var string
*/
protected $baseUrl;
/**
* The script path to use for urls.
*
* @var string
*/
protected $scriptPath;
/**
* Whether both secure and insecure session cookies can be used simultaneously.
*
* @var bool
*/
protected $mixedModeSessions;
/**
* Constructs a new generator object.
*
* @param \Symfony\Cmf\Component\Routing\RouteProviderInterface $provider
* The route provider to be searched for routes.
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
* The alias manager responsible for path aliasing.
* @param \Symfony\Component\HttpKernel\Log\LoggerInterface $logger
* An optional logger for recording errors.
*/
public function __construct(RouteProviderInterface $provider, OutboundPathProcessorInterface $path_processor, ConfigFactory $config, Settings $settings, LoggerInterface $logger = NULL) {
parent::__construct($provider, $logger);
$this->pathProcessor = $path_processor;
$this->mixedModeSessions = $settings
->get('mixed_mode_sessions', FALSE);
$allowed_protocols = $config
->get('system.filter')
->get('protocols') ?: array(
'http',
'https',
);
UrlValidator::setAllowedProtocols($allowed_protocols);
}
/**
* Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setRequest().
*/
public function setRequest(Request $request) {
$this->request = $request;
// Set some properties, based on the request, that are used during path-based
// url generation.
$this->basePath = $request
->getBasePath() . '/';
$this->baseUrl = $request
->getSchemeAndHttpHost() . $this->basePath;
$this->scriptPath = '';
$base_path_with_script = $request
->getBaseUrl();
$script_name = $request
->getScriptName();
if (!empty($base_path_with_script) && strpos($base_path_with_script, $script_name) !== FALSE) {
$length = strlen($this->basePath);
$this->scriptPath = ltrim(substr($script_name, $length), '/') . '/';
}
}
/**
* Implements Symfony\Component\Routing\Generator\UrlGeneratorInterface::generate().
*/
public function generate($name, $parameters = array(), $absolute = FALSE) {
if ($name instanceof SymfonyRoute) {
$route = $name;
}
elseif (null === ($route = $this->provider
->getRouteByName($name, $parameters))) {
throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name));
}
// The Route has a cache of its own and is not recompiled as long as it does
// not get modified.
$compiledRoute = $route
->compile();
$hostTokens = $compiledRoute
->getHostTokens();
$route_requirements = $route
->getRequirements();
// We need to bypass the doGenerate() method's handling of absolute URLs as
// we handle that ourselves after processing the path.
if (isset($route_requirements['_scheme'])) {
$scheme_req = $route_requirements['_scheme'];
unset($route_requirements['_scheme']);
}
$path = $this
->doGenerate($compiledRoute
->getVariables(), $route
->getDefaults(), $route_requirements, $compiledRoute
->getTokens(), $parameters, $name, FALSE, $hostTokens);
// The URL returned from doGenerate() will include the base path if there is
// one (i.e., if running in a subdirectory) so we need to strip that off
// before processing the path.
$base_url = $this->context
->getBaseUrl();
if (!empty($base_url) && strpos($path, $base_url) === 0) {
$path = substr($path, strlen($base_url));
}
$path = $this
->processPath($path);
if (!$absolute || !($host = $this->context
->getHost())) {
return $base_url . $path;
}
// Prepare an absolute URL by getting the correct scheme, host and port from
// the request context.
$scheme = $this->context
->getScheme();
if (isset($scheme_req) && ($req = strtolower($scheme_req)) && $scheme !== $req) {
$scheme = $req;
}
$port = '';
if ('http' === $scheme && 80 != $this->context
->getHttpPort()) {
$port = ':' . $this->context
->getHttpPort();
}
elseif ('https' === $scheme && 443 != $this->context
->getHttpsPort()) {
$port = ':' . $this->context
->getHttpsPort();
}
return $scheme . '://' . $host . $port . $base_url . $path;
}
/**
* Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::generateFromPath().
*
* @param $path
* (optional) The internal path or external URL being linked to, such as
* "node/34" or "http://example.com/foo". The default value is equivalent to
* passing in '<front>'. A few notes:
* - If you provide a full URL, it will be considered an external URL.
* - If you provide only the path (e.g. "node/34"), it will be
* considered an internal link. In this case, it should be a system URL,
* and it will be replaced with the alias, if one exists. Additional query
* arguments for internal paths must be supplied in $options['query'], not
* included in $path.
* - If you provide an internal path and $options['alias'] is set to TRUE, the
* path is assumed already to be the correct path alias, and the alias is
* not looked up.
* - The special string '<front>' generates a link to the site's base URL.
* - If your external URL contains a query (e.g. http://example.com/foo?a=b),
* then you can either URL encode the query keys and values yourself and
* include them in $path, or use $options['query'] to let this method
* URL encode them.
*
* @param $options
* (optional) An associative array of additional options, with the following
* elements:
* - 'query': An array of query key/value-pairs (without any URL-encoding) to
* append to the URL.
* - 'fragment': A fragment identifier (named anchor) to append to the URL.
* Do not include the leading '#' character.
* - 'absolute': Defaults to FALSE. Whether to force the output to be an
* absolute link (beginning with http:). Useful for links that will be
* displayed outside the site, such as in an RSS feed.
* - 'alias': Defaults to FALSE. Whether the given path is a URL alias
* already.
* - 'external': Whether the given path is an external URL.
* - 'language': An optional language object. If the path being linked to is
* internal to the site, $options['language'] is used to look up the alias
* for the URL. If $options['language'] is omitted, the language will be
* obtained from language(Language::TYPE_URL).
* - 'https': Whether this URL should point to a secure location. If not
* defined, the current scheme is used, so the user stays on HTTP or HTTPS
* respectively. TRUE enforces HTTPS and FALSE enforces HTTP, but HTTPS can
* only be enforced when the variable 'https' is set to TRUE.
* - 'base_url': Only used internally, to modify the base URL when a language
* dependent URL requires so.
* - 'prefix': Only used internally, to modify the path when a language
* dependent URL requires so.
* - 'script': Added to the URL between the base path and the path prefix.
* Defaults to empty string when clean URLs are in effect, and to
* 'index.php/' when they are not.
* - 'entity_type': The entity type of the object that called url(). Only
* set if url() is invoked by Drupal\Core\Entity\Entity::uri().
* - 'entity': The entity object (such as a node) for which the URL is being
* generated. Only set if url() is invoked by Drupal\Core\Entity\Entity::uri().
*
* @return
* A string containing a URL to the given path.
*
* @throws \Drupal\Core\Routing\GeneratorNotInitializedException.
*/
public function generateFromPath($path = NULL, $options = array()) {
if (!$this
->initialized()) {
throw new GeneratorNotInitializedException();
}
// Merge in defaults.
$options += array(
'fragment' => '',
'query' => array(),
'absolute' => FALSE,
'prefix' => '',
);
if (!isset($options['external'])) {
// Return an external link if $path contains an allowed absolute URL. Only
// call the slow drupal_strip_dangerous_protocols() if $path contains a ':'
// before any / ? or #. Note: we could use url_is_external($path) here, but
// that would require another function call, and performance inside url() is
// critical.
$colonpos = strpos($path, ':');
$options['external'] = $colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && UrlValidator::stripDangerousProtocols($path) == $path;
}
if (isset($options['fragment']) && $options['fragment'] !== '') {
$options['fragment'] = '#' . $options['fragment'];
}
if ($options['external']) {
// Split off the fragment.
if (strpos($path, '#') !== FALSE) {
list($path, $old_fragment) = explode('#', $path, 2);
// If $options contains no fragment, take it over from the path.
if (isset($old_fragment) && !$options['fragment']) {
$options['fragment'] = '#' . $old_fragment;
}
}
// Append the query.
if ($options['query']) {
$path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $this
->httpBuildQuery($options['query']);
}
if (isset($options['https']) && $this->mixedModeSessions) {
if ($options['https'] === TRUE) {
$path = str_replace('http://', 'https://', $path);
}
elseif ($options['https'] === FALSE) {
$path = str_replace('https://', 'http://', $path);
}
}
// Reassemble.
return $path . $options['fragment'];
}
else {
$path = ltrim($this
->processPath($path, $options), '/');
}
if (!isset($options['script'])) {
$options['script'] = $this->scriptPath;
}
// The base_url might be rewritten from the language rewrite in domain mode.
if (!isset($options['base_url'])) {
if (isset($options['https']) && $this->mixedModeSessions) {
if ($options['https'] === TRUE) {
$options['base_url'] = str_replace('http://', 'https://', $this->baseUrl);
$options['absolute'] = TRUE;
}
elseif ($options['https'] === FALSE) {
$options['base_url'] = str_replace('https://', 'http://', $this->baseUrl);
$options['absolute'] = TRUE;
}
}
else {
$options['base_url'] = $this->baseUrl;
}
}
elseif (rtrim($options['base_url'], '/') == $options['base_url']) {
$options['base_url'] .= '/';
}
$base = $options['absolute'] ? $options['base_url'] : $this->basePath;
$prefix = empty($path) ? rtrim($options['prefix'], '/') : $options['prefix'];
$path = str_replace('%2F', '/', rawurlencode($prefix . $path));
$query = $options['query'] ? '?' . $this
->httpBuildQuery($options['query']) : '';
return $base . $options['script'] . $path . $query . $options['fragment'];
}
/**
* Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setBaseUrl().
*/
public function setBaseUrl($url) {
$this->baseUrl = $url;
}
/**
* Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setBasePath().
*/
public function setBasePath($path) {
$this->basePath = $path;
}
/**
* Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setScriptPath().
*/
public function setScriptPath($path) {
$this->scriptPath = $path;
}
/**
* Parses an array into a valid, rawurlencoded query string.
*
* This differs from http_build_query() as we need to rawurlencode() (instead of
* urlencode()) all query parameters.
*
* @param $query
* The query parameter array to be processed, e.g. $_GET.
* @param $parent
* Internal use only. Used to build the $query array key for nested items.
*
* @return
* A rawurlencoded string which can be used as or appended to the URL query
* string.
*
* @see drupal_get_query_parameters()
* @ingroup php_wrappers
*/
public function httpBuildQuery(array $query, $parent = '') {
$params = array();
foreach ($query as $key => $value) {
$key = $parent ? $parent . '[' . rawurlencode($key) . ']' : rawurlencode($key);
// Recurse into children.
if (is_array($value)) {
$params[] = $this
->httpBuildQuery($value, $key);
}
elseif (!isset($value)) {
$params[] = $key;
}
else {
// For better readability of paths in query strings, we decode slashes.
$params[] = $key . '=' . str_replace('%2F', '/', rawurlencode($value));
}
}
return implode('&', $params);
}
/**
* Passes the path to a processor manager to allow alterations.
*/
protected function processPath($path, &$options = array()) {
// Router-based paths may have a querystring on them.
if ($query_pos = strpos($path, '?')) {
// We don't need to do a strict check here because position 0 would mean we
// have no actual path to work with.
$actual_path = substr($path, 0, $query_pos);
$query_string = substr($path, $query_pos);
}
else {
$actual_path = $path;
$query_string = '';
}
$path = '/' . $this->pathProcessor
->processOutbound(trim($actual_path, '/'), $options, $this->request);
$path .= $query_string;
return $path;
}
/**
* Returns whether or not the url generator has been initialized.
*
* @return bool
* Returns TRUE if the basePath, baseUrl and scriptPath properties have been
* set, FALSE otherwise.
*/
protected function initialized() {
return isset($this->basePath) && isset($this->baseUrl) && isset($this->scriptPath);
}
}
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
UrlGeneratorInterface:: |
constant | Generates a relative path based on the current request path, e.g. "../parent-file". | ||
UrlGeneratorInterface:: |
constant | Generates a network path, e.g. "//example.com/dir/file". Such reference reuses the current scheme but specifies the host. | ||
UrlGeneratorInterface:: |
constant | Generates an absolute URL, e.g. "http://example.com/dir/file". | ||
UrlGeneratorInterface:: |
constant | Generates an absolute path, e.g. "/dir/file". | ||
UrlGenerator:: |
public | function |
Constructs a new generator object. Overrides ProviderBasedGenerator:: |
|
UrlGenerator:: |
public | function |
Enables or disables the exception on incorrect parameters.
Passing null will deactivate the requirements check completely. Overrides ConfigurableRequirementsInterface:: |
|
UrlGenerator:: |
public | function |
Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setScriptPath(). Overrides PathBasedGeneratorInterface:: |
|
UrlGenerator:: |
public | function |
Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setRequest(). Overrides PathBasedGeneratorInterface:: |
|
UrlGenerator:: |
public | function |
Sets the request context. Overrides RequestContextAwareInterface:: |
1 |
UrlGenerator:: |
public | function |
Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setBaseUrl(). Overrides PathBasedGeneratorInterface:: |
|
UrlGenerator:: |
public | function |
Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::setBasePath(). Overrides PathBasedGeneratorInterface:: |
|
UrlGenerator:: |
protected | function | Passes the path to a processor manager to allow alterations. | 1 |
UrlGenerator:: |
public | function |
Returns whether to throw an exception on incorrect parameters.
Null means the requirements check is deactivated completely. Overrides ConfigurableRequirementsInterface:: |
|
UrlGenerator:: |
protected | function | Returns whether or not the url generator has been initialized. | |
UrlGenerator:: |
public | function | Parses an array into a valid, rawurlencoded query string. | |
UrlGenerator:: |
public static | function | Returns the target path as relative reference from the base path. | |
UrlGenerator:: |
public | function |
Gets the request context. Overrides RequestContextAwareInterface:: |
1 |
UrlGenerator:: |
public | function |
Implements \Drupal\Core\Routing\PathBasedGeneratorInterface::generateFromPath(). Overrides PathBasedGeneratorInterface:: |
|
UrlGenerator:: |
public | function |
Implements Symfony\Component\Routing\Generator\UrlGeneratorInterface::generate(). Overrides ProviderBasedGenerator:: |
|
UrlGenerator:: |
protected | function | 2 | |
UrlGenerator:: |
protected | property | ||
UrlGenerator:: |
protected | property | The script path to use for urls. | |
UrlGenerator:: |
protected | property | ||
UrlGenerator:: |
protected | property | A request object. | |
UrlGenerator:: |
protected | property | The path processor to convert the system path to one suitable for urls. | |
UrlGenerator:: |
protected | property | Whether both secure and insecure session cookies can be used simultaneously. | |
UrlGenerator:: |
protected | property | ||
UrlGenerator:: |
protected | property | This array defines the characters (besides alphanumeric ones) that will not be percent-encoded in the path segment of the generated URL. | |
UrlGenerator:: |
protected | property | ||
UrlGenerator:: |
protected | property | The base url to use for urls. | |
UrlGenerator:: |
protected | property | The base path to use for urls. | |
ProviderBasedGenerator:: |
public | function |
Support a route object and any string as route name Overrides VersatileGeneratorInterface:: |
1 |
ProviderBasedGenerator:: |
public | function |
Convert a route identifier (name, content object etc) into a string
usable for logging and other debug/error messages Overrides VersatileGeneratorInterface:: |
1 |
ProviderBasedGenerator:: |
protected | property | The route provider for this generator. |