Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 11 |
CRAP | |
0.00% |
0 / 161 |
| AliasStorage | |
0.00% |
0 / 1 |
|
0.00% |
0 / 11 |
992 | |
0.00% |
0 / 161 |
| __construct | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 3 |
|||
| save | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 35 |
|||
| load | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 16 |
|||
| delete | |
0.00% |
0 / 1 |
20 | |
0.00% |
0 / 15 |
|||
| preloadPathAlias | |
0.00% |
0 / 1 |
30 | |
0.00% |
0 / 23 |
|||
| lookupPathAlias | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 18 |
|||
| lookupPathSource | |
0.00% |
0 / 1 |
12 | |
0.00% |
0 / 18 |
|||
| aliasExists | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 10 |
|||
| languageAliasExists | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 2 |
|||
| getAliasesForAdminListing | |
0.00% |
0 / 1 |
6 | |
0.00% |
0 / 13 |
|||
| pathHasMatchingAlias | |
0.00% |
0 / 1 |
2 | |
0.00% |
0 / 8 |
|||
| <?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(); | |
| } | |
| } |