Commit ac120e26 authored by catch's avatar catch

Issue #2209145 by slashrsm, fgm, chx: Move all path alias SQL queries to a...

Issue #2209145 by slashrsm, fgm, chx: Move all path alias SQL queries to a single storage controller.
parent 55b0a054
......@@ -146,7 +146,7 @@ services:
class: Drupal\Core\Path\AliasWhitelist
tags:
- { name: needs_destruction }
arguments: [path_alias_whitelist, '@cache.default', '@lock', '@state', '@database']
arguments: [path_alias_whitelist, '@cache.default', '@lock', '@state', '@path.alias_storage']
path.alias_manager:
class: Drupal\Core\Path\AliasManager
arguments: ['@path.alias_storage', '@path.alias_whitelist', '@language_manager']
......
......@@ -185,4 +185,83 @@ public function lookupPathSource($path, $langcode) {
return $result->fetchField();
}
/**
* Checks if alias already exists.
*
* @param string $alias
* Alias to check against.
* @param string $langcode
* Language of the alias.
* @param string $source
* Path that alias is to be assigned to (optional).
* @return boolean
* TRUE if alias already exists and FALSE otherwise.
*/
public function aliasExists($alias, $langcode, $source = NULL) {
$query = $this->connection->select('url_alias')
->condition('alias', $alias)
->condition('langcode', $langcode);
if (!empty($source)) {
$query->condition('source', $source, '<>');
}
$query->addExpression('1');
$query->range(0, 1);
return (bool) $query->execute()->fetchField();
}
/**
* Checks if there are any aliases with language defined.
*
* @return bool
* TRUE if aliases with language exist.
*/
public function languageAliasExists() {
return (bool) $this->connection->queryRange('SELECT 1 FROM {url_alias} WHERE langcode <> :langcode', 0, 1, array(':langcode' => Language::LANGCODE_NOT_SPECIFIED))->fetchField();
}
/**
* Loads aliases for admin listing.
*
* @param array $header
* Table header.
* @param string $keys
* Search keys.
* @return array
* Array of items to be displayed on the current page.
*/
public function getAliasesForAdminListing($header, $keys = NULL) {
$query = $this->connection->select('url_alias')
->extend('Drupal\Core\Database\Query\PagerSelectExtender')
->extend('Drupal\Core\Database\Query\TableSortExtender');
if ($keys) {
// Replace wildcards with PDO wildcards.
$query->condition('alias', '%' . preg_replace('!\*+!', '%', $keys) . '%', 'LIKE');
}
return $query
->fields('url_alias')
->orderByHeader($header)
->limit(50)
->execute()
->fetchAll();
}
/**
* Check if any alias exists starting with $initial_substring.
*
* @param $initial_substring
* Initial path substring to test against.
*
* @return
* TRUE if any alias exists, FALSE otherwise.
*/
public function pathHasMatchingAlias($initial_substring) {
$query = $this->connection->select('url_alias', 'u');
$query->addExpression(1);
return (bool) $query
->condition('u.source', $this->connection->escapeLike($initial_substring) . '%', 'LIKE')
->range(0, 1)
->execute()
->fetchField();
}
}
......@@ -26,11 +26,11 @@ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface {
protected $state;
/**
* The database connection.
* The Path CRUD service.
*
* @var \Drupal\Core\Database\Connection
* @var \Drupal\Core\Path\AliasStorageInterface
*/
protected $connection;
protected $aliasStorage;
/**
* Constructs an AliasWhitelist object.
......@@ -43,13 +43,13 @@ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface {
* The lock backend.
* @param \Drupal\Core\KeyValueStore\StateInterface $state
* The state keyvalue store.
* @param \Drupal\Core\Database\Connection $connection
* The database connection.
* @param \Drupal\Core\Path\AliasStorageInterface $alias_storage
* The alias storage service.
*/
public function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $lock, StateInterface $state, Connection $connection) {
public function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $lock, StateInterface $state, AliasStorageInterface $alias_storage) {
parent::__construct($cid, $cache, $lock);
$this->state = $state;
$this->connection = $connection;
$this->aliasStorage = $alias_storage;
}
/**
......@@ -107,13 +107,7 @@ public function get($offset) {
* {@inheritdoc}
*/
public function resolveCacheMiss($root) {
$query = $this->connection->select('url_alias', 'u');
$query->addExpression(1);
$exists = (bool) $query
->condition('u.source', $this->connection->escapeLike($root) . '%', 'LIKE')
->range(0, 1)
->execute()
->fetchField();
$exists = $this->aliasStorage->pathHasMatchingAlias($root);
$this->storage[$root] = $exists;
$this->persist($root);
if ($exists) {
......
......@@ -39,7 +39,7 @@ class UrlAlias extends DestinationBase implements ContainerFactoryPluginInterfac
* @param MigrationInterface $migration
* The migration.
* @param \Drupal\Core\Path\AliasStorage $alias_storage
* The path crud service.
* The alias storage service.
*/
public function __construct(array $configuration, $plugin_id, array $plugin_definition, MigrationInterface $migration, AliasStorage $alias_storage) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
......
......@@ -22,8 +22,7 @@ function path_admin_overview($keys = NULL) {
$build['path_admin_filter_form'] = \Drupal::formBuilder()->getForm('path_admin_filter_form', $keys);
// Enable language column if language.module is enabled or if we have any
// alias with a language.
$alias_exists = (bool) db_query_range('SELECT 1 FROM {url_alias} WHERE langcode <> :langcode', 0, 1, array(':langcode' => Language::LANGCODE_NOT_SPECIFIED))->fetchField();
$multilanguage = (\Drupal::moduleHandler()->moduleExists('language') || $alias_exists);
$multilanguage = (\Drupal::moduleHandler()->moduleExists('language') || \Drupal::service('path.alias_storage')->languageAliasExists());
$header = array();
$header[] = array('data' => t('Alias'), 'field' => 'alias', 'sort' => 'asc');
......@@ -33,22 +32,11 @@ function path_admin_overview($keys = NULL) {
}
$header[] = t('Operations');
$query = db_select('url_alias')
->extend('Drupal\Core\Database\Query\PagerSelectExtender')
->extend('Drupal\Core\Database\Query\TableSortExtender');
if ($keys) {
// Replace wildcards with PDO wildcards.
$query->condition('alias', '%' . preg_replace('!\*+!', '%', $keys) . '%', 'LIKE');
}
$result = $query
->fields('url_alias')
->orderByHeader($header)
->limit(50)
->execute();
$rows = array();
$destination = drupal_get_destination();
foreach ($result as $data) {
/** @var \Drupal\core\Path\AliasStorage $alias_storage */
$alias_storage = \Drupal::service('path.alias_storage');
foreach ($alias_storage->getAliasesForAdminListing($header, $keys) as $data) {
$row = array();
$row['data']['alias'] = l(truncate_utf8($data->alias, 50, FALSE, TRUE), $data->source, array(
'attributes' => array('title' => $data->alias),
......@@ -230,19 +218,11 @@ function path_admin_form_validate($form, &$form_state) {
$source = &$form_state['values']['source'];
$source = \Drupal::service('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
// languages.
$langcode = isset($form_state['values']['langcode']) ? $form_state['values']['langcode'] : Language::LANGCODE_NOT_SPECIFIED;
$has_alias = db_query("SELECT COUNT(alias) FROM {url_alias} WHERE pid <> :pid AND alias = :alias AND langcode = :langcode", array(
':pid' => $pid,
':alias' => $alias,
':langcode' => $langcode,
))
->fetchField();
if ($has_alias) {
if (\Drupal::service('path.alias_storage')->aliasExists($alias, $langcode, $source)) {
form_set_error('alias', $form_state, t('The alias %alias is already in use in this language.', array('%alias' => $alias)));
}
if (!drupal_valid_path($source)) {
......
......@@ -131,15 +131,7 @@ function path_form_element_validate($element, &$form_state, $complete_form) {
$path = $form_state['values']['path'];
// Ensure that the submitted alias does not exist yet.
$query = db_select('url_alias')
->condition('alias', $path['alias'])
->condition('langcode', $path['langcode']);
if (!empty($path['source'])) {
$query->condition('source', $path['source'], '<>');
}
$query->addExpression('1');
$query->range(0, 1);
if ($query->execute()->fetchField()) {
if (\Drupal::service('path.alias_storage')->aliasExists($path['alias'], $path['langcode'], $path['source'])) {
form_error($element, $form_state, t('The alias is already in use.'));
}
}
......
......@@ -168,8 +168,8 @@ function testWhitelist() {
$memoryCounterBackend = new MemoryCounterBackend('default');
// Create AliasManager and Path object.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $connection);
$aliasStorage = new AliasStorage($connection, $this->container->get('module_handler'));
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $aliasStorage);
$aliasManager = new AliasManager($aliasStorage, $whitelist, $this->container->get('language_manager'));
// No alias for user and admin yet, so should be NULL.
......@@ -208,7 +208,7 @@ function testWhitelist() {
// Re-initialize the whitelist using the same cache backend, should load
// from cache.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $connection);
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $aliasStorage);
$this->assertNull($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomName()));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment