summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDries2012-11-21 15:29:04 (GMT)
committerDries2012-11-21 15:29:04 (GMT)
commite3d863834cd901bf6cd7ec9711b0438c37bdc576 (patch)
tree80fe06fd0af39c41779aaa83c16f1bc415925c01
parentdaf490d3a42950a11764e78ab4c36383db1ff383 (diff)
Issue #1269742 by katbailey, beejeebus, pwolanin, g.oechsler, ksenzee: Make path lookup code into an pluggable class.
-rw-r--r--core/includes/bootstrap.inc4
-rw-r--r--core/includes/common.inc5
-rw-r--r--core/includes/menu.inc2
-rw-r--r--core/includes/path.inc397
-rw-r--r--core/lib/Drupal/Core/CacheDecorator/AliasManagerCacheDecorator.php124
-rw-r--r--core/lib/Drupal/Core/CacheDecorator/CacheDecoratorInterface.php25
-rw-r--r--core/lib/Drupal/Core/CoreBundle.php16
-rw-r--r--core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php25
-rw-r--r--core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php3
-rw-r--r--core/lib/Drupal/Core/ExceptionController.php4
-rw-r--r--core/lib/Drupal/Core/Path/AliasManager.php320
-rw-r--r--core/lib/Drupal/Core/Path/AliasManagerInterface.php57
-rw-r--r--core/lib/Drupal/Core/Path/Path.php144
-rw-r--r--core/modules/block/block.module2
-rw-r--r--core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php12
-rw-r--r--core/modules/menu/menu.admin.inc2
-rw-r--r--core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php6
-rw-r--r--core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php16
-rw-r--r--core/modules/path/path.admin.inc16
-rw-r--r--core/modules/path/path.api.php6
-rw-r--r--core/modules/path/path.module36
-rw-r--r--core/modules/search/search.module2
-rw-r--r--core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php4
-rw-r--r--core/modules/shortcut/shortcut.admin.inc6
-rw-r--r--core/modules/shortcut/shortcut.module2
-rw-r--r--core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php6
-rw-r--r--core/modules/statistics/statistics.module2
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php2
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php165
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/LookupTest.php100
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/SaveTest.php63
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php91
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Path/UrlAlterFunctionalTest.php36
-rw-r--r--core/modules/system/system.admin.inc9
-rw-r--r--core/modules/system/system.api.php2
-rw-r--r--core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/PathSubscriber.php59
-rw-r--r--core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/UrlAlterTestBundle.php27
-rw-r--r--core/modules/system/tests/modules/url_alter_test/url_alter_test.module26
-rw-r--r--core/modules/views/views_ui/views_ui.module2
-rw-r--r--core/scripts/generate-d7-content.sh2
40 files changed, 1147 insertions, 681 deletions
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index ef53eaf..a991ed1 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -2490,6 +2490,10 @@ function drupal_container(Container $new_container = NULL, $rebuild = FALSE) {
->register('keyvalue.database', 'Drupal\Core\KeyValueStore\KeyValueDatabaseFactory')
->addArgument(new Reference('database'));
+ $container->register('path.alias_manager', 'Drupal\Core\Path\AliasManager')
+ ->addArgument(new Reference('database'))
+ ->addArgument(new Reference('keyvalue.database'));
+
// Register the EntityManager.
$container->register('plugin.manager.entity', 'Drupal\Core\Entity\EntityManager');
}
diff --git a/core/includes/common.inc b/core/includes/common.inc
index f8a54e9..1eb3b94 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2208,7 +2208,7 @@ function url($path = NULL, array $options = array()) {
}
elseif (!empty($path) && !$options['alias']) {
$langcode = isset($options['language']) && isset($options['language']->langcode) ? $options['language']->langcode : '';
- $alias = drupal_get_path_alias($original_path, $langcode);
+ $alias = drupal_container()->get('path.alias_manager')->getPathAlias($original_path, $langcode);
if ($alias != $original_path) {
$path = $alias;
}
@@ -4922,9 +4922,6 @@ function _drupal_bootstrap_full($skip = FALSE) {
// current_path().
drupal_language_initialize();
- // Initialize current_path() prior to invoking hook_init().
- drupal_path_initialize();
-
// Let all modules take action before the menu system handles the request.
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 091d898..2e55366 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -2994,7 +2994,7 @@ function _menu_delete_item($item, $force = FALSE) {
* @param $item
* An associative array representing a menu link item, with elements:
* - link_path: (required) The path of the menu item, which should be
- * normalized first by calling drupal_get_normal_path() on it.
+ * normalized first by calling drupal_container()->get('path.alias_manager')->getSystemPath() on it.
* - link_title: (required) Title to appear in menu for the link.
* - menu_name: (optional) The machine name of the menu for the link.
* Defaults to 'tools'.
diff --git a/core/includes/path.inc b/core/includes/path.inc
index dc878c0..ba7c034 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -2,7 +2,7 @@
/**
* @file
- * Functions to handle paths in Drupal, including path aliasing.
+ * Functions to handle paths in Drupal.
*
* These functions are not loaded for cached pages, but modules that need
* to use them in hook_boot() or hook exit() can make them available, by
@@ -10,289 +10,6 @@
*/
/**
- * Initializes the current path to the proper normal path.
- */
-function drupal_path_initialize() {
- // At this point, the current path is either the request path (due to
- // drupal_environment_initialize()) or some modified version of it due to
- // other bootstrap code (e.g., language negotiation), but it has not yet been
- // normalized by drupal_get_normal_path().
- $path = _current_path();
-
- // If on the front page, resolve to the front page path, including for calls
- // to current_path() while drupal_get_normal_path() is in progress.
- if (empty($path)) {
- $path = config('system.site')->get('page.front');
- _current_path($path);
- }
-
- // Normalize the path.
- _current_path(drupal_get_normal_path($path));
-}
-
-/**
- * Given an alias, return its Drupal system URL if one exists. Given a Drupal
- * system URL return one of its aliases if such a one exists. Otherwise,
- * return FALSE.
- *
- * @param $action
- * One of the following values:
- * - wipe: delete the alias cache.
- * - alias: return an alias for a given Drupal system path (if one exists).
- * - source: return the Drupal system URL for a path alias (if one exists).
- * @param $path
- * The path to investigate for corresponding aliases or 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
- * Either a Drupal system path, an aliased path, or FALSE if no path was
- * found.
- */
-function drupal_lookup_path($action, $path = '', $langcode = NULL) {
- // Use the advanced drupal_static() pattern, since this is called very often.
- static $drupal_static_fast;
- if (!isset($drupal_static_fast)) {
- $drupal_static_fast['cache'] = &drupal_static(__FUNCTION__);
- }
- $cache = &$drupal_static_fast['cache'];
-
- if (!isset($cache)) {
- $cache = array(
- 'map' => array(),
- 'no_source' => array(),
- 'whitelist' => NULL,
- 'system_paths' => array(),
- 'no_aliases' => array(),
- 'first_call' => TRUE,
- );
- }
-
- // Retrieve the path alias whitelist.
- if (!isset($cache['whitelist'])) {
- $cache['whitelist'] = state()->get('system.path_alias_whitelist', NULL);
- if (!isset($cache['whitelist'])) {
- $cache['whitelist'] = drupal_path_alias_whitelist_rebuild();
- }
- }
-
- // 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.
- $langcode = $langcode ? $langcode : language(LANGUAGE_TYPE_URL)->langcode;
-
- if ($action == 'wipe') {
- $cache = array();
- $cache['whitelist'] = drupal_path_alias_whitelist_rebuild();
- }
- elseif ($cache['whitelist'] && $path != '') {
- if ($action == 'alias') {
- // During the first call to drupal_lookup_path() per language, load the
- // expected system paths for the page from cache.
- if (!empty($cache['first_call'])) {
- $cache['first_call'] = FALSE;
-
- $cache['map'][$langcode] = array();
- // Load system paths from cache.
- $cid = current_path();
- if ($cached = cache('path')->get($cid)) {
- $cache['system_paths'] = $cached->data;
- // Now fetch the aliases corresponding to these system paths.
- $args = array(
- ':system' => $cache['system_paths'],
- ':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 = db_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 = db_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 = db_query('SELECT source, alias FROM {url_alias} WHERE source IN (:system) AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid ASC', $args);
- }
- $cache['map'][$langcode] = $result->fetchAllKeyed();
- // Keep a record of paths with no alias to avoid querying twice.
- $cache['no_aliases'][$langcode] = array_flip(array_diff_key($cache['system_paths'], array_keys($cache['map'][$langcode])));
- }
- }
- // If the alias has already been loaded, return it.
- if (isset($cache['map'][$langcode][$path])) {
- return $cache['map'][$langcode][$path];
- }
- // Check the path whitelist, if the top_level part before the first /
- // is not in the list, then there is no need to do anything further,
- // it is not in the database.
- elseif (!isset($cache['whitelist'][strtok($path, '/')])) {
- return FALSE;
- }
- // For system paths which were not cached, query aliases individually.
- elseif (!isset($cache['no_aliases'][$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 = db_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 = db_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 = db_query("SELECT alias FROM {url_alias} WHERE source = :source AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode ASC, pid DESC", $args)->fetchField();
- }
- $cache['map'][$langcode][$path] = $alias;
- return $alias;
- }
- }
- // Check $no_source for this $path in case we've already determined that there
- // isn't a path that has this alias
- elseif ($action == 'source' && !isset($cache['no_source'][$langcode][$path])) {
- // Look for the value $path within the cached $map
- $source = FALSE;
- if (!isset($cache['map'][$langcode]) || !($source = array_search($path, $cache['map'][$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 = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND langcode = :langcode_undetermined ORDER BY pid DESC", $args);
- }
- elseif ($langcode > LANGUAGE_NOT_SPECIFIED) {
- $result = db_query("SELECT source FROM {url_alias} WHERE alias = :alias AND langcode IN (:langcode, :langcode_undetermined) ORDER BY langcode DESC, pid DESC", $args);
- }
- else {
- $result = db_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()) {
- $cache['map'][$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.
- $cache['no_source'][$langcode][$path] = TRUE;
- }
- }
- return $source;
- }
- }
-
- return FALSE;
-}
-
-/**
- * Cache system paths for a page.
- *
- * Cache an array of the system paths available on each page. We assume
- * that aliases will be needed for the majority of these paths during
- * subsequent requests, and load them in a single query during
- * drupal_lookup_path().
- */
-function drupal_cache_system_paths() {
- // Check if the system paths for this page were loaded from cache in this
- // request to avoid writing to cache on every request.
- $cache = &drupal_static('drupal_lookup_path', array());
- if (empty($cache['system_paths']) && !empty($cache['map'])) {
-
- // @todo Because we are not within the request scope at this time, we cannot
- // use current_path(), which would give us the system path to use as the
- // key. Instead we call _current_path(), which may give us the alias
- // instead. However, at lookup time the system path will be used as the
- // key, because it uses current_path(), and so it will be a cache miss.
- // There is a critical issue for fixing the path alias logic here:
- // http://drupal.org/node/1269742
-
- // Generate a cache ID (cid) specifically for this page.
- $cid = _current_path();
- // The static $map array used by drupal_lookup_path() includes all
- // system paths for the page request.
- if ($paths = current($cache['map'])) {
- $data = array_keys($paths);
- $expire = REQUEST_TIME + (60 * 60 * 24);
- cache('path')->set($cid, $data, $expire);
- }
- }
-}
-
-/**
- * Given an internal Drupal path, return the alias set by the administrator.
- *
- * If no path is provided, the function will return the alias of the current
- * page.
- *
- * @param $path
- * An internal Drupal path.
- * @param $langcode
- * An optional language code to look up the path in.
- *
- * @return
- * An aliased path if one was found, or the original path if no alias was
- * found.
- */
-function drupal_get_path_alias($path = NULL, $langcode = NULL) {
- // If no path is specified, use the current page's path.
- if ($path == NULL) {
- $path = current_path();
- }
- $result = $path;
- if ($alias = drupal_lookup_path('alias', $path, $langcode)) {
- $result = $alias;
- }
- return $result;
-}
-
-/**
- * Given a path alias, return the internal path it represents.
- *
- * @param $path
- * A Drupal path alias.
- * @param $langcode
- * An optional language code to look up the path in.
- *
- * @return
- * The internal path represented by the alias, or the original alias if no
- * internal path was found.
- */
-function drupal_get_normal_path($path, $langcode = NULL) {
- $original_path = $path;
-
- // Lookup the path alias first.
- if ($source = drupal_lookup_path('source', $path, $langcode)) {
- $path = $source;
- }
-
- // Allow other modules to alter the inbound URL. We cannot use drupal_alter()
- // here because we need to run hook_url_inbound_alter() in the reverse order
- // of hook_url_outbound_alter().
- foreach (array_reverse(module_implements('url_inbound_alter')) as $module) {
- $function = $module . '_url_inbound_alter';
- $function($path, $original_path, $langcode);
- }
-
- return $path;
-}
-
-/**
* Check if the current page is the front page.
*
* @return
@@ -379,49 +96,13 @@ function current_path() {
}
/**
- * 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.
- */
-function drupal_path_alias_whitelist_rebuild($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)) {
- $whitelist = 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 = db_query("SELECT DISTINCT SUBSTRING_INDEX(source, '/', 1) AS path FROM {url_alias}");
- foreach ($result as $row) {
- $whitelist[$row->path] = TRUE;
- }
- state()->set('system.path_alias_whitelist', $whitelist);
- return $whitelist;
-}
-
-/**
* Fetch a specific URL alias from the database.
*
* @param $conditions
* A string representing the source, a number representing the pid, or an
* array of query conditions.
*
- * @return
- * FALSE if no alias was found or an associative array containing the
- * following keys:
- * - source: The internal system path.
- * - alias: The URL alias.
- * - pid: Unique path alias identifier.
- * - langcode: The language code of the alias.
+ * @see \Drupal\Core\Path\Path::load()
*/
function path_load($conditions) {
if (is_numeric($conditions)) {
@@ -433,68 +114,7 @@ function path_load($conditions) {
elseif (!is_array($conditions)) {
return FALSE;
}
- $select = db_select('url_alias');
- foreach ($conditions as $field => $value) {
- $select->condition($field, $value);
- }
- return $select
- ->fields('url_alias')
- ->execute()
- ->fetchAssoc();
-}
-
-/**
- * Save a path alias to the database.
- *
- * @param $path
- * An associative array containing the following keys:
- * - source: The internal system path.
- * - alias: The URL alias.
- * - pid: (optional) Unique path alias identifier.
- * - langcode: (optional) The language code of the alias.
- */
-function path_save(&$path) {
- $path += array('langcode' => LANGUAGE_NOT_SPECIFIED);
-
- // Load the stored alias, if any.
- if (!empty($path['pid']) && !isset($path['original'])) {
- $path['original'] = path_load($path['pid']);
- }
-
- if (empty($path['pid'])) {
- drupal_write_record('url_alias', $path);
- module_invoke_all('path_insert', $path);
- }
- else {
- drupal_write_record('url_alias', $path, array('pid'));
- module_invoke_all('path_update', $path);
- }
-
- // Clear internal properties.
- unset($path['original']);
-
- // Clear the static alias cache.
- drupal_clear_path_cache($path['source']);
-}
-
-/**
- * Delete a URL alias.
- *
- * @param $criteria
- * A number representing the pid or an array of criteria.
- */
-function path_delete($criteria) {
- if (!is_array($criteria)) {
- $criteria = array('pid' => $criteria);
- }
- $path = path_load($criteria);
- $query = db_delete('url_alias');
- foreach ($criteria as $field => $value) {
- $query->condition($field, $value);
- }
- $query->execute();
- module_invoke_all('path_delete', $path);
- drupal_clear_path_cache($path['source']);
+ return drupal_container()->get('path.crud')->load($conditions);
}
/**
@@ -597,14 +217,3 @@ function drupal_valid_path($path, $dynamic_allowed = FALSE) {
return $item && $item['access'];
}
-/**
- * Clear the path cache.
- *
- * @param $source
- * An optional system path for which an alias is being changed.
- */
-function drupal_clear_path_cache($source = NULL) {
- // Clear the drupal_lookup_path() static cache.
- drupal_static_reset('drupal_lookup_path');
- drupal_path_alias_whitelist_rebuild($source);
-}
diff --git a/core/lib/Drupal/Core/CacheDecorator/AliasManagerCacheDecorator.php b/core/lib/Drupal/Core/CacheDecorator/AliasManagerCacheDecorator.php
new file mode 100644
index 0000000..ae5c8bc
--- /dev/null
+++ b/core/lib/Drupal/Core/CacheDecorator/AliasManagerCacheDecorator.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\CacheDecorator\AliasManagerCacheDecorator.
+ */
+
+namespace Drupal\Core\CacheDecorator;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Path\AliasManagerInterface;
+
+/**
+ * Class used by the PathSubscriber to get the system path and cache path lookups.
+ */
+class AliasManagerCacheDecorator implements CacheDecoratorInterface, AliasManagerInterface {
+
+ /**
+ * @var \Drupal\Core\Path\AliasManagerInterface
+ */
+ protected $aliasManager;
+
+ /**
+ * @var \Drupal\Core\Cache\CacheBackendInterface;
+ */
+ protected $cache;
+
+ /**
+ * Stack of request paths for use as cids when caching system paths.
+ *
+ * @var array
+ */
+ protected $cacheKeys = array();
+
+ /**
+ * Holds an array of previously cached paths based on a request path.
+ *
+ * @var array
+ */
+ protected $preloadedPathLookups = array();
+
+ /**
+ * Whether the cache needs to be written.
+ *
+ * @var boolean
+ */
+ protected $cacheNeedsWriting = TRUE;
+
+ /**
+ * Constructs a \Drupal\Core\CacheDecorator\AliasManagerCacheDecorator.
+ */
+ public function __construct(AliasManagerInterface $alias_manager, CacheBackendInterface $cache) {
+ $this->aliasManager = $alias_manager;
+ $this->cache = $cache;
+ }
+
+ /**
+ * Implements \Drupal\Core\CacheDecorator\CacheDecoratorInterface::setCacheKey().
+ */
+ public function setCacheKey($key) {
+ $this->cacheKeys[] = $key;
+ }
+
+ /**
+ * Implements \Drupal\Core\CacheDecorator\CacheDecoratorInterface::writeCache().
+ *
+ * Cache an array of the system paths available on each page. We assume
+ * that aliases will be needed for the majority of these paths during
+ * subsequent requests, and load them in a single query during path alias
+ * lookup.
+ */
+ public function writeCache() {
+ $path_lookups = $this->getPathLookups();
+ // Check if the system paths for this page were loaded from cache in this
+ // request to avoid writing to cache on every request.
+ if ($this->cacheNeedsWriting && !empty($path_lookups) && !empty($this->cacheKeys)) {
+ // Use the system path of the current request for the cache ID (cid).
+ $cid = end($this->cacheKeys);
+ // Set the path cache to expire in 24 hours.
+ $expire = REQUEST_TIME + (60 * 60 * 24);
+ $this->cache->set($cid, $path_lookups, $expire);
+ }
+ // We are at the end of the request, so pop off the last request path.
+ array_pop($this->cacheKeys);
+ }
+
+ /**
+ * Implements \Drupal\Core\Path\AliasManagerInterface::getSystemPath().
+ */
+ public function getSystemPath($path, $path_language = NULL) {
+ $system_path = $this->aliasManager->getSystemPath($path, $path_language);
+ // We need to pass on the list of previously cached system paths for this
+ // key to the alias manager for use in subsequent lookups.
+ $cached = $this->cache->get($system_path);
+ $cached_paths = array();
+ if ($cached) {
+ $cached_paths = $cached->data;
+ $this->cacheNeedsWriting = FALSE;
+ }
+ $this->preloadPathLookups($cached_paths);
+ return $system_path;
+ }
+
+ /**
+ * Implements \Drupal\Core\Path\AliasManagerInterface::getPathAlias().
+ */
+ public function getPathAlias($path, $path_language = NULL) {
+ return $this->aliasManager->getPathAlias($path, $path_language);
+ }
+
+ /**
+ * Implements \Drupal\Core\Path\AliasManagerInterface::getPathLookups().
+ */
+ public function getPathLookups() {
+ return $this->aliasManager->getPathLookups();
+ }
+
+ /**
+ * Implements \Drupal\Core\Path\AliasManagerInterface::preloadPathLookups().
+ */
+ public function preloadPathLookups(array $path_list) {
+ $this->aliasManager->preloadPathLookups($path_list);
+ }
+}
diff --git a/core/lib/Drupal/Core/CacheDecorator/CacheDecoratorInterface.php b/core/lib/Drupal/Core/CacheDecorator/CacheDecoratorInterface.php
new file mode 100644
index 0000000..574d81a
--- /dev/null
+++ b/core/lib/Drupal/Core/CacheDecorator/CacheDecoratorInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\CacheDecorator\CacheDecoratorInterface.
+ */
+
+namespace Drupal\Core\CacheDecorator;
+
+/**
+ * Defines an interface for cache decorator implementations.
+ */
+interface CacheDecoratorInterface {
+
+ /**
+ * Specify the key to use when writing the cache.
+ */
+ public function setCacheKey($key);
+
+ /**
+ * Write the cache.
+ */
+ public function writeCache();
+
+}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 48684e5..a32bf90 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -13,6 +13,7 @@ use Drupal\Core\DependencyInjection\Compiler\RegisterNestedMatchersPass;
use Drupal\Core\DependencyInjection\Compiler\RegisterSerializationClassesPass;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Scope;
use Symfony\Component\HttpKernel\Bundle\Bundle;
@@ -82,6 +83,20 @@ class CoreBundle extends Bundle
$container->register('nested_matcher', 'Drupal\Core\Routing\NestedMatcher')
->addTag('chained_matcher', array('priority' => 5));
+ $container
+ ->register('cache.path', 'Drupal\Core\Cache\CacheBackendInterface')
+ ->setFactoryClass('Drupal\Core\Cache\CacheFactory')
+ ->setFactoryMethod('get')
+ ->addArgument('path');
+
+ $container->register('path.alias_manager.cached', 'Drupal\Core\CacheDecorator\AliasManagerCacheDecorator')
+ ->addArgument(new Reference('path.alias_manager'))
+ ->addArgument(new Reference('cache.path'));
+
+ $container->register('path.crud', 'Drupal\Core\Path\Path')
+ ->addArgument(new Reference('database'))
+ ->addArgument(new Reference('path.alias_manager'));
+
// The following services are tagged as 'nested_matcher' services and are
// processed in the RegisterNestedMatchersPass compiler pass. Each one
// needs to be set on the matcher using a different method, so we use a
@@ -110,6 +125,7 @@ class CoreBundle extends Bundle
$container->register('maintenance_mode_subscriber', 'Drupal\Core\EventSubscriber\MaintenanceModeSubscriber')
->addTag('event_subscriber');
$container->register('path_subscriber', 'Drupal\Core\EventSubscriber\PathSubscriber')
+ ->addArgument(new Reference('path.alias_manager.cached'))
->addTag('event_subscriber');
$container->register('legacy_request_subscriber', 'Drupal\Core\EventSubscriber\LegacyRequestSubscriber')
->addTag('event_subscriber');
diff --git a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
index 7688107..8f0359d 100644
--- a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php
@@ -7,8 +7,10 @@
namespace Drupal\Core\EventSubscriber;
+use Drupal\Core\CacheDecorator\AliasManagerCacheDecorator;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\HttpKernel\Event\PostResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
@@ -16,23 +18,31 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
*/
class PathSubscriber extends PathListenerBase implements EventSubscriberInterface {
+ protected $aliasManager;
+
+ public function __construct(AliasManagerCacheDecorator $alias_manager) {
+ $this->aliasManager = $alias_manager;
+ }
+
/**
* Resolve the system path.
*
- * @todo The path system should be objectified to remove the function calls in
- * this method.
- *
* @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The Event to process.
*/
public function onKernelRequestPathResolve(GetResponseEvent $event) {
$request = $event->getRequest();
-
$path = $this->extractPath($request);
-
- $path = drupal_get_normal_path($path);
-
+ $path = $this->aliasManager->getSystemPath($path);
$this->setPath($request, $path);
+ $this->aliasManager->setCacheKey($path);
+ }
+
+ /**
+ * Ensures system paths for the request get cached.
+ */
+ public function onKernelTerminate(PostResponseEvent $event) {
+ $this->aliasManager->writeCache();
}
/**
@@ -116,6 +126,7 @@ class PathSubscriber extends PathListenerBase implements EventSubscriberInterfac
$events[KernelEvents::REQUEST][] = array('onKernelRequestLanguageResolve', 150);
$events[KernelEvents::REQUEST][] = array('onKernelRequestFrontPageResolve', 101);
$events[KernelEvents::REQUEST][] = array('onKernelRequestPathResolve', 100);
+ $events[KernelEvents::TERMINATE][] = array('onKernelTerminate', 200);
return $events;
}
diff --git a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php
index 175ce79..8d5f87a 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php
@@ -29,7 +29,6 @@ class RequestCloseSubscriber implements EventSubscriberInterface {
*/
public function onTerminate(PostResponseEvent $event) {
module_invoke_all('exit');
- drupal_cache_system_paths();
module_implements_write_cache();
system_run_automated_cron();
}
@@ -41,7 +40,7 @@ class RequestCloseSubscriber implements EventSubscriberInterface {
* An array of event listener definitions.
*/
static function getSubscribedEvents() {
- $events[KernelEvents::TERMINATE][] = array('onTerminate');
+ $events[KernelEvents::TERMINATE][] = array('onTerminate', 100);
return $events;
}
diff --git a/core/lib/Drupal/Core/ExceptionController.php b/core/lib/Drupal/Core/ExceptionController.php
index e311c93..92d4454 100644
--- a/core/lib/Drupal/Core/ExceptionController.php
+++ b/core/lib/Drupal/Core/ExceptionController.php
@@ -101,7 +101,7 @@ class ExceptionController extends ContainerAware {
$system_path = $request->attributes->get('system_path');
watchdog('access denied', $system_path, array(), WATCHDOG_WARNING);
- $path = drupal_get_normal_path(config('system.site')->get('page.403'));
+ $path = $this->container->get('path.alias_manager')->getSystemPath(config('system.site')->get('page.403'));
if ($path && $path != $system_path) {
// Keep old path for reference, and to allow forms to redirect to it.
if (!isset($_GET['destination'])) {
@@ -173,7 +173,7 @@ class ExceptionController extends ContainerAware {
$_GET['destination'] = $system_path;
}
- $path = drupal_get_normal_path(config('system.site')->get('page.404'));
+ $path = $this->container->get('path.alias_manager')->getSystemPath(config('system.site')->get('page.404'));
if ($path && $path != $system_path) {
// @todo Um, how do I specify an override URL again? Totally not clear. Do
// that and sub-call the kernel rather than using meah().
diff --git a/core/lib/Drupal/Core/Path/AliasManager.php b/core/lib/Drupal/Core/Path/AliasManager.php
new file mode 100644
index 0000000..02433ce
--- /dev/null
+++ b/core/lib/Drupal/Core/Path/AliasManager.php
@@ -0,0 +1,320 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Path\AliasManager.
+ */
+
+namespace Drupal\Core\Path;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\KeyValueStore\KeyValueDatabaseFactory;
+
+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, KeyValueDatabaseFactory $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];
+ }
+ // Check the path whitelist, if the top-level part before the first /
+ // is not in the list, then there is no need to do anything further,
+ // it is not in the database.
+ elseif (!isset($this->whitelist[strtok($path, '/')])) {
+ return FALSE;
+ }
+ // For system paths which were not cached, query aliases individually.
+ 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;
+ }
+}
diff --git a/core/lib/Drupal/Core/Path/AliasManagerInterface.php b/core/lib/Drupal/Core/Path/AliasManagerInterface.php
new file mode 100644
index 0000000..3dedd3e
--- /dev/null
+++ b/core/lib/Drupal/Core/Path/AliasManagerInterface.php
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Path\AliasManagerInterface.
+ */
+
+namespace Drupal\Core\Path;
+
+interface AliasManagerInterface {
+
+ /**
+ * Given a path alias, return the internal path it represents.
+ *
+ * @param $path
+ * A Drupal path alias.
+ * @param $path_language
+ * An optional language code to look up the path in.
+ *
+ * @return
+ * The internal path represented by the alias, or the original alias if no
+ * internal path was found.
+ */
+ public function getSystemPath($path, $path_language = NULL);
+
+ /**
+ * Given an internal Drupal path, return the alias set by the administrator.
+ *
+ * @param $path
+ * An internal Drupal path.
+ *
+ * @param $path_language
+ * An optional language code to look up the path in.
+ *
+ * @return
+ * An aliased path if one was found, or the original path if no alias was
+ * found.
+ */
+ public function getPathAlias($path, $path_language = NULL);
+
+ /**
+ * Returns an array of system paths that have been looked up.
+ *
+ * @return array
+ * An array of all system paths that have been looked up during the current
+ * request.
+ */
+ public function getPathLookups();
+
+ /**
+ * Preload a set of paths for bulk alias lookups.
+ *
+ * @param $path_list
+ * An array of system paths.
+ */
+ public function preloadPathLookups(array $path_list);
+}
diff --git a/core/lib/Drupal/Core/Path/Path.php b/core/lib/Drupal/Core/Path/Path.php
new file mode 100644
index 0000000..a7fd55a
--- /dev/null
+++ b/core/lib/Drupal/Core/Path/Path.php
@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Path\Path.
+ */
+
+namespace Drupal\Core\Path;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Database\Connection;
+
+/**
+ * Defines a class for CRUD operations on path aliases.
+ */
+class Path {
+
+ /**
+ * The database connection.
+ *
+ * @var \Drupal\Core\Database\Connection
+ */
+ protected $connection;
+
+ /**
+ * Constructs a Path CRUD object.
+ *
+ * @param \Drupal\Core\Database\Connection $connection
+ * A database connection for reading and writing path aliases.
+ *
+ * @param \Drupal\Core\Path\AliasManager $alias_manager
+ * An alias manager with an internal cache of stored aliases.
+ *
+ * @todo This class should not take an alias manager in its constructor. Once
+ * we move to firing an event for CRUD operations instead of invoking a
+ * hook, we can have a listener that calls cacheClear() on the alias manager.
+ */
+ public function __construct(Connection $connection, AliasManager $alias_manager) {
+ $this->connection = $connection;
+ $this->alias_manager = $alias_manager;
+ }
+
+ /**
+ * Saves a path alias to the database.
+ *
+ * @param string $source
+ * The internal system path.
+ *
+ * @param string $alias
+ * The URL alias.
+ *
+ * @param string $langcode
+ * The language code of the alias.
+ *
+ * @param int $pid
+ * Unique path alias identifier.
+ *
+ * @return
+ * FALSE if the path could not be saved or an associative array containing
+ * the following keys:
+ * - source: The internal system path.
+ * - alias: The URL alias.
+ * - pid: Unique path alias identifier.
+ * - langcode: The language code of the alias.
+ */
+ public function save($source, $alias, $langcode = LANGUAGE_NOT_SPECIFIED, $pid = NULL) {
+
+ $fields = array(
+ 'source' => $source,
+ 'alias' => $alias,
+ 'langcode' => $langcode,
+ );
+
+ // Insert or update the alias.
+ if (empty($pid)) {
+ $query = $this->connection->insert('url_alias')
+ ->fields($fields);
+ $pid = $query->execute();
+ $fields['pid'] = $pid;
+ // @todo: Find a correct place to invoke hook_path_insert().
+ $hook = 'path_insert';
+ }
+ else {
+ $fields['pid'] = $pid;
+ $query = $this->connection->update('url_alias')
+ ->fields($fields)
+ ->condition('pid', $pid);
+ $pid = $query->execute();
+ // @todo: figure out where we can invoke hook_path_update()
+ $hook = 'path_update';
+ }
+ if ($pid) {
+ // @todo Switch to using an event for this instead of a hook.
+ module_invoke_all($hook, $fields);
+ $this->alias_manager->cacheClear();
+ return $fields;
+ }
+ return FALSE;
+ }
+
+ /**
+ * Fetches a specific URL alias from the database.
+ *
+ * @param $conditions
+ * An array of query conditions.
+ *
+ * @return
+ * FALSE if no alias was found or an associative array containing the
+ * following keys:
+ * - source: The internal system path.
+ * - alias: The URL alias.
+ * - pid: Unique path alias identifier.
+ * - langcode: The language code of the alias.
+ */
+ public function load($conditions) {
+ $select = $this->connection->select('url_alias');
+ foreach ($conditions as $field => $value) {
+ $select->condition($field, $value);
+ }
+ return $select
+ ->fields('url_alias')
+ ->execute()
+ ->fetchAssoc();
+ }
+
+ /**
+ * Deletes a URL alias.
+ *
+ * @param array $conditions
+ * An array of criteria.
+ */
+ public function delete($conditions) {
+ $path = $this->load($conditions);
+ $query = $this->connection->delete('url_alias');
+ foreach ($conditions as $field => $value) {
+ $query->condition($field, $value);
+ }
+ $deleted = $query->execute();
+ // @todo Switch to using an event for this instead of a hook.
+ module_invoke_all('path_delete', $path);
+ $this->alias_manager->cacheClear();
+ return $deleted;
+ }
+}
diff --git a/core/modules/block/block.module b/core/modules/block/block.module
index 2978146..7340c6b 100644
--- a/core/modules/block/block.module
+++ b/core/modules/block/block.module
@@ -851,7 +851,7 @@ function block_block_list_alter(&$blocks) {
if ($block->visibility < BLOCK_VISIBILITY_PHP) {
// Compare the lowercase path alias (if any) and internal path.
$path = current_path();
- $path_alias = drupal_strtolower(drupal_get_path_alias($path));
+ $path_alias = drupal_strtolower(drupal_container()->get('path.alias_manager')->getPathAlias($path));
$page_match = drupal_match_path($path_alias, $pages) || (($path != $path_alias) && drupal_match_path($path, $pages));
// When $block->visibility has a value of 0 (BLOCK_VISIBILITY_NOTLISTED),
// the block is displayed on all pages except those listed in $block->pages.
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
index bafb620..d1ad5f0 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
@@ -109,13 +109,13 @@ class LocalePathTest extends WebTestBase {
'alias' => $custom_path,
'langcode' => LANGUAGE_NOT_SPECIFIED,
);
- path_save($edit);
- $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, 'en');
+ drupal_container()->get('path.crud')->save($edit['source'], $edit['alias'], $edit['langcode']);
+ $lookup_path = drupal_container()->get('path.alias_manager')->getPathAlias('node/' . $node->nid, 'en');
$this->assertEqual($english_path, $lookup_path, t('English language alias has priority.'));
// Same check for language 'xx'.
- $lookup_path = drupal_lookup_path('alias', 'node/' . $node->nid, $prefix);
+ $lookup_path = drupal_container()->get('path.alias_manager')->getPathAlias('node/' . $node->nid, $prefix);
$this->assertEqual($custom_language_path, $lookup_path, t('Custom language alias has priority.'));
- path_delete($edit);
+ drupal_container()->get('path.crud')->delete($edit);
// Create language nodes to check priority of aliases.
$first_node = $this->drupalCreateNode(array('type' => 'page', 'promote' => 1));
@@ -127,7 +127,7 @@ class LocalePathTest extends WebTestBase {
'alias' => $custom_path,
'langcode' => 'en',
);
- path_save($edit);
+ drupal_container()->get('path.crud')->save($edit['source'], $edit['alias'], $edit['langcode']);
// Assign a custom path alias to second node with LANGUAGE_NOT_SPECIFIED.
$edit = array(
@@ -135,7 +135,7 @@ class LocalePathTest extends WebTestBase {
'alias' => $custom_path,
'langcode' => LANGUAGE_NOT_SPECIFIED,
);
- path_save($edit);
+ drupal_container()->get('path.crud')->save($edit['source'], $edit['alias'], $edit['langcode']);
// Test that both node titles link to our path alias.
$this->drupalGet('<front>');
diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc
index 3b67b97..605f898 100644
--- a/core/modules/menu/menu.admin.inc
+++ b/core/modules/menu/menu.admin.inc
@@ -417,7 +417,7 @@ function menu_edit_item($form, &$form_state, $type, $item, $menu) {
*/
function menu_edit_item_validate($form, &$form_state) {
$item = &$form_state['values'];
- $normal_path = drupal_get_normal_path($item['link_path']);
+ $normal_path = drupal_container()->get('path.alias_manager')->getSystemPath($item['link_path']);
if ($item['link_path'] != $normal_path) {
drupal_set_message(t('The menu system stores system paths only, but will use the URL alias for display. %link_path has been stored as %normal_path', array('%link_path' => $item['link_path'], '%normal_path' => $normal_path)));
$item['link_path'] = $normal_path;
diff --git a/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php b/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php
index 181bd72..4168275 100644
--- a/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php
+++ b/core/modules/path/lib/Drupal/path/Tests/PathAliasTest.php
@@ -57,9 +57,7 @@ class PathAliasTest extends PathTestBase {
// Visit the alias for the node and confirm a cache entry is created.
cache('path')->flush();
$this->drupalGet($edit['alias']);
- // @todo The alias should actually have been cached with the system path as
- // the key, see the todo in drupal_cache_system_paths() in path.inc.
- $this->assertTrue(cache('path')->get($edit['alias']), 'Cache entry was created.');
+ $this->assertTrue(cache('path')->get($edit['source']), 'Cache entry was created.');
}
/**
@@ -94,7 +92,7 @@ class PathAliasTest extends PathTestBase {
$this->assertText($node1->label(), 'Changed alias works.');
$this->assertResponse(200);
- drupal_static_reset('drupal_lookup_path');
+ drupal_container()->get('path.alias_manager')->cacheClear();
// Confirm that previous alias no longer works.
$this->drupalGet($previous);
$this->assertNoText($node1->label(), 'Previous alias no longer works.');
diff --git a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php
index e6fd10d..83be7b5 100644
--- a/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php
+++ b/core/modules/path/lib/Drupal/path/Tests/PathLanguageTest.php
@@ -82,7 +82,7 @@ class PathLanguageTest extends PathTestBase {
$this->drupalPost(NULL, $edit, t('Save'));
// Clear the path lookup cache.
- drupal_lookup_path('wipe');
+ drupal_container()->get('path.alias_manager')->cacheClear();
// Ensure the node was created.
$french_node = $this->drupalGetNodeByTitle($edit["title"]);
@@ -121,7 +121,7 @@ class PathLanguageTest extends PathTestBase {
// We need to ensure that the user language preference is not taken into
// account while determining the path alias language, because if this
// happens we have no way to check that the path alias is valid: there is no
- // path alias for French matching the english alias. So drupal_lookup_path()
+ // path alias for French matching the english alias. So the alias manager
// needs to use the URL language to check whether the alias is valid.
$this->drupalGet($english_alias);
$this->assertText($english_node->label(), 'Alias for English translation works.');
@@ -145,20 +145,20 @@ class PathLanguageTest extends PathTestBase {
$this->drupalGet($french_alias);
$this->assertResponse(404, 'Alias for French translation is unavailable when URL language negotiation is disabled.');
- // drupal_lookup_path() has an internal static cache. Check to see that
+ // The alias manager has an internal path lookup cache. Check to see that
// it has the appropriate contents at this point.
- drupal_lookup_path('wipe');
- $french_node_path = drupal_lookup_path('source', $french_alias, $french_node->langcode);
+ drupal_container()->get('path.alias_manager')->cacheClear();
+ $french_node_path = drupal_container()->get('path.alias_manager')->getSystemPath($french_alias, $french_node->langcode);
$this->assertEqual($french_node_path, 'node/' . $french_node->nid, 'Normal path works.');
// Second call should return the same path.
- $french_node_path = drupal_lookup_path('source', $french_alias, $french_node->langcode);
+ $french_node_path = drupal_container()->get('path.alias_manager')->getSystemPath($french_alias, $french_node->langcode);
$this->assertEqual($french_node_path, 'node/' . $french_node->nid, 'Normal path is the same.');
// Confirm that the alias works.
- $french_node_alias = drupal_lookup_path('alias', 'node/' . $french_node->nid, $french_node->langcode);
+ $french_node_alias = drupal_container()->get('path.alias_manager')->getPathAlias('node/' . $french_node->nid, $french_node->langcode);
$this->assertEqual($french_node_alias, $french_alias, 'Alias works.');
// Second call should return the same alias.
- $french_node_alias = drupal_lookup_path('alias', 'node/' . $french_node->nid, $french_node->langcode);
+ $french_node_alias = drupal_container()->get('path.alias_manager')->getPathAlias('node/' . $french_node->nid, $french_node->langcode);
$this->assertEqual($french_node_alias, $french_alias, 'Alias is the same.');
}
}
diff --git a/core/modules/path/path.admin.inc b/core/modules/path/path.admin.inc
index 32c5e4d..8c87dee 100644
--- a/core/modules/path/path.admin.inc
+++ b/core/modules/path/path.admin.inc
@@ -75,7 +75,7 @@ function path_admin_overview($keys = NULL) {
// If the system path maps to a different URL alias, highlight this table
// row to let the user know of old aliases.
- if ($data->alias != drupal_get_path_alias($data->source, $data->langcode)) {
+ if ($data->alias != drupal_container()->get('path.alias_manager')->getPathAlias($data->source, $data->langcode)) {
$row['class'] = array('warning');
}
@@ -217,7 +217,7 @@ function path_admin_form_delete_submit($form, &$form_state) {
*/
function path_admin_form_validate($form, &$form_state) {
$source = &$form_state['values']['source'];
- $source = drupal_get_normal_path($source);
+ $source = drupal_container()->get('path.alias_manager')->getSystemPath($source);
$alias = $form_state['values']['alias'];
$pid = isset($form_state['values']['pid']) ? $form_state['values']['pid'] : 0;
// Language is only set if language.module is enabled, otherwise save for all
@@ -249,7 +249,15 @@ function path_admin_form_submit($form, &$form_state) {
// Remove unnecessary values.
form_state_values_clean($form_state);
- path_save($form_state['values']);
+ $pid = isset($form_state['values']['pid']) ? $form_state['values']['pid'] : 0;
+ $source = &$form_state['values']['source'];
+ $source = drupal_container()->get('path.alias_manager')->getSystemPath($source);
+ $alias = $form_state['values']['alias'];
+ // Language is only set if language.module is enabled, otherwise save for all
+ // languages.
+ $langcode = isset($form_state['values']['langcode']) ? $form_state['values']['langcode'] : LANGUAGE_NOT_SPECIFIED;
+
+ drupal_container()->get('path.crud')->save($source, $alias, $langcode, $pid);
drupal_set_message(t('The alias has been saved.'));
$form_state['redirect'] = 'admin/config/search/path';
@@ -281,7 +289,7 @@ function path_admin_delete_confirm($form, &$form_state, $path) {
*/
function path_admin_delete_confirm_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
- path_delete($form_state['path']['pid']);
+ drupal_container()->get('path.crud')->delete(array('pid' => $form_state['path']['pid']));
$form_state['redirect'] = 'admin/config/search/path';
}
}
diff --git a/core/modules/path/path.api.php b/core/modules/path/path.api.php
index f2c5ece..c69b97d 100644
--- a/core/modules/path/path.api.php
+++ b/core/modules/path/path.api.php
@@ -20,7 +20,7 @@
* - pid: Unique path alias identifier.
* - langcode: The language code of the alias.
*
- * @see path_save()
+ * @see \Drupal\Core\Path\Path::save()
*/
function hook_path_insert($path) {
db_insert('mytable')
@@ -41,7 +41,7 @@ function hook_path_insert($path) {
* - pid: Unique path alias identifier.
* - langcode: The language code of the alias.
*
- * @see path_save()
+ * @see \Drupal\Core\Path\Path::save()
*/
function hook_path_update($path) {
db_update('mytable')
@@ -60,7 +60,7 @@ function hook_path_update($path) {
* - pid: Unique path alias identifier.
* - langcode: The language code of the alias.
*
- * @see path_delete()
+ * @see \Drupal\Core\Path\Path::delete()
*/
function hook_path_delete($path) {
db_delete('mytable')
diff --git a/core/modules/path/path.module b/core/modules/path/path.module
index 942fbb6..dcbe3be 100644
--- a/core/modules/path/path.module
+++ b/core/modules/path/path.module
@@ -107,7 +107,7 @@ function path_form_node_form_alter(&$form, $form_state) {
if ($node->langcode != LANGUAGE_NOT_SPECIFIED) {
$conditions['langcode'] = $node->langcode;
}
- $path = path_load($conditions);
+ $path = drupal_container()->get('path.crud')->load($conditions);
if ($path === FALSE) {
$path = array();
}
@@ -190,14 +190,13 @@ function path_form_element_validate($element, &$form_state, $complete_form) {
*/
function path_node_insert(Node $node) {
if (isset($node->path)) {
- $path = $node->path;
- $path['alias'] = trim($path['alias']);
+ $alias = trim($node->path['alias']);
// Only save a non-empty alias.
- if (!empty($path['alias'])) {
+ if (!empty($alias)) {
// Ensure fields for programmatic executions.
- $path['source'] = 'node/' . $node->nid;
- $path['langcode'] = isset($node->langcode) ? $node->langcode : LANGUAGE_NOT_SPECIFIED;
- path_save($path);
+ $source = 'node/' . $node->nid;
+ $langcode = isset($node->langcode) ? $node->langcode : LANGUAGE_NOT_SPECIFIED;
+ drupal_container()->get('path.crud')->save($source, $alias, $langcode);
}
}
}
@@ -208,17 +207,17 @@ function path_node_insert(Node $node) {
function path_node_update(Node $node) {
if (isset($node->path)) {
$path = $node->path;
- $path['alias'] = trim($path['alias']);
+ $alias = trim($path['alias']);
// Delete old alias if user erased it.
if (!empty($path['pid']) && empty($path['alias'])) {
- path_delete($path['pid']);
+ drupal_container()->get('path.crud')->delete(array('pid' => $path['pid']));
}
// Only save a non-empty alias.
if (!empty($path['alias'])) {
// Ensure fields for programmatic executions.
- $path['source'] = 'node/' . $node->nid;
- $path['langcode'] = isset($node->langcode) ? $node->langcode : LANGUAGE_NOT_SPECIFIED;
- path_save($path);
+ $source = 'node/' . $node->nid;
+ $langcode = isset($node->langcode) ? $node->langcode : LANGUAGE_NOT_SPECIFIED;
+ drupal_container()->get('path.crud')->save($source, $alias, $langcode, $path['pid']);
}
}
}
@@ -228,7 +227,7 @@ function path_node_update(Node $node) {
*/
function path_node_predelete(Node $node) {
// Delete all aliases associated with this node.
- path_delete(array('source' => 'node/' . $node->nid));
+ drupal_container()->get('path.crud')->delete(array('source' => 'node/' . $node->nid));
}
/**
@@ -238,7 +237,7 @@ function path_form_taxonomy_term_form_alter(&$form, $form_state) {
// Make sure this does not show up on the delete confirmation form.
if (empty($form_state['confirm_delete'])) {
$term = $form_state['controller']->getEntity($form_state);
- $path = (isset($term->tid) ? path_load('taxonomy/term/' . $term->tid) : array());
+ $path = (isset($term->tid) ? drupal_container()->get('path.crud')->load(array('source' => 'taxonomy/term/' . $term->tid)) : array());
if ($path === FALSE) {
$path = array();
}
@@ -279,7 +278,7 @@ function path_taxonomy_term_insert(Term $term) {
// Ensure fields for programmatic executions.
$path['source'] = 'taxonomy/term/' . $term->tid;
$path['langcode'] = LANGUAGE_NOT_SPECIFIED;
- path_save($path);
+ drupal_container()->get('path.crud')->save($path['source'], $path['alias'], $path['langcode']);
}
}
}
@@ -293,14 +292,15 @@ function path_taxonomy_term_update(Term $term) {
$path['alias'] = trim($path['alias']);
// Delete old alias if user erased it.
if (!empty($path['pid']) && empty($path['alias'])) {
- path_delete($path['pid']);
+ drupal_container()->get('path.crud')->delete(array('pid' => $path['pid']));
}
// Only save a non-empty alias.
if (!empty($path['alias'])) {
+ $pid = (!empty($path['pid']) ? $path['pid'] : NULL);
// Ensure fields for programmatic executions.
$path['source'] = 'taxonomy/term/' . $term->tid;
$path['langcode'] = LANGUAGE_NOT_SPECIFIED;
- path_save($path);
+ drupal_container()->get('path.crud')->save($path['source'], $path['alias'], $path['langcode'], $pid);
}
}
}
@@ -310,7 +310,7 @@ function path_taxonomy_term_update(Term $term) {
*/
function path_taxonomy_term_delete(Term $term) {
// Delete all aliases associated with this term.
- path_delete(array('source' => 'taxonomy/term/' . $term->tid));
+ drupal_container()->get('path.crud')->delete(array('source' => 'taxonomy/term/' . $term->tid));
}
/**
diff --git a/core/modules/search/search.module b/core/modules/search/search.module
index a32b5c3..866536e 100644
--- a/core/modules/search/search.module
+++ b/core/modules/search/search.module
@@ -643,7 +643,7 @@ function search_index($sid, $module, $text, $langcode) {
if ($tagname == 'a') {
// Check if link points to a node on this site
if (preg_match($node_regexp, $value, $match)) {
- $path = drupal_get_normal_path($match[1]);
+ $path = drupal_container()->get('path.alias_manager')->getSystemPath($match[1]);
if (preg_match('!(?:node|book)/(?:view/)?([0-9]+)!i', $path, $match)) {
$linknid = $match[1];
if ($linknid > 0) {
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
index 54eeab4..ccf9834 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/Tests/ShortcutLinksTest.php
@@ -31,7 +31,7 @@ class ShortcutLinksTest extends ShortcutTestBase {
'source' => 'node/' . $this->node->nid,
'alias' => $this->randomName(8),
);
- path_save($path);
+ drupal_container()->get('path.crud')->save($path['source'], $path['alias']);
// Create some paths to test.
$test_cases = array(
@@ -54,7 +54,7 @@ class ShortcutLinksTest extends ShortcutTestBase {
$saved_set = shortcut_set_load($set->set_name);
$paths = $this->getShortcutInformation($saved_set, 'link_path');
$test_path = empty($test['path']) ? '<front>' : $test['path'];
- $this->assertTrue(in_array(drupal_get_normal_path($test_path), $paths), 'Shortcut created: '. $test['path']);
+ $this->assertTrue(in_array(drupal_container()->get('path.alias_manager')->getSystemPath($test_path), $paths), 'Shortcut created: '. $test['path']);
$this->assertLink($title, 0, 'Shortcut link found on the page.');
}
}
diff --git a/core/modules/shortcut/shortcut.admin.inc b/core/modules/shortcut/shortcut.admin.inc
index e805acf..18ec1c3 100644
--- a/core/modules/shortcut/shortcut.admin.inc
+++ b/core/modules/shortcut/shortcut.admin.inc
@@ -430,7 +430,7 @@ function _shortcut_link_form_elements($shortcut_link = NULL) {
);
}
else {
- $shortcut_link['link_path'] = ($shortcut_link['link_path'] == '<front>') ? '' : drupal_get_path_alias($shortcut_link['link_path']);
+ $shortcut_link['link_path'] = ($shortcut_link['link_path'] == '<front>') ? '' : drupal_container()->get('path.alias_manager')->getPathAlias($shortcut_link['link_path']);
}
$form['shortcut_link']['#tree'] = TRUE;
@@ -477,7 +477,7 @@ function shortcut_link_edit_validate($form, &$form_state) {
*/
function shortcut_link_edit_submit($form, &$form_state) {
// Normalize the path in case it is an alias.
- $shortcut_path = drupal_get_normal_path($form_state['values']['shortcut_link']['link_path']);
+ $shortcut_path = drupal_container()->get('path.alias_manager')->getSystemPath($form_state['values']['shortcut_link']['link_path']);
if (empty($shortcut_path)) {
$shortcut_path = '<front>';
}
@@ -517,7 +517,7 @@ function shortcut_link_add_submit($form, &$form_state) {
*/
function shortcut_admin_add_link($shortcut_link, &$shortcut_set) {
// Normalize the path in case it is an alias.
- $shortcut_link['link_path'] = drupal_get_normal_path($shortcut_link['link_path']);
+ $shortcut_link['link_path'] = drupal_container()->get('path.alias_manager')->getSystemPath($shortcut_link['link_path']);
if (empty($shortcut_link['link_path'])) {
$shortcut_link['link_path'] = '<front>';
}
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index 9bbb12a..2a07989 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -616,7 +616,7 @@ function shortcut_set_title_exists($title) {
*/
function shortcut_valid_link($path) {
// Do not use URL aliases.
- $normal_path = drupal_get_normal_path($path);
+ $normal_path = drupal_container()->get('path.alias_manager')->getSystemPath($path);
if ($path != $normal_path) {
$path = $normal_path;
}
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 7d14ca0..964b16b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -760,6 +760,12 @@ abstract class WebTestBase extends TestBase {
variable_set('mail_system', array('default-system' => 'Drupal\Core\Mail\VariableLog'));
drupal_set_time_limit($this->timeLimit);
+ // Temporary fix so that when running from run-tests.sh we don't get an
+ // empty current path which would indicate we're on the home page.
+ $path = current_path();
+ if (empty($path)) {
+ _current_path('run-tests');
+ }
$this->setup = TRUE;
}
diff --git a/core/modules/statistics/statistics.module b/core/modules/statistics/statistics.module
index db45bee..a359981 100644
--- a/core/modules/statistics/statistics.module
+++ b/core/modules/statistics/statistics.module
@@ -388,7 +388,7 @@ function statistics_block_view($delta = '') {
* A string as a link, truncated to the width, linked to the given $path.
*/
function _statistics_link($path, $width = 35) {
- $title = drupal_get_path_alias($path);
+ $title = drupal_container()->get('path.alias_manager')->getPathAlias($path);
$title = truncate_utf8($title, $width, FALSE, TRUE);
return l($title, $path);
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
index f52907f..7ce84cb 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/JavaScriptTest.php
@@ -176,7 +176,7 @@ class JavaScriptTest extends WebTestBase {
$this->drupalGet('common-test/query-string');
$this->assertPattern('@<script>.+drupalSettings.+"currentPath":"common-test\\\/query-string"@s', 'currentPath is in the JS settings');
$path = array('source' => 'common-test/query-string', 'alias' => 'common-test/currentpath-check');
- path_save($path);
+ drupal_container()->get('path.crud')->save($path['source'], $path['alias']);
$this->drupalGet('common-test/currentpath-check');
$this->assertPattern('@<script>.+drupalSettings.+"currentPath":"common-test\\\/query-string"@s', 'currentPath is in the JS settings for an aliased path');
}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php b/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php
new file mode 100644
index 0000000..bbca543
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/AliasTest.php
@@ -0,0 +1,165 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Path\CrudTest.
+ */
+
+namespace Drupal\system\Tests\Path;
+
+use Drupal\simpletest\UnitTestBase;
+use Drupal\Core\Database\Database;
+use Drupal\Core\KeyValueStore\KeyValueDatabaseFactory;
+use Drupal\Core\Path\Path;
+use Drupal\Core\Path\AliasManager;
+
+/**
+ * Tests path alias CRUD and lookup functionality.
+ */
+class AliasTest extends UnitTestBase {
+
+ public static function getInfo() {
+ return array(
+ 'name' => t('Path Alias Unit Tests'),
+ 'description' => t('Tests path alias CRUD and lookup functionality.'),
+ 'group' => t('Path API'),
+ );
+ }
+
+ function __construct($test_id = NULL) {
+ parent::__construct($test_id);
+
+ $this->fixtures = new UrlAliasFixtures();
+ }
+
+ public function tearDown() {
+ $this->fixtures->dropTables(Database::getConnection());
+
+ parent::tearDown();
+ }
+
+
+ function testCRUD() {
+ //Prepare database table.
+ $connection = Database::getConnection();
+ $this->fixtures->createTables($connection);
+
+ //Create AliasManager and Path object.
+ $aliasManager = new AliasManager($connection, new KeyValueDatabaseFactory($connection));
+ $path = new Path($connection, $aliasManager);
+
+ $aliases = $this->fixtures->sampleUrlAliases();
+
+ //Create a few aliases
+ foreach ($aliases as $idx => $alias) {
+ $path->save($alias['source'], $alias['alias'], $alias['langcode']);
+
+ $result = $connection->query('SELECT * FROM {url_alias} WHERE source = :source AND alias= :alias AND langcode = :langcode', array(':source' => $alias['source'], ':alias' => $alias['alias'], ':langcode' => $alias['langcode']));
+ $rows = $result->fetchAll();
+
+ $this->assertEqual(count($rows), 1, format_string('Created an entry for %alias.', array('%alias' => $alias['alias'])));
+
+ //Cache the pid for further tests.
+ $aliases[$idx]['pid'] = $rows[0]->pid;
+ }
+
+ //Load a few aliases
+ foreach ($aliases as $alias) {
+ $pid = $alias['pid'];
+ $loadedAlias = $path->load(array('pid' => $pid));
+ $this->assertEqual($loadedAlias, $alias, format_string('Loaded the expected path with pid %pid.', array('%pid' => $pid)));
+ }
+
+ //Update a few aliases
+ foreach ($aliases as $alias) {
+ $path->save($alias['source'], $alias['alias'] . '_updated', $alias['langcode'], $alias['pid']);
+
+ $result = $connection->query('SELECT pid FROM {url_alias} WHERE source = :source AND alias= :alias AND langcode = :langcode', array(':source' => $alias['source'], ':alias' => $alias['alias'] . '_updated', ':langcode' => $alias['langcode']));
+ $pid = $result->fetchField();
+
+ $this->assertEqual($pid, $alias['pid'], format_string('Updated entry for pid %pid.', array('%pid' => $pid)));
+ }
+
+ //Delete a few aliases
+ foreach ($aliases as $alias) {
+ $pid = $alias['pid'];
+ $path->delete(array('pid' => $pid));
+
+ $result = $connection->query('SELECT * FROM {url_alias} WHERE pid = :pid', array(':pid' => $pid));
+ $rows = $result->fetchAll();
+
+ $this->assertEqual(count($rows), 0, format_string('Deleted entry with pid %pid.', array('%pid' => $pid)));
+ }
+ }
+
+ function testLookupPath() {
+ //Prepare database table.
+ $connection = Database::getConnection();
+ $this->fixtures->createTables($connection);
+
+ //Create AliasManager and Path object.
+ $aliasManager = new AliasManager($connection, new KeyValueDatabaseFactory($connection));
+ $pathObject = new Path($connection, $aliasManager);
+
+ // Test the situation where the source is the same for multiple aliases.
+ // Start with a language-neutral alias, which we will override.
+ $path = array(
+ 'source' => "user/1",
+ 'alias' => 'foo',
+ );
+
+ $pathObject->save($path['source'], $path['alias']);
+ $this->assertEqual($aliasManager->getPathAlias($path['source']), $path['alias'], 'Basic alias lookup works.');
+ $this->assertEqual($aliasManager->getSystemPath($path['alias']), $path['source'], 'Basic source lookup works.');
+
+ // Create a language specific alias for the default language (English).
+ $path = array(
+ 'source' => "user/1",
+ 'alias' => "users/Dries",
+ 'langcode' => 'en',
+ );
+ $pathObject->save($path['source'], $path['alias'], $path['langcode']);
+ $this->assertEqual($aliasManager->getPathAlias($path['source']), $path['alias'], 'English alias overrides language-neutral alias.');
+ $this->assertEqual($aliasManager->getSystemPath($path['alias']), $path['source'], 'English source overrides language-neutral source.');
+
+ // Create a language-neutral alias for the same path, again.
+ $path = array(
+ 'source' => "user/1",
+ 'alias' => 'bar',
+ );
+ $pathObject->save($path['source'], $path['alias']);
+ $this->assertEqual($aliasManager->getPathAlias($path['source']), "users/Dries", 'English alias still returned after entering a language-neutral alias.');
+
+ // Create a language-specific (xx-lolspeak) alias for the same path.
+ $path = array(
+ 'source' => "user/1",
+ 'alias' => 'LOL',
+ 'langcode' => 'xx-lolspeak',
+ );
+ $pathObject->save($path['source'], $path['alias'], $path['langcode']);
+ $this->assertEqual($aliasManager->getPathAlias($path['source']), "users/Dries", 'English alias still returned after entering a LOLspeak alias.');
+ // The LOLspeak alias should be returned if we really want LOLspeak.
+ $this->assertEqual($aliasManager->getPathAlias($path['source'], 'xx-lolspeak'), 'LOL', 'LOLspeak alias returned if we specify xx-lolspeak to the alias manager.');
+
+ // Create a new alias for this path in English, which should override the
+ // previous alias for "user/1".
+ $path = array(
+ 'source' => "user/1",
+ 'alias' => 'users/my-new-path',
+ 'langcode' => 'en',
+ );
+ $pathObject->save($path['source'], $path['alias'], $path['langcode']);
+ $this->assertEqual($aliasManager->getPathAlias($path['source']), $path['alias'], 'Recently created English alias returned.');
+ $this->assertEqual($aliasManager->getSystemPath($path['alias']), $path['source'], 'Recently created English source returned.');
+
+ // Remove the English aliases, which should cause a fallback to the most
+ // recently created language-neutral alias, 'bar'.
+ $pathObject->delete(array('langcode' => 'en'));
+ $this->assertEqual($aliasManager->getPathAlias($path['source']), 'bar', 'Path lookup falls back to recently created language-neutral alias.');
+
+ // Test the situation where the alias and language are the same, but
+ // the source differs. The newer alias record should be returned.
+ $pathObject->save('user/2', 'bar');
+ $this->assertEqual($aliasManager->getSystemPath('bar'), 'user/2', 'Newer alias record is returned when comparing two LANGUAGE_NOT_SPECIFIED paths with the same alias.');
+ }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/LookupTest.php b/core/modules/system/lib/Drupal/system/Tests/Path/LookupTest.php
deleted file mode 100644
index e319b94..0000000
--- a/core/modules/system/lib/Drupal/system/Tests/Path/LookupTest.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\system\Tests\Path\LookupTest.
- */
-
-namespace Drupal\system\Tests\Path;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Unit test for drupal_lookup_path().
- */
-class LookupTest extends WebTestBase {
- public static function getInfo() {
- return array(
- 'name' => t('Path lookup'),
- 'description' => t('Tests that drupal_lookup_path() returns correct paths.'),
- 'group' => t('Path API'),
- );
- }
-
- /**
- * Test that drupal_lookup_path() returns the correct path.
- */
- function testDrupalLookupPath() {
- $account = $this->drupalCreateUser();
- $uid = $account->uid;
- $name = $account->name;
-
- // Test the situation where the source is the same for multiple aliases.
- // Start with a language-neutral alias, which we will override.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'foo',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Basic alias lookup works.');
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Basic source lookup works.');
-
- // Create a language specific alias for the default language (English).
- $path = array(
- 'source' => "user/$uid",
- 'alias' => "users/$name",
- 'langcode' => 'en',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'English alias overrides language-neutral alias.');
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'English source overrides language-neutral source.');
-
- // Create a language-neutral alias for the same path, again.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'bar',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a language-neutral alias.');
-
- // Create a language-specific (xx-lolspeak) alias for the same path.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'LOL',
- 'langcode' => 'xx-lolspeak',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), "users/$name", 'English alias still returned after entering a LOLspeak alias.');
- // The LOLspeak alias should be returned if we really want LOLspeak.
- $this->assertEqual(drupal_lookup_path('alias', $path['source'], 'xx-lolspeak'), 'LOL', 'LOLspeak alias returned if we specify xx-lolspeak to drupal_lookup_path().');
-
- // Create a new alias for this path in English, which should override the
- // previous alias for "user/$uid".
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'users/my-new-path',
- 'langcode' => 'en',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), $path['alias'], 'Recently created English alias returned.');
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Recently created English source returned.');
-
- // Remove the English aliases, which should cause a fallback to the most
- // recently created language-neutral alias, 'bar'.
- db_delete('url_alias')
- ->condition('langcode', 'en')
- ->execute();
- drupal_clear_path_cache();
- $this->assertEqual(drupal_lookup_path('alias', $path['source']), 'bar', 'Path lookup falls back to recently created language-neutral alias.');
-
- // Test the situation where the alias and language are the same, but
- // the source differs. The newer alias record should be returned.
- $account2 = $this->drupalCreateUser();
- $path = array(
- 'source' => 'user/' . $account2->uid,
- 'alias' => 'bar',
- );
- path_save($path);
- $this->assertEqual(drupal_lookup_path('source', $path['alias']), $path['source'], 'Newer alias record is returned when comparing two LANGUAGE_NOT_SPECIFIED paths with the same alias.');
- }
-}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/SaveTest.php b/core/modules/system/lib/Drupal/system/Tests/Path/SaveTest.php
deleted file mode 100644
index b95893a..0000000
--- a/core/modules/system/lib/Drupal/system/Tests/Path/SaveTest.php
+++ /dev/null
@@ -1,63 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\system\Tests\Path\SaveTest.
- */
-
-namespace Drupal\system\Tests\Path;
-
-use Drupal\simpletest\WebTestBase;
-
-/**
- * Tests the path_save() function.
- */
-class SaveTest extends WebTestBase {
-
- /**
- * Enable a helper module that implements hook_path_update().
- *
- * @var array
- */
- public static $modules = array('path_test');
-
- public static function getInfo() {
- return array(
- 'name' => t('Path save'),
- 'description' => t('Tests that path_save() exposes the previous alias value.'),
- 'group' => t('Path API'),
- );
- }
-
- function setUp() {
- parent::setUp();
- path_test_reset();
- }
-
- /**
- * Tests that path_save() makes the original path available to modules.
- */
- function testDrupalSaveOriginalPath() {
- $account = $this->drupalCreateUser();
- $uid = $account->uid;
- $name = $account->name;
-
- // Create a language-neutral alias.
- $path = array(
- 'source' => "user/$uid",
- 'alias' => 'foo',
- );
- $path_original = $path;
- path_save($path);
-
- // Alter the path.
- $path['alias'] = 'bar';
- path_save($path);
-
- // Test to see if the original alias is available to modules during
- // hook_path_update().
- $results = variable_get('path_test_results', array());
- $this->assertIdentical($results['hook_path_update']['original']['alias'], $path_original['alias'], 'Old path alias available to modules during hook_path_update.');
- $this->assertIdentical($results['hook_path_update']['original']['source'], $path_original['source'], 'Old path alias available to modules during hook_path_update.');
- }
-}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php b/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php
new file mode 100644
index 0000000..6fb02da
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/UrlAliasFixtures.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Drupal\system\Tests\Path;
+
+use Drupal\Core\Database\Connection;
+
+/**
+ * Utility methods to generate sample data, database configuration, etc.
+ */
+class UrlAliasFixtures {
+
+ /**
+ * Create the tables required for the sample data.
+ *
+ * @param Drupal\Core\Database\Connection $connection
+ * The connection to use to create the tables.
+ */
+ public function createTables(Connection $connection) {
+ $tables = $this->urlAliasTableDefinition();
+ $schema = $connection->schema();
+
+ foreach ($tables as $name => $table) {
+ $schema->dropTable($name);
+ $schema->createTable($name, $table);
+ }
+ }
+
+ /**
+ * Drop the tables used for the sample data.
+ *
+ * @param Drupal\Core\Database\Connection $connection
+ * The connection to use to drop the tables.
+ */
+ public function dropTables(Connection $connection) {
+ $tables = $this->urlAliasTableDefinition();
+ $schema = $connection->schema();
+
+ foreach ($tables as $name => $table) {
+ $schema->dropTable($name);
+ }
+ }
+
+ /**
+ * Returns an array of URL aliases for testing.
+ *
+ * @return array of URL alias definitions.
+ */
+ public function sampleUrlAliases() {
+ return array(
+ array(
+ 'source' => 'node/1',
+ 'alias' => 'alias_for_node_1_en',
+ 'langcode' => 'en'
+ ),
+ array(
+ 'source' => 'node/2',
+ 'alias' => 'alias_for_node_2_en',
+ 'langcode' => 'en'
+ ),
+ array(
+ 'source' => 'node/1',
+ 'alias' => 'alias_for_node_1_fr',
+ 'langcode' => 'fr'
+ ),
+ array(
+ 'source' => 'node/1',
+ 'alias' => 'alias_for_node_1_und',
+ 'langcode' => 'und'
+ )
+ );
+ }
+
+
+ /**
+ * Returns the table definition for the URL alias fixtures.
+ *
+ * @return array
+ * Table definitions.
+ */
+ public function urlAliasTableDefinition() {
+ $tables = array();
+
+ module_load_install('system');
+ $schema = system_schema();
+
+ $tables['url_alias'] = $schema['url_alias'];
+ $tables['key_value'] = $schema['key_value'];
+
+ return $tables;
+ }
+}
diff --git a/core/modules/system/lib/Drupal/system/Tests/Path/UrlAlterFunctionalTest.php b/core/modules/system/lib/Drupal/system/Tests/Path/UrlAlterFunctionalTest.php
index 72091e5..353ba18 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Path/UrlAlterFunctionalTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Path/UrlAlterFunctionalTest.php
@@ -40,41 +40,43 @@ class UrlAlterFunctionalTest extends WebTestBase {
$name = $account->name;
// Test a single altered path.
- $this->assertUrlInboundAlter("user/$name", "user/$uid");
+ $this->drupalGet("user/$name");
+ $this->assertResponse('200', 'The user/username path gets resolved correctly');
$this->assertUrlOutboundAlter("user/$uid", "user/$name");
// Test that a path always uses its alias.
$path = array('source' => "user/$uid/test1", 'alias' => 'alias/test1');
- path_save($path);
+ drupal_container()->get('path.crud')->save($path['source'], $path['alias']);
$this->assertUrlInboundAlter('alias/test1', "user/$uid/test1");
$this->assertUrlOutboundAlter("user/$uid/test1", 'alias/test1');
- // Test that alias source paths are normalized in the interface.
- $edit = array('source' => "user/$name/edit", 'alias' => 'alias/test2');
+ // Test adding an alias via the UI.
+ $edit = array('source' => "user/$uid/edit", 'alias' => 'alias/test2');
$this->drupalPost('admin/config/search/path/add', $edit, t('Save'));
$this->assertText(t('The alias has been saved.'));
-
- // Test that a path always uses its alias.
- $this->assertUrlInboundAlter('alias/test2', "user/$uid/edit");
+ $this->drupalGet('alias/test2');
+ $this->assertResponse('200', 'The path alias gets resolved correctly');
$this->assertUrlOutboundAlter("user/$uid/edit", 'alias/test2');
// Test a non-existent user is not altered.
$uid++;
- $this->assertUrlInboundAlter("user/$uid", "user/$uid");
$this->assertUrlOutboundAlter("user/$uid", "user/$uid");
// Test that 'forum' is altered to 'community' correctly, both at the root
// level and for a specific existing forum.
- $this->assertUrlInboundAlter('community', 'forum');
+ $this->drupalGet('community');
+ $this->assertText('General discussion', 'The community path gets resolved correctly');
$this->assertUrlOutboundAlter('forum', 'community');
$forum_vid = config('forum.settings')->get('vocabulary');
+ $term_name = $this->randomName();
$tid = db_insert('taxonomy_term_data')
->fields(array(
- 'name' => $this->randomName(),
+ 'name' => $term_name,
'vid' => $forum_vid,
))
->execute();
- $this->assertUrlInboundAlter("community/$tid", "forum/$tid");
+ $this->drupalGet("community/$tid");
+ $this->assertText($term_name, 'The community/{tid} path gets resolved correctly');
$this->assertUrlOutboundAlter("forum/$tid", "community/$tid");
}
@@ -88,14 +90,6 @@ class UrlAlterFunctionalTest extends WebTestBase {
}
/**
- * Tests that current_path() is initialized when the request path is empty.
- */
- function testGetQInitialized() {
- $this->drupalGet('');
- $this->assertText("current_path() is non-empty with an empty request path.", 'current_path() is initialized with an empty request path.');
- }
-
- /**
* Assert that an outbound path is altered to an expected value.
*
* @param $original
@@ -118,7 +112,7 @@ class UrlAlterFunctionalTest extends WebTestBase {
*
* @param $original
* A string with the aliased or un-normal path that is run through
- * drupal_get_normal_path().
+ * drupal_container()->get('path.alias_manager')->getSystemPath().
* @param $final
* A string with the expected result after url().
* @return
@@ -126,7 +120,7 @@ class UrlAlterFunctionalTest extends WebTestBase {
*/
protected function assertUrlInboundAlter($original, $final) {
// Test inbound altering.
- $result = drupal_get_normal_path($original);
+ $result = drupal_container()->get('path.alias_manager')->getSystemPath($original);
$this->assertIdentical($result, $final, format_string('Altered inbound URL %original, expected %final, and got %result.', array('%original' => $original, '%final' => $final, '%result' => $result)));
}
}
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 3a07fa2..25691bd 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -1410,10 +1410,11 @@ function system_site_information_settings($form, &$form_state) {
'#type' => 'fieldset',
'#title' => t('Front page'),
);
+ $front_page = $site_config->get('page.front') != 'user' ? drupal_container()->get('path.alias_manager')->getPathAlias($site_config->get('page.front')) : '';
$form['front_page']['site_frontpage'] = array(
'#type' => 'textfield',
'#title' => t('Default front page'),
- '#default_value' => ($site_config->get('page.front') != 'user' ? drupal_get_path_alias($site_config->get('page.front')) : ''),
+ '#default_value' => $front_page,
'#size' => 40,
'#description' => t('Optionally, specify a relative URL to display as the front page. Leave blank to display the default front page.'),
'#field_prefix' => url(NULL, array('absolute' => TRUE)),
@@ -1455,7 +1456,7 @@ function system_site_information_settings_validate($form, &$form_state) {
}
else {
// Get the normal path of the front page.
- form_set_value($form['front_page']['site_frontpage'], drupal_get_normal_path($form_state['values']['site_frontpage']), $form_state);
+ form_set_value($form['front_page']['site_frontpage'], drupal_container()->get('path.alias_manager')->getSystemPath($form_state['values']['site_frontpage']), $form_state);
}
// Validate front page path.
if (!drupal_valid_path($form_state['values']['site_frontpage'])) {
@@ -1463,10 +1464,10 @@ function system_site_information_settings_validate($form, &$form_state) {
}
// Get the normal paths of both error pages.
if (!empty($form_state['values']['site_403'])) {
- form_set_value($form['error_page']['site_403'], drupal_get_normal_path($form_state['values']['site_403']), $form_state);
+ form_set_value($form['error_page']['site_403'], drupal_container()->get('path.alias_manager')->getSystemPath($form_state['values']['site_403']), $form_state);
}
if (!empty($form_state['values']['site_404'])) {
- form_set_value($form['error_page']['site_404'], drupal_get_normal_path($form_state['values']['site_404']), $form_state);
+ form_set_value($form['error_page']['site_404'], drupal_container()->get('path.alias_manager')->getSystemPath($form_state['values']['site_404']), $form_state);
}
// Validate 403 error path.
if (!empty($form_state['values']['site_403']) && !drupal_valid_path($form_state['values']['site_403'])) {
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index e9c0860..239d3a2 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -3476,7 +3476,7 @@ function hook_system_themes_page_alter(&$theme_groups) {
* @param $path_language
* The language of the path.
*
- * @see drupal_get_normal_path()
+ * @see \Drupal\Core\Path\AliasManager::getSystemPath()
*/
function hook_url_inbound_alter(&$path, $original_path, $path_language) {
// Create the path user/me/edit, which allows a user to edit their account.
diff --git a/core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/PathSubscriber.php b/core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/PathSubscriber.php
new file mode 100644
index 0000000..3f4f728
--- /dev/null
+++ b/core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/PathSubscriber.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\url_alter_test\PathSubscriber.
+ */
+
+namespace Drupal\url_alter_test;
+
+use Drupal\Core\EventSubscriber\PathListenerBase;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Path subscriber for url_alter_test.
+ */
+class PathSubscriber extends PathListenerBase implements EventSubscriberInterface {
+
+ /**
+ * Resolve the system path based on some arbitrary rules.
+ *
+ * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+ * The Event to process.
+ */
+ public function onKernelRequestPathResolve(GetResponseEvent $event) {
+ $request = $event->getRequest();
+ $path = $this->extractPath($request);
+ // Rewrite user/username to user/uid.
+ if (preg_match('!^user/([^/]+)(/.*)?!', $path, $matches)) {
+ if ($account = user_load_by_name($matches[1])) {
+ $matches += array(2 => '');
+ $path = 'user/' . $account->uid . $matches[2];
+ }
+ }
+
+ // Rewrite community/ to forum/.
+ if ($path == 'community' || strpos($path, 'community/') === 0) {
+ $path = 'forum' . substr($path, 9);
+ }
+
+ if ($path == 'url-alter-test/bar') {
+ $path = 'url-alter-test/foo';
+ }
+
+ $this->setPath($request, $path);
+ }
+
+ /**
+ * Registers the methods in this class that should be listeners.
+ *
+ * @return array
+ * An array of event listener definitions.
+ */
+ static function getSubscribedEvents() {
+ $events[KernelEvents::REQUEST][] = array('onKernelRequestPathResolve', 100);
+ return $events;
+ }
+}
diff --git a/core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/UrlAlterTestBundle.php b/core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/UrlAlterTestBundle.php
new file mode 100644
index 0000000..cd028e8
--- /dev/null
+++ b/core/modules/system/tests/modules/url_alter_test/lib/Drupal/url_alter_test/UrlAlterTestBundle.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\url_alter_test\UrlAlterTestBundle.
+ */
+
+namespace Drupal\url_alter_test;
+
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpKernel\Bundle\Bundle;
+
+/**
+ * Test bundle class for url_alter_test.
+ *
+ * Used to register an event subscriber that resolves a path alias to a system
+ * path based on an arbitrary set of rules.
+ *
+ * @see \Drupal\url_alter_test\PathSubscriber
+ */
+class UrlAlterTestBundle extends Bundle
+{
+ public function build(ContainerBuilder $container) {
+ $container->register('url_alter_test.path_subscriber', 'Drupal\url_alter_test\PathSubscriber')
+ ->addTag('event_subscriber');
+ }
+}
diff --git a/core/modules/system/tests/modules/url_alter_test/url_alter_test.module b/core/modules/system/tests/modules/url_alter_test/url_alter_test.module
index a5ca13d..61cc625 100644
--- a/core/modules/system/tests/modules/url_alter_test/url_alter_test.module
+++ b/core/modules/system/tests/modules/url_alter_test/url_alter_test.module
@@ -27,32 +27,6 @@ function url_alter_test_foo() {
}
/**
- * Implements hook_url_inbound_alter().
- */
-function url_alter_test_url_inbound_alter(&$path, $original_path, $path_language) {
- if (!request_path() && current_path()) {
- drupal_set_message("current_path() is non-empty with an empty request path.");
- }
-
- // Rewrite user/username to user/uid.
- if (preg_match('!^user/([^/]+)(/.*)?!', $path, $matches)) {
- if ($account = user_load_by_name($matches[1])) {
- $matches += array(2 => '');
- $path = 'user/' . $account->uid . $matches[2];
- }
- }
-
- // Rewrite community/ to forum/.
- if ($path == 'community' || strpos($path, 'community/') === 0) {
- $path = 'forum' . substr($path, 9);
- }
-
- if ($path == 'url-alter-test/bar') {
- $path = 'url-alter-test/foo';
- }
-}
-
-/**
* Implements hook_url_outbound_alter().
*/
function url_alter_test_url_outbound_alter(&$path, &$options, $original_path) {
diff --git a/core/modules/views/views_ui/views_ui.module b/core/modules/views/views_ui/views_ui.module
index b7040ac..9a814d5 100644
--- a/core/modules/views/views_ui/views_ui.module
+++ b/core/modules/views/views_ui/views_ui.module
@@ -718,7 +718,7 @@ function views_ui_views_analyze($view) {
continue;
}
if ($display->hasPath() && $path = $display->getOption('path')) {
- $normal_path = drupal_get_normal_path($path);
+ $normal_path = drupal_container()->get('path.alias_manager')->getSystemPath($path);
if ($path != $normal_path) {
$ret[] = Analyzer::formatMessage(t('You have configured display %display with a path which is an path alias as well. This might lead to unwanted effects so better use an internal path.', array('%display' => $display['display_title'])), 'warning');
}
diff --git a/core/scripts/generate-d7-content.sh b/core/scripts/generate-d7-content.sh
index acfc1a3..5f03ab2 100644
--- a/core/scripts/generate-d7-content.sh
+++ b/core/scripts/generate-d7-content.sh
@@ -252,7 +252,7 @@ for ($i = 0; $i < 12; $i++) {
'alias' => "content/poll/$i/results",
'source' => "node/$node->nid/results",
);
- path_save($path);
+ drupal_container()->get('path.crud')->save($path['source'], $path['alias']);
// Add some votes
$node = node_load($node->nid);