Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
Total | |
0.00% |
0 / 1 |
|
54.55% |
18 / 33 |
CRAP | |
62.50% |
90 / 144 |
Url | |
0.00% |
0 / 1 |
|
54.55% |
18 / 33 |
389.66 | |
62.50% |
90 / 144 |
__construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
fromRoute | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
fromRouteMatch | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
fromUserInput | |
100.00% |
1 / 1 |
4 | |
100.00% |
3 / 3 |
|||
fromUri | |
100.00% |
1 / 1 |
13 | |
100.00% |
31 / 31 |
|||
fromEntityUri | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 4 |
|||
fromInternalUri | |
0.00% |
0 / 1 |
42 | |
0.00% |
0 / 13 |
|||
fromRouteUri | |
0.00% |
0 / 1 |
4.12 | |
50.00% |
4 / 8 |
|||
createFromRequest | |
100.00% |
1 / 1 |
1 | |
100.00% |
4 / 4 |
|||
setUnrouted | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 5 |
|||
toUriString | |
0.00% |
0 / 1 |
6.07 | |
87.50% |
7 / 8 |
|||
isExternal | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
isRouted | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getRouteName | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
getRouteParameters | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
setRouteParameters | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
setRouteParameter | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 4 |
|||
getOptions | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
getOption | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
setOptions | |
100.00% |
1 / 1 |
1 | |
100.00% |
2 / 2 |
|||
setOption | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
getUri | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
setAbsolute | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
toString | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
toRenderArray | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 5 |
|||
getInternalPath | |
100.00% |
1 / 1 |
3 | |
100.00% |
5 / 5 |
|||
access | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
renderAccess | |
100.00% |
1 / 1 |
1 | |
100.00% |
1 / 1 |
|||
accessManager | |
0.00% |
0 / 1 |
2.15 | |
66.67% |
2 / 3 |
|||
urlGenerator | |
100.00% |
1 / 1 |
2 | |
100.00% |
3 / 3 |
|||
unroutedUrlAssembler | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 3 |
|||
setUrlGenerator | |
100.00% |
1 / 1 |
1 | |
100.00% |
3 / 3 |
|||
setUnroutedUrlAssembler | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
<?php | |
/** | |
* @file | |
* Contains \Drupal\Core\Url. | |
*/ | |
namespace Drupal\Core; | |
use Drupal\Component\Utility\UrlHelper; | |
use Drupal\Core\DependencyInjection\DependencySerializationTrait; | |
use Drupal\Core\Routing\RouteMatchInterface; | |
use Drupal\Core\Routing\UrlGeneratorInterface; | |
use Drupal\Core\Session\AccountInterface; | |
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface; | |
use Symfony\Cmf\Component\Routing\RouteObjectInterface; | |
use Symfony\Component\HttpFoundation\Request; | |
/** | |
* Defines an object that holds information about a URL. | |
*/ | |
class Url { | |
use DependencySerializationTrait; | |
/** | |
* The URL generator. | |
* | |
* @var \Drupal\Core\Routing\UrlGeneratorInterface | |
*/ | |
protected $urlGenerator; | |
/** | |
* The unrouted URL assembler. | |
* | |
* @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface | |
*/ | |
protected $urlAssembler; | |
/** | |
* The access manager | |
* | |
* @var \Drupal\Core\Access\AccessManagerInterface | |
*/ | |
protected $accessManager; | |
/** | |
* The route name. | |
* | |
* @var string | |
*/ | |
protected $routeName; | |
/** | |
* The route parameters. | |
* | |
* @var array | |
*/ | |
protected $routeParameters = array(); | |
/** | |
* The URL options. | |
* | |
* @var array | |
*/ | |
protected $options = array(); | |
/** | |
* Indicates whether this object contains an external URL. | |
* | |
* @var bool | |
*/ | |
protected $external = FALSE; | |
/** | |
* Indicates whether this URL is for a URI without a Drupal route. | |
* | |
* @var bool | |
*/ | |
protected $unrouted = FALSE; | |
/** | |
* The non-route URI. | |
* | |
* Only used if self::$unrouted is TRUE. | |
* | |
* @var string | |
*/ | |
protected $uri; | |
/** | |
* Stores the internal path, if already requested by getInternalPath(). | |
* | |
* @var string | |
*/ | |
protected $internalPath; | |
/** | |
* Constructs a new Url object. | |
* | |
* In most cases, use Url::fromRoute() or Url::fromUri() rather than | |
* constructing Url objects directly in order to avoid ambiguity and make your | |
* code more self-documenting. | |
* | |
* @param string $route_name | |
* The name of the route | |
* @param array $route_parameters | |
* (optional) An associative array of parameter names and values. | |
* @param array $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. Merged with the parameters array. | |
* - '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. | |
* - 'language': An optional language object used to look up the alias | |
* for the URL. If $options['language'] is omitted, it defaults to the | |
* current language for the language type LanguageInterface::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. | |
* | |
* @see static::fromRoute() | |
* @see static::fromUri() | |
* | |
* @todo Update this documentation for non-routed URIs in | |
* https://www.drupal.org/node/2346787 | |
*/ | |
public function __construct($route_name, $route_parameters = array(), $options = array()) { | |
$this->routeName = $route_name; | |
$this->routeParameters = $route_parameters; | |
$this->options = $options; | |
} | |
/** | |
* Creates a new Url object for a URL that has a Drupal route. | |
* | |
* This method is for URLs that have Drupal routes (that is, most pages | |
* generated by Drupal). For non-routed local URIs relative to the base | |
* path (like robots.txt) use Url::fromUri() with the base: scheme. | |
* | |
* @param string $route_name | |
* The name of the route | |
* @param array $route_parameters | |
* (optional) An associative array of route parameter names and values. | |
* @param array $options | |
* (optional) An associative array of additional URL options, with the | |
* following elements: | |
* - 'query': An array of query key/value-pairs (without any URL-encoding) | |
* to append to the URL. Merged with the parameters array. | |
* - '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. | |
* - 'language': An optional language object used to look up the alias | |
* for the URL. If $options['language'] is omitted, it defaults to the | |
* current language for the language type LanguageInterface::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. | |
* | |
* @return \Drupal\Core\Url | |
* A new Url object for a routed (internal to Drupal) URL. | |
* | |
* @see \Drupal\Core\Url::fromUserInput() | |
* @see \Drupal\Core\Url::fromUri() | |
*/ | |
public static function fromRoute($route_name, $route_parameters = array(), $options = array()) { | |
return new static($route_name, $route_parameters, $options); | |
} | |
/** | |
* Creates a new URL object from a route match. | |
* | |
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match | |
* The route match. | |
* | |
* @return $this | |
*/ | |
public static function fromRouteMatch(RouteMatchInterface $route_match) { | |
if ($route_match->getRouteObject()) { | |
return new static($route_match->getRouteName(), $route_match->getRawParameters()->all()); | |
} | |
else { | |
throw new \InvalidArgumentException('Route required'); | |
} | |
} | |
/** | |
* Creates a Url object for a relative URI reference submitted by user input. | |
* | |
* Use this method to create a URL for user-entered paths that may or may not | |
* correspond to a valid Drupal route. | |
* | |
* @param string $user_input | |
* User input for a link or path. The first character must be one of the | |
* following characters: | |
* - '/': A path within the current site. This path might be to a Drupal | |
* route (e.g., '/admin'), to a file (e.g., '/README.txt'), or to | |
* something processed by a non-Drupal script (e.g., | |
* '/not/a/drupal/page'). If the path matches a Drupal route, then the | |
* URL generation will include Drupal's path processors (e.g., | |
* language-prefixing and aliasing). Otherwise, the URL generation will | |
* just append the passed-in path to Drupal's base path. | |
* - '?': A query string for the current page or resource. | |
* - '#': A fragment (jump-link) on the current page or resource. | |
* This helps reduce ambiguity for user-entered links and paths, and | |
* supports user interfaces where users may normally use auto-completion | |
* to search for existing resources, but also may type one of these | |
* characters to link to (e.g.) a specific path on the site. | |
* (With regard to the URI specification, the user input is treated as a | |
* @link https://tools.ietf.org/html/rfc3986#section-4.2 relative URI reference @endlink | |
* where the relative part is of type | |
* @link https://tools.ietf.org/html/rfc3986#section-3.3 path-abempty @endlink.) | |
* @param array $options | |
* (optional) An array of options. See Url::fromUri() for details. | |
* | |
* @return static | |
* A new Url object based on user input. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown when the user input does not begin with one of the following | |
* characters: '/', '?', or '#'. | |
*/ | |
public static function fromUserInput($user_input, $options = []) { | |
// Ensuring one of these initial characters also enforces that what is | |
// passed is a relative URI reference rather than an absolute URI, | |
// because these are URI reserved characters that a scheme name may not | |
// start with. | |
if ((strpos($user_input, '/') !== 0) && (strpos($user_input, '#') !== 0) && (strpos($user_input, '?') !== 0)) { | |
throw new \InvalidArgumentException("The user-entered string '$user_input' must begin with a '/', '?', or '#'."); | |
} | |
// fromUri() requires an absolute URI, so prepend the appropriate scheme | |
// name. | |
return static::fromUri('internal:' . $user_input, $options); | |
} | |
/** | |
* Creates a new Url object from a URI. | |
* | |
* This method is for generating URLs for URIs that: | |
* - do not have Drupal routes: both external URLs and unrouted local URIs | |
* like base:robots.txt | |
* - do have a Drupal route but have a custom scheme to simplify linking. | |
* Currently, there is only the entity: scheme (This allows URIs of the | |
* form entity:{entity_type}/{entity_id}. For example: entity:node/1 | |
* resolves to the entity.node.canonical route with a node parameter of 1.) | |
* | |
* For URLs that have Drupal routes (that is, most pages generated by Drupal), | |
* use Url::fromRoute(). | |
* | |
* @param string $uri | |
* The URI of the resource including the scheme. For user input that may | |
* correspond to a Drupal route, use internal: for the scheme. For paths | |
* that are known not to be handled by the Drupal routing system (such as | |
* static files), use base: for the scheme to get a link relative to the | |
* Drupal base path (like the <base> HTML element). For a link to an entity | |
* you may use entity:{entity_type}/{entity_id} URIs. | |
* @param array $options | |
* (optional) An associative array of additional URL 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. | |
* - 'language': An optional language object used to look up the alias | |
* for the URL. If $options['language'] is omitted, it defaults to the | |
* current language for the language type LanguageInterface::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. | |
* | |
* Note: the internal: scheme should be avoided except when processing actual | |
* user input that may or may not correspond to a Drupal route. Normally use | |
* Url::fromRoute() for code linking to any any Drupal page. | |
* | |
* You can call access() on the returned object to do access checking. | |
* | |
* @return \Drupal\Core\Url | |
* A new Url object with properties depending on the URI scheme. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown when the passed in path has no scheme. | |
* | |
* @see \Drupal\Core\Url::fromRoute() | |
* @see \Drupal\Core\Url::fromUserInput() | |
*/ | |
public static function fromUri($uri, $options = []) { | |
// parse_url() incorrectly parses base:number/... as hostname:port/... | |
// and not the scheme. Prevent that by prefixing the path with a slash. | |
if (preg_match('/^base:\d/', $uri)) { | |
$uri = str_replace('base:', 'base:/', $uri); | |
} | |
$uri_parts = parse_url($uri); | |
if ($uri_parts === FALSE) { | |
throw new \InvalidArgumentException("The URI '$uri' is malformed."); | |
} | |
if (empty($uri_parts['scheme'])) { | |
throw new \InvalidArgumentException("The URI '$uri' is invalid. You must use a valid URI scheme."); | |
} | |
$uri_parts += ['path' => '']; | |
// Discard empty fragment in $options for consistency with parse_url(). | |
if (isset($options['fragment']) && strlen($options['fragment']) == 0) { | |
unset($options['fragment']); | |
} | |
// Extract query parameters and fragment and merge them into $uri_options, | |
// but preserve the original $options for the fallback case. | |
$uri_options = $options; | |
if (isset($uri_parts['fragment'])) { | |
$uri_options += ['fragment' => $uri_parts['fragment']]; | |
unset($uri_parts['fragment']); | |
} | |
if (!empty($uri_parts['query'])) { | |
$uri_query = []; | |
parse_str($uri_parts['query'], $uri_query); | |
$uri_options['query'] = isset($uri_options['query']) ? $uri_options['query'] + $uri_query : $uri_query; | |
unset($uri_parts['query']); | |
} | |
if ($uri_parts['scheme'] === 'entity') { | |
$url = static::fromEntityUri($uri_parts, $uri_options, $uri); | |
} | |
elseif ($uri_parts['scheme'] === 'internal') { | |
$url = static::fromInternalUri($uri_parts, $uri_options); | |
} | |
elseif ($uri_parts['scheme'] === 'route') { | |
$url = static::fromRouteUri($uri_parts, $uri_options, $uri); | |
} | |
else { | |
$url = new static($uri, array(), $options); | |
if ($uri_parts['scheme'] !== 'base') { | |
$url->external = TRUE; | |
$url->setOption('external', TRUE); | |
} | |
$url->setUnrouted(); | |
} | |
return $url; | |
} | |
/** | |
* Create a new Url object for entity URIs. | |
* | |
* @param array $uri_parts | |
* Parts from an URI of the form entity:{entity_type}/{entity_id} as from | |
* parse_url(). | |
* @param array $options | |
* An array of options, see static::fromUri() for details. | |
* @param string $uri | |
* The original entered URI. | |
* | |
* @return \Drupal\Core\Url | |
* A new Url object for an entity's canonical route. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown if the entity URI is invalid. | |
*/ | |
protected static function fromEntityUri(array $uri_parts, array $options, $uri) { | |
list($entity_type_id, $entity_id) = explode('/', $uri_parts['path'], 2); | |
if ($uri_parts['scheme'] != 'entity' || $entity_id === '') { | |
throw new \InvalidArgumentException("The entity URI '$uri' is invalid. You must specify the entity id in the URL. e.g., entity:node/1 for loading the canonical path to node entity with id 1."); | |
} | |
return new static("entity.$entity_type_id.canonical", [$entity_type_id => $entity_id], $options); | |
} | |
/** | |
* Creates a new Url object for 'internal:' URIs. | |
* | |
* Important note: the URI minus the scheme can NOT simply be validated by a | |
* \Drupal\Core\Path\PathValidatorInterface implementation. The semantics of | |
* the 'internal:' URI scheme are different: | |
* - PathValidatorInterface accepts paths without a leading slash (e.g. | |
* 'node/add') as well as 2 special paths: '<front>' and '<none>', which are | |
* mapped to the correspondingly named routes. | |
* - 'internal:' URIs store paths with a leading slash that represents the | |
* root — i.e. the front page — (e.g. 'internal:/node/add'), and doesn't | |
* have any exceptions. | |
* | |
* To clarify, a few examples of path plus corresponding 'internal:' URI: | |
* - 'node/add' -> 'internal:/node/add' | |
* - 'node/add?foo=bar' -> 'internal:/node/add?foo=bar' | |
* - 'node/add#kitten' -> 'internal:/node/add#kitten' | |
* - '<front>' -> 'internal:/' | |
* - '<front>foo=bar' -> 'internal:/?foo=bar' | |
* - '<front>#kitten' -> 'internal:/#kitten' | |
* - '<none>' -> 'internal:' | |
* - '<none>foo=bar' -> 'internal:?foo=bar' | |
* - '<none>#kitten' -> 'internal:#kitten' | |
* | |
* Therefore, when using a PathValidatorInterface to validate 'internal:' | |
* URIs, we must map: | |
* - 'internal:' (path component is '') to the special '<none>' path | |
* - 'internal:/' (path component is '/') to the special '<front>' path | |
* - 'internal:/some-path' (path component is '/some-path') to 'some-path' | |
* | |
* @param array $uri_parts | |
* Parts from an URI of the form internal:{path} as from parse_url(). | |
* @param array $options | |
* An array of options, see static::fromUri() for details. | |
* | |
* @return \Drupal\Core\Url | |
* A new Url object for a 'internal:' URI. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown when the URI's path component doesn't have a leading slash. | |
*/ | |
protected static function fromInternalUri(array $uri_parts, array $options) { | |
// Both PathValidator::getUrlIfValidWithoutAccessCheck() and 'base:' URIs | |
// only accept/contain paths without a leading slash, unlike 'internal:' | |
// URIs, for which the leading slash means "relative to Drupal root" and | |
// "relative to Symfony app root" (just like in Symfony/Drupal 8 routes). | |
if (empty($uri_parts['path'])) { | |
$uri_parts['path'] = '<none>'; | |
} | |
elseif ($uri_parts['path'] === '/') { | |
$uri_parts['path'] = '<front>'; | |
} | |
else { | |
if ($uri_parts['path'][0] !== '/') { | |
throw new \InvalidArgumentException("The internal path component '{$uri_parts['path']}' is invalid. Its path component must have a leading slash, e.g. internal:/foo."); | |
} | |
// Remove the leading slash. | |
$uri_parts['path'] = substr($uri_parts['path'], 1); | |
if (UrlHelper::isExternal($uri_parts['path'])) { | |
throw new \InvalidArgumentException("The internal path component '{$uri_parts['path']}' is external. You are not allowed to specify an external URL together with internal:/."); | |
} | |
} | |
$url = \Drupal::pathValidator() | |
->getUrlIfValidWithoutAccessCheck($uri_parts['path']) ?: static::fromUri('base:' . $uri_parts['path'], $options); | |
// Allow specifying additional options. | |
$url->setOptions($options + $url->getOptions()); | |
return $url; | |
} | |
/** | |
* Creates a new Url object for 'route:' URIs. | |
* | |
* @param array $uri_parts | |
* Parts from an URI of the form route:{route_name};{route_parameters} as | |
* from parse_url(), where the path is the route name optionally followed by | |
* a ";" followed by route parameters in key=value format with & separators. | |
* @param array $options | |
* An array of options, see static::fromUri() for details. | |
* @param string $uri | |
* The original passed in URI. | |
* | |
* @return \Drupal\Core\Url | |
* A new Url object for a 'route:' URI. | |
* | |
* @throws \InvalidArgumentException | |
* Thrown when the route URI does not have a route name. | |
*/ | |
protected static function fromRouteUri(array $uri_parts, array $options, $uri) { | |
$route_parts = explode(';', $uri_parts['path'], 2); | |
$route_name = $route_parts[0]; | |
if ($route_name === '') { | |
throw new \InvalidArgumentException("The route URI '$uri' is invalid. You must have a route name in the URI. e.g., route:system.admin"); | |
} | |
$route_parameters = []; | |
if (!empty($route_parts[1])) { | |
parse_str($route_parts[1], $route_parameters); | |
} | |
return new static($route_name, $route_parameters, $options); | |
} | |
/** | |
* Returns the Url object matching a request. | |
* | |
* SECURITY NOTE: The request path is not checked to be valid and accessible | |
* by the current user to allow storing and reusing Url objects by different | |
* users. The 'path.validator' service getUrlIfValid() method should be used | |
* instead of this one if validation and access check is desired. Otherwise, | |
* 'access_manager' service checkNamedRoute() method should be used on the | |
* router name and parameters stored in the Url object returned by this | |
* method. | |
* | |
* @param \Symfony\Component\HttpFoundation\Request $request | |
* A request object. | |
* | |
* @return static | |
* A Url object. Warning: the object is created even if the current user | |
* would get an access denied running the same request via the normal page | |
* flow. | |
* | |
* @throws \Drupal\Core\Routing\MatchingRouteNotFoundException | |
* Thrown when the request cannot be matched. | |
*/ | |
public static function createFromRequest(Request $request) { | |
// We use the router without access checks because URL objects might be | |
// created and stored for different users. | |
$result = \Drupal::service('router.no_access_checks')->matchRequest($request); | |
$route_name = $result[RouteObjectInterface::ROUTE_NAME]; | |
$route_parameters = $result['_raw_variables']->all(); | |
return new static($route_name, $route_parameters); | |
} | |
/** | |
* Sets this Url to encapsulate an unrouted URI. | |
* | |
* @return $this | |
*/ | |
protected function setUnrouted() { | |
$this->unrouted = TRUE; | |
// What was passed in as the route name is actually the URI. | |
// @todo Consider fixing this in https://www.drupal.org/node/2346787. | |
$this->uri = $this->routeName; | |
// Set empty route name and parameters. | |
$this->routeName = NULL; | |
$this->routeParameters = array(); | |
return $this; | |
} | |
/** | |
* Generates a URI string that represents tha data in the Url object. | |
* | |
* The URI will typically have the scheme of route: even if the object was | |
* constructed using an entity: or internal: scheme. A internal: URI that | |
* does not match a Drupal route with be returned here with the base: scheme, | |
* and external URLs will be returned in their original form. | |
* | |
* @return string | |
* A URI representation of the Url object data. | |
*/ | |
public function toUriString() { | |
if ($this->isRouted()) { | |
$uri = 'route:' . $this->routeName; | |
if ($this->routeParameters) { | |
$uri .= ';' . UrlHelper::buildQuery($this->routeParameters); | |
} | |
} | |
else { | |
$uri = $this->uri; | |
} | |
$query = !empty($this->options['query']) ? ('?' . UrlHelper::buildQuery($this->options['query'])) : ''; | |
$fragment = isset($this->options['fragment']) && strlen($this->options['fragment']) ? '#' . $this->options['fragment'] : ''; | |
return $uri . $query . $fragment; | |
} | |
/** | |
* Indicates if this Url is external. | |
* | |
* @return bool | |
*/ | |
public function isExternal() { | |
return $this->external; | |
} | |
/** | |
* Indicates if this Url has a Drupal route. | |
* | |
* @return bool | |
*/ | |
public function isRouted() { | |
return !$this->unrouted; | |
} | |
/** | |
* Returns the route name. | |
* | |
* @return string | |
* | |
* @throws \UnexpectedValueException. | |
* If this is a URI with no corresponding route. | |
*/ | |
public function getRouteName() { | |
if ($this->unrouted) { | |
throw new \UnexpectedValueException('External URLs do not have an internal route name.'); | |
} | |
return $this->routeName; | |
} | |
/** | |
* Returns the route parameters. | |
* | |
* @return array | |
* | |
* @throws \UnexpectedValueException. | |
* If this is a URI with no corresponding route. | |
*/ | |
public function getRouteParameters() { | |
if ($this->unrouted) { | |
throw new \UnexpectedValueException('External URLs do not have internal route parameters.'); | |
} | |
return $this->routeParameters; | |
} | |
/** | |
* Sets the route parameters. | |
* | |
* @param array $parameters | |
* The array of parameters. | |
* | |
* @return $this | |
* | |
* @throws \UnexpectedValueException. | |
* If this is a URI with no corresponding route. | |
*/ | |
public function setRouteParameters($parameters) { | |
if ($this->unrouted) { | |
throw new \UnexpectedValueException('External URLs do not have route parameters.'); | |
} | |
$this->routeParameters = $parameters; | |
return $this; | |
} | |
/** | |
* Sets a specific route parameter. | |
* | |
* @param string $key | |
* The key of the route parameter. | |
* @param mixed $value | |
* The route parameter. | |
* | |
* @return $this | |
* | |
* @throws \UnexpectedValueException. | |
* If this is a URI with no corresponding route. | |
*/ | |
public function setRouteParameter($key, $value) { | |
if ($this->unrouted) { | |
throw new \UnexpectedValueException('External URLs do not have route parameters.'); | |
} | |
$this->routeParameters[$key] = $value; | |
return $this; | |
} | |
/** | |
* Returns the URL options. | |
* | |
* @return array | |
*/ | |
public function getOptions() { | |
return $this->options; | |
} | |
/** | |
* Gets a specific option. | |
* | |
* @param string $name | |
* The name of the option. | |
* | |
* @return mixed | |
* The value for a specific option, or NULL if it does not exist. | |
*/ | |
public function getOption($name) { | |
if (!isset($this->options[$name])) { | |
return NULL; | |
} | |
return $this->options[$name]; | |
} | |
/** | |
* Sets the URL options. | |
* | |
* @param array $options | |
* The array of options. | |
* | |
* @return $this | |
*/ | |
public function setOptions($options) { | |
$this->options = $options; | |
return $this; | |
} | |
/** | |
* Sets a specific option. | |
* | |
* @param string $name | |
* The name of the option. | |
* @param mixed $value | |
* The option value. | |
* | |
* @return $this | |
*/ | |
public function setOption($name, $value) { | |
$this->options[$name] = $value; | |
return $this; | |
} | |
/** | |
* Returns the URI value for this Url object. | |
* | |
* Only to be used if self::$unrouted is TRUE. | |
* | |
* @return string | |
* A URI not connected to a route. May be an external URL. | |
* | |
* @throws \UnexpectedValueException | |
* Thrown when the URI was requested for a routed URL. | |
*/ | |
public function getUri() { | |
if (!$this->unrouted) { | |
throw new \UnexpectedValueException('This URL has a Drupal route, so the canonical form is not a URI.'); | |
} | |
return $this->uri; | |
} | |
/** | |
* Sets the value of the absolute option for this Url. | |
* | |
* @param bool $absolute | |
* (optional) Whether to make this Url absolute or not. Defaults to TRUE. | |
* | |
* @return $this | |
*/ | |
public function setAbsolute($absolute = TRUE) { | |
$this->options['absolute'] = $absolute; | |
return $this; | |
} | |
/** | |
* Generates the string URL representation for this Url object. | |
* | |
* For an external URL, the string will contain the input plus any query | |
* string or fragment specified by the options array. | |
* | |
* If this Url object was constructed from a Drupal route or from an internal | |
* URI (URIs using the internal:, base:, or entity: schemes), the returned | |
* string will either be a relative URL like /node/1 or an absolute URL like | |
* http://example.com/node/1 depending on the options array, plus any | |
* specified query string or fragment. | |
* | |
* @param bool $collect_bubbleable_metadata | |
* (optional) Defaults to FALSE. When TRUE, both the generated URL and its | |
* associated bubbleable metadata are returned. | |
* | |
* @return string|\Drupal\Core\GeneratedUrl | |
* A string URL. | |
* When $collect_bubbleable_metadata is TRUE, a GeneratedUrl object is | |
* returned, containing the generated URL plus bubbleable metadata. | |
*/ | |
public function toString($collect_bubbleable_metadata = FALSE) { | |
if ($this->unrouted) { | |
return $this->unroutedUrlAssembler()->assemble($this->getUri(), $this->getOptions(), $collect_bubbleable_metadata); | |
} | |
return $this->urlGenerator()->generateFromRoute($this->getRouteName(), $this->getRouteParameters(), $this->getOptions(), $collect_bubbleable_metadata); | |
} | |
/** | |
* Returns the route information for a render array. | |
* | |
* @return array | |
* An associative array suitable for a render array. | |
*/ | |
public function toRenderArray() { | |
$render_array = [ | |
'#url' => $this, | |
'#options' => $this->getOptions(), | |
]; | |
if (!$this->unrouted) { | |
$render_array['#access_callback'] = [get_class(), 'renderAccess']; | |
} | |
return $render_array; | |
} | |
/** | |
* Returns the internal path (system path) for this route. | |
* | |
* This path will not include any prefixes, fragments, or query strings. | |
* | |
* @return string | |
* The internal path for this route. | |
* | |
* @throws \UnexpectedValueException. | |
* If this is a URI with no corresponding system path. | |
*/ | |
public function getInternalPath() { | |
if ($this->unrouted) { | |
throw new \UnexpectedValueException('Unrouted URIs do not have internal representations.'); | |
} | |
if (!isset($this->internalPath)) { | |
$this->internalPath = $this->urlGenerator()->getPathFromRoute($this->getRouteName(), $this->getRouteParameters()); | |
} | |
return $this->internalPath; | |
} | |
/** | |
* Checks this Url object against applicable access check services. | |
* | |
* Determines whether the route is accessible or not. | |
* | |
* @param \Drupal\Core\Session\AccountInterface $account | |
* (optional) Run access checks for this account. Defaults to the current | |
* user. | |
* | |
* @return bool | |
* Returns TRUE if the user has access to the url, otherwise FALSE. | |
*/ | |
public function access(AccountInterface $account = NULL) { | |
if ($this->isRouted()) { | |
return $this->accessManager()->checkNamedRoute($this->getRouteName(), $this->getRouteParameters(), $account); | |
} | |
return TRUE; | |
} | |
/** | |
* Checks a Url render element against applicable access check services. | |
* | |
* @param array $element | |
* A render element as returned from \Drupal\Core\Url::toRenderArray(). | |
* | |
* @return bool | |
* Returns TRUE if the current user has access to the url, otherwise FALSE. | |
*/ | |
public static function renderAccess(array $element) { | |
return $element['#url']->access(); | |
} | |
/** | |
* @return \Drupal\Core\Access\AccessManagerInterface | |
*/ | |
protected function accessManager() { | |
if (!isset($this->accessManager)) { | |
$this->accessManager = \Drupal::service('access_manager'); | |
} | |
return $this->accessManager; | |
} | |
/** | |
* Gets the URL generator. | |
* | |
* @return \Drupal\Core\Routing\UrlGeneratorInterface | |
* The URL generator. | |
*/ | |
protected function urlGenerator() { | |
if (!$this->urlGenerator) { | |
$this->urlGenerator = \Drupal::urlGenerator(); | |
} | |
return $this->urlGenerator; | |
} | |
/** | |
* Gets the unrouted URL assembler for non-Drupal URLs. | |
* | |
* @return \Drupal\Core\Utility\UnroutedUrlAssemblerInterface | |
* The unrouted URL assembler. | |
*/ | |
protected function unroutedUrlAssembler() { | |
if (!$this->urlAssembler) { | |
$this->urlAssembler = \Drupal::service('unrouted_url_assembler'); | |
} | |
return $this->urlAssembler; | |
} | |
/** | |
* Sets the URL generator. | |
* | |
* @param \Drupal\Core\Routing\UrlGeneratorInterface | |
* (optional) The URL generator, specify NULL to reset it. | |
* | |
* @return $this | |
*/ | |
public function setUrlGenerator(UrlGeneratorInterface $url_generator = NULL) { | |
$this->urlGenerator = $url_generator; | |
$this->internalPath = NULL; | |
return $this; | |
} | |
/** | |
* Sets the unrouted URL assembler. | |
* | |
* @param \Drupal\Core\Utility\UnroutedUrlAssemblerInterface | |
* The unrouted URL assembler. | |
* | |
* @return $this | |
*/ | |
public function setUnroutedUrlAssembler(UnroutedUrlAssemblerInterface $url_assembler) { | |
$this->urlAssembler = $url_assembler; | |
return $this; | |
} | |
} |