AliasStorage.php in Zircon Profile 8
Same filename and directory in other branches
Contains \Drupal\Core\Path\AliasStorage.
Namespace
Drupal\Core\PathFile
core/lib/Drupal/Core/Path/AliasStorage.phpView source
<?php
/**
* @file
* Contains \Drupal\Core\Path\AliasStorage.
*/
namespace Drupal\Core\Path;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Database\Connection;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Database\Query\Condition;
/**
* Provides a class for CRUD operations on path aliases.
*
* All queries perform case-insensitive matching on the 'source' and 'alias'
* fields, so the aliases '/test-alias' and '/test-Alias' are considered to be
* the same, and will both refer to the same internal system path.
*/
class AliasStorage implements AliasStorageInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* The module handler.
*
* @var \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected $moduleHandler;
/**
* Constructs a Path CRUD object.
*
* @param \Drupal\Core\Database\Connection $connection
* A database connection for reading and writing path aliases.
*
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
* The module handler.
*/
public function __construct(Connection $connection, ModuleHandlerInterface $module_handler) {
$this->connection = $connection;
$this->moduleHandler = $module_handler;
}
/**
* {@inheritdoc}
*/
public function save($source, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid = NULL) {
if ($source[0] !== '/') {
throw new \InvalidArgumentException(sprintf('Source path %s has to start with a slash.', $source));
}
if ($alias[0] !== '/') {
throw new \InvalidArgumentException(sprintf('Alias path %s has to start with a slash.', $alias));
}
$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;
$operation = 'insert';
}
else {
// Fetch the current values so that an update hook can identify what
// exactly changed.
$original = $this->connection
->query('SELECT source, alias, langcode FROM {url_alias} WHERE pid = :pid', array(
':pid' => $pid,
))
->fetchAssoc();
$fields['pid'] = $pid;
$query = $this->connection
->update('url_alias')
->fields($fields)
->condition('pid', $pid);
$pid = $query
->execute();
$fields['original'] = $original;
$operation = 'update';
}
if ($pid) {
// @todo Switch to using an event for this instead of a hook.
$this->moduleHandler
->invokeAll('path_' . $operation, array(
$fields,
));
Cache::invalidateTags([
'route_match',
]);
return $fields;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function load($conditions) {
$select = $this->connection
->select('url_alias');
foreach ($conditions as $field => $value) {
if ($field == 'source' || $field == 'alias') {
// Use LIKE for case-insensitive matching.
$select
->condition($field, $this->connection
->escapeLike($value), 'LIKE');
}
else {
$select
->condition($field, $value);
}
}
return $select
->fields('url_alias')
->orderBy('pid', 'DESC')
->range(0, 1)
->execute()
->fetchAssoc();
}
/**
* {@inheritdoc}
*/
public function delete($conditions) {
$path = $this
->load($conditions);
$query = $this->connection
->delete('url_alias');
foreach ($conditions as $field => $value) {
if ($field == 'source' || $field == 'alias') {
// Use LIKE for case-insensitive matching.
$query
->condition($field, $this->connection
->escapeLike($value), 'LIKE');
}
else {
$query
->condition($field, $value);
}
}
$deleted = $query
->execute();
// @todo Switch to using an event for this instead of a hook.
$this->moduleHandler
->invokeAll('path_delete', array(
$path,
));
Cache::invalidateTags([
'route_match',
]);
return $deleted;
}
/**
* {@inheritdoc}
*/
public function preloadPathAlias($preloaded, $langcode) {
$langcode_list = [
$langcode,
LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
$select = $this->connection
->select('url_alias')
->fields('url_alias', [
'source',
'alias',
]);
if (!empty($preloaded)) {
$conditions = new Condition('OR');
foreach ($preloaded as $preloaded_item) {
$conditions
->condition('source', $this->connection
->escapeLike($preloaded_item), 'LIKE');
}
$select
->condition($conditions);
}
// 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.
if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
array_pop($langcode_list);
}
elseif ($langcode < LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$select
->orderBy('langcode', 'ASC');
}
else {
$select
->orderBy('langcode', 'DESC');
}
$select
->orderBy('pid', 'ASC');
$select
->condition('langcode', $langcode_list, 'IN');
return $select
->execute()
->fetchAllKeyed();
}
/**
* {@inheritdoc}
*/
public function lookupPathAlias($path, $langcode) {
$source = $this->connection
->escapeLike($path);
$langcode_list = [
$langcode,
LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
// See the queries above. Use LIKE for case-insensitive matching.
$select = $this->connection
->select('url_alias')
->fields('url_alias', [
'alias',
])
->condition('source', $source, 'LIKE');
if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
array_pop($langcode_list);
}
elseif ($langcode > LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$select
->orderBy('langcode', 'DESC');
}
else {
$select
->orderBy('langcode', 'ASC');
}
$select
->orderBy('pid', 'DESC');
$select
->condition('langcode', $langcode_list, 'IN');
return $select
->execute()
->fetchField();
}
/**
* {@inheritdoc}
*/
public function lookupPathSource($path, $langcode) {
$alias = $this->connection
->escapeLike($path);
$langcode_list = [
$langcode,
LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
// See the queries above. Use LIKE for case-insensitive matching.
$select = $this->connection
->select('url_alias')
->fields('url_alias', [
'source',
])
->condition('alias', $alias, 'LIKE');
if ($langcode == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
array_pop($langcode_list);
}
elseif ($langcode > LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$select
->orderBy('langcode', 'DESC');
}
else {
$select
->orderBy('langcode', 'ASC');
}
$select
->orderBy('pid', 'DESC');
$select
->condition('langcode', $langcode_list, 'IN');
return $select
->execute()
->fetchField();
}
/**
* {@inheritdoc}
*/
public function aliasExists($alias, $langcode, $source = NULL) {
// Use LIKE and NOT LIKE for case-insensitive matching.
$query = $this->connection
->select('url_alias')
->condition('alias', $this->connection
->escapeLike($alias), 'LIKE')
->condition('langcode', $langcode);
if (!empty($source)) {
$query
->condition('source', $this->connection
->escapeLike($source), 'NOT LIKE');
}
$query
->addExpression('1');
$query
->range(0, 1);
return (bool) $query
->execute()
->fetchField();
}
/**
* {@inheritdoc}
*/
public function languageAliasExists() {
return (bool) $this->connection
->queryRange('SELECT 1 FROM {url_alias} WHERE langcode <> :langcode', 0, 1, array(
':langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
))
->fetchField();
}
/**
* {@inheritdoc}
*/
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();
}
/**
* {@inheritdoc}
*/
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();
}
}
Classes
Name | Description |
---|---|
AliasStorage | Provides a class for CRUD operations on path aliases. |