Expanded class hierarchy of AliasManager
class AliasManager implements AliasManagerInterface {
/**
* The database connectino to use for path lookups.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The Key/Value Store to use for state
*
* @var \Drupal\Core\KeyValueStore\DatabaseStorage
*/
protected $state;
/**
* The default langcode to use when none is specified for path lookups.
*
* @var string
*/
protected $langcode;
/**
* Holds the map of path lookups per language.
*
* @var array
*/
protected $lookupMap = array();
/**
* Holds an array of path alias for which no source was found.
*
* @var array
*/
protected $noSource = array();
/**
* Holds the array of whitelisted path aliases.
*
* @var array
*/
protected $whitelist;
/**
* Holds an array of system paths that have no aliases.
*
* @var array
*/
protected $noAliases = array();
/**
* Whether lookupPath() has not yet been called.
*
* @var boolean
*/
protected $firstLookup = TRUE;
/**
* Holds an array of previously looked up paths for the current request path.
*
* This will only ever get populated if the alias manager is being used in
* the context of a request.
*
* @var array
*/
protected $preloadedPathLookups = array();
public function __construct(Connection $connection, KeyValueFactory $keyvalue) {
$this->connection = $connection;
$this->state = $keyvalue
->get('state');
$this->langcode = language(LANGUAGE_TYPE_URL)->langcode;
$this->whitelist = $this->state
->get('system.path_alias_whitelist', NULL);
if (!isset($this->whitelist)) {
$this->whitelist = $this
->pathAliasWhitelistRebuild();
}
}
/**
* Implements \Drupal\Core\Path\AliasManagerInterface::getSystemPath().
*/
public function getSystemPath($path, $path_language = NULL) {
// If no language is explicitly specified we default to the current URL
// language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path
// alias matching the URL path.
$path_language = $path_language ?: $this->langcode;
$original_path = $path;
// Lookup the path alias first.
if (!empty($path) && ($source = $this
->lookupPathSource($path, $path_language))) {
$path = $source;
}
return $path;
}
/**
* Implements \Drupal\Core\Path\AliasManagerInterface::getPathAlias().
*/
public function getPathAlias($path, $path_language = NULL) {
// If no language is explicitly specified we default to the current URL
// language. If we used a language different from the one conveyed by the
// requested URL, we might end up being unable to check if there is a path
// alias matching the URL path.
$path_language = $path_language ?: $this->langcode;
$result = $path;
if (!empty($path) && ($alias = $this
->lookupPathAlias($path, $path_language))) {
$result = $alias;
}
return $result;
}
/**
* Implements \Drupal\Core\Path\AliasManagerInterface::cacheClear().
*/
public function cacheClear($source = NULL) {
$this->lookupMap = array();
$this->noSource = array();
$this->no_aliases = array();
$this->firstCall = TRUE;
$this->preloadedPathLookups = array();
$this->whitelist = $this
->pathAliasWhitelistRebuild($source);
}
/**
* Implements \Drupal\Core\Path\AliasManagerInterface::getPathLookups().
*/
public function getPathLookups() {
$current = current($this->lookupMap);
if ($current) {
return array_keys($current);
}
return array();
}
/**
* Implements \Drupal\Core\Path\AliasManagerInterface::preloadPathLookups().
*/
public function preloadPathLookups(array $path_list) {
$this->preloadedPathLookups = $path_list;
}
/**
* Given a Drupal system URL return one of its aliases if such a one exists.
* Otherwise, return FALSE.
* @param $path
* The path to investigate for corresponding aliases.
* @param $langcode
* Optional language code to search the path with. Defaults to the page language.
* If there's no path defined for that language it will search paths without
* language.
*
* @return
* An aliased path, or FALSE if no path was found.
*/
protected function lookupPathAlias($path, $langcode) {
// During the first call to this method per language, load the expected
// system paths for the page from cache.
if (!empty($this->firstLookup)) {
$this->firstLookup = FALSE;
$this->lookupMap[$langcode] = array();
// Load system paths from cache.
if (!empty($this->preloadedPathLookups)) {
// Now fetch the aliases corresponding to these system paths.
$args = array(
':system' => $this->preloadedPathLookups,
':langcode' => $langcode,
':langcode_undetermined' => LANGUAGE_NOT_SPECIFIED,
);
// Always get the language-specific alias before the language-neutral
// one. For example 'de' is less than 'und' so the order needs to be
// ASC, while 'xx-lolspeak' is more than 'und' so the order needs to
// be DESC. We also order by pid ASC so that fetchAllKeyed() returns
// the most recently created alias for each source. Subsequent queries
// using fetchField() must use pid DESC to have the same effect.
// For performance reasons, the query builder is not used here.
if ($langcode == LANGUAGE_NOT_SPECIFIED) {
// Prevent PDO from complaining about a token the query doesn't use.
unset($args[':langcode']);
$result = $this->connection
->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode = :langcode_undetermined ORDER BY pid ASC', $args);
}
elseif ($langcode < LANGUAGE_NOT_SPECIFIED) {
$result = $this->connection
->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid ASC', $args);
}
else {
$result = $this->connection
->query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid ASC', $args);
}
$this->lookupMap[$langcode] = $result
->fetchAllKeyed();
// Keep a record of paths with no alias to avoid querying twice.
$this->noAliases[$langcode] = array_flip(array_diff_key($this->preloadedPathLookups, array_keys($this->lookupMap[$langcode])));
}
}
// If the alias has already been loaded, return it.
if (isset($this->lookupMap[$langcode][$path])) {
return $this->lookupMap[$langcode][$path];
}
elseif (!isset($this->whitelist[strtok($path, '/')])) {
return FALSE;
}
elseif (!isset($this->noAliases[$langcode][$path])) {
$args = array(
':source' => $path,
':langcode' => $langcode,
':langcode_undetermined' => LANGUAGE_NOT_SPECIFIED,
);
// See the queries above.
if ($langcode == LANGUAGE_NOT_SPECIFIED) {
unset($args[':langcode']);
$alias = $this->connection
->query("SELECT alias FROM {url_alias} WHERE source = :source AND langcode = :langcode_undetermined ORDER BY pid DESC", $args)
->fetchField();
}
elseif ($langcode > LANGUAGE_NOT_SPECIFIED) {
$alias = $this->connection
->query("SELECT alias FROM {url_alias} WHERE source = :source AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid DESC", $args)
->fetchField();
}
else {
$alias = $this->connection
->query("SELECT alias FROM {url_alias} WHERE source = :source AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid DESC", $args)
->fetchField();
}
$this->lookupMap[$langcode][$path] = $alias;
return $alias;
}
return FALSE;
}
/**
* Given an alias, return its Drupal system URL if one exists. Otherwise,
* return FALSE.
*
* @param $path
* The path to investigate for corresponding system URLs.
* @param $langcode
* Optional language code to search the path with. Defaults to the page language.
* If there's no path defined for that language it will search paths without
* language.
*
* @return
* A Drupal system path, or FALSE if no path was found.
*/
protected function lookupPathSource($path, $langcode) {
if ($this->whitelist && !isset($this->noSource[$langcode][$path])) {
// Look for the value $path within the cached $map
$source = FALSE;
if (!isset($this->lookupMap[$langcode]) || !($source = array_search($path, $this->lookupMap[$langcode]))) {
$args = array(
':alias' => $path,
':langcode' => $langcode,
':langcode_undetermined' => LANGUAGE_NOT_SPECIFIED,
);
// See the queries above.
if ($langcode == LANGUAGE_NOT_SPECIFIED) {
unset($args[':langcode']);
$result = $this->connection
->query("SELECT source FROM {url_alias} WHERE alias = :alias AND langcode = :langcode_undetermined ORDER BY pid DESC", $args);
}
elseif ($langcode > LANGUAGE_NOT_SPECIFIED) {
$result = $this->connection
->query("SELECT source FROM {url_alias} WHERE alias = :alias AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid DESC", $args);
}
else {
$result = $this->connection
->query("SELECT source FROM {url_alias} WHERE alias = :alias AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid DESC", $args);
}
if ($source = $result
->fetchField()) {
$this->lookupMap[$langcode][$source] = $path;
}
else {
// We can't record anything into $map because we do not have a valid
// index and there is no need because we have not learned anything
// about any Drupal path. Thus cache to $no_source.
$this->noSource[$langcode][$path] = TRUE;
}
}
return $source;
}
return FALSE;
}
/**
* Rebuild the path alias white list.
*
* @param $source
* An optional system path for which an alias is being inserted.
*
* @return
* An array containing a white list of path aliases.
*/
protected function pathAliasWhitelistRebuild($source = NULL) {
// When paths are inserted, only rebuild the whitelist if the system path
// has a top level component which is not already in the whitelist.
if (!empty($source)) {
// @todo Inject state so we don't have this function call.
$whitelist = $this->state
->get('system.path_alias_whitelist', NULL);
if (isset($whitelist[strtok($source, '/')])) {
return $whitelist;
}
}
// For each alias in the database, get the top level component of the system
// path it corresponds to. This is the portion of the path before the first
// '/', if present, otherwise the whole path itself.
$whitelist = array();
$result = $this->connection
->query("SELECT DISTINCT SUBSTRING_INDEX(source, '/', 1) AS path FROM {url_alias}");
foreach ($result as $row) {
$whitelist[$row->path] = TRUE;
}
$this->state
->set('system.path_alias_whitelist', $whitelist);
return $whitelist;
}
}
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
AliasManager:: |
public | function | ||
AliasManager:: |
protected | function | Given a Drupal system URL return one of its aliases if such a one exists. Otherwise, return FALSE. | |
AliasManager:: |
protected | function | Given an alias, return its Drupal system URL if one exists. Otherwise, return FALSE. | |
AliasManager:: |
protected | property | Holds an array of path alias for which no source was found. | |
AliasManager:: |
protected | property | Holds an array of previously looked up paths for the current request path. | |
AliasManager:: |
protected | property | Holds an array of system paths that have no aliases. | |
AliasManager:: |
protected | property | Holds the array of whitelisted path aliases. | |
AliasManager:: |
protected | property | Holds the map of path lookups per language. | |
AliasManager:: |
public | function | Implements \Drupal\Core\Path\AliasManagerInterface::cacheClear(). | |
AliasManager:: |
public | function |
Implements \Drupal\Core\Path\AliasManagerInterface::getPathAlias(). Overrides AliasManagerInterface:: |
|
AliasManager:: |
public | function |
Implements \Drupal\Core\Path\AliasManagerInterface::getPathLookups(). Overrides AliasManagerInterface:: |
|
AliasManager:: |
public | function |
Implements \Drupal\Core\Path\AliasManagerInterface::getSystemPath(). Overrides AliasManagerInterface:: |
|
AliasManager:: |
public | function |
Implements \Drupal\Core\Path\AliasManagerInterface::preloadPathLookups(). Overrides AliasManagerInterface:: |
|
AliasManager:: |
protected | function | Rebuild the path alias white list. | |
AliasManager:: |
protected | property | The database connectino to use for path lookups. | |
AliasManager:: |
protected | property | The default langcode to use when none is specified for path lookups. | |
AliasManager:: |
protected | property | The Key/Value Store to use for state | |
AliasManager:: |
protected | property | Whether lookupPath() has not yet been called. |