Issue #2233595 by amateescu, marcingy, SpartyDan, visabhishek, Sharique, carletex, slashrsm, hanoii, plach, Berdir, xjm: Deprecate the custom path alias storage

merge-requests/2419/head
catch 2019-10-24 09:35:41 +01:00
parent bf51490e46
commit bdf48170cd
37 changed files with 965 additions and 507 deletions

View File

@ -465,10 +465,10 @@ services:
class: Drupal\Core\Path\AliasWhitelist class: Drupal\Core\Path\AliasWhitelist
tags: tags:
- { name: needs_destruction } - { name: needs_destruction }
arguments: [path_alias_whitelist, '@cache.bootstrap', '@lock', '@state', '@path.alias_storage'] arguments: [path_alias_whitelist, '@cache.bootstrap', '@lock', '@state', '@path.alias_repository']
path.alias_manager: path.alias_manager:
class: Drupal\Core\Path\AliasManager class: Drupal\Core\Path\AliasManager
arguments: ['@path.alias_storage', '@path.alias_whitelist', '@language_manager', '@cache.data'] arguments: ['@path.alias_repository', '@path.alias_whitelist', '@language_manager', '@cache.data']
path.current: path.current:
class: Drupal\Core\Path\CurrentPathStack class: Drupal\Core\Path\CurrentPathStack
arguments: ['@request_stack'] arguments: ['@request_stack']
@ -960,11 +960,17 @@ services:
arguments: ['@lock', '@plugin.manager.menu.link', '@database', '@database.replica_kill_switch'] arguments: ['@lock', '@plugin.manager.menu.link', '@database', '@database.replica_kill_switch']
tags: tags:
- { name: event_subscriber } - { name: event_subscriber }
path.alias_repository:
class: Drupal\Core\Path\AliasRepository
arguments: ['@database']
tags:
- { name: backend_overridable }
path.alias_storage: path.alias_storage:
class: Drupal\Core\Path\AliasStorage class: Drupal\Core\Path\AliasStorage
arguments: ['@database', '@module_handler', '@entity_type.manager'] arguments: ['@database', '@module_handler', '@entity_type.manager']
tags: tags:
- { name: backend_overridable } - { name: backend_overridable }
deprecated: The "%service_id%" service is deprecated. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865
path.matcher: path.matcher:
class: Drupal\Core\Path\PathMatcher class: Drupal\Core\Path\PathMatcher
arguments: ['@config.factory', '@current_route_match'] arguments: ['@config.factory', '@current_route_match']

View File

@ -4,6 +4,7 @@ namespace Drupal\Core\Path;
use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\CacheDecorator\CacheDecoratorInterface; use Drupal\Core\CacheDecorator\CacheDecoratorInterface;
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\Language\LanguageManagerInterface;
@ -12,12 +13,19 @@ use Drupal\Core\Language\LanguageManagerInterface;
*/ */
class AliasManager implements AliasManagerInterface, CacheDecoratorInterface { class AliasManager implements AliasManagerInterface, CacheDecoratorInterface {
use DeprecatedServicePropertyTrait;
/** /**
* The alias storage service. * {@inheritdoc}
*
* @var \Drupal\Core\Path\AliasStorageInterface
*/ */
protected $storage; protected $deprecatedProperties = ['storage' => 'path.alias_storage'];
/**
* The path alias repository.
*
* @var \Drupal\Core\Path\AliasRepositoryInterface
*/
protected $pathAliasRepository;
/** /**
* Cache backend service. * Cache backend service.
@ -95,8 +103,8 @@ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface {
/** /**
* Constructs an AliasManager. * Constructs an AliasManager.
* *
* @param \Drupal\Core\Path\AliasStorageInterface $storage * @param \Drupal\Core\Path\AliasRepositoryInterface $alias_repository
* The alias storage service. * The path alias repository.
* @param \Drupal\Core\Path\AliasWhitelistInterface $whitelist * @param \Drupal\Core\Path\AliasWhitelistInterface $whitelist
* The whitelist implementation to use. * The whitelist implementation to use.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
@ -104,8 +112,12 @@ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface {
* @param \Drupal\Core\Cache\CacheBackendInterface $cache * @param \Drupal\Core\Cache\CacheBackendInterface $cache
* Cache backend. * Cache backend.
*/ */
public function __construct(AliasStorageInterface $storage, AliasWhitelistInterface $whitelist, LanguageManagerInterface $language_manager, CacheBackendInterface $cache) { public function __construct($alias_repository, AliasWhitelistInterface $whitelist, LanguageManagerInterface $language_manager, CacheBackendInterface $cache) {
$this->storage = $storage; if (!$alias_repository instanceof AliasRepositoryInterface) {
@trigger_error('Passing the path.alias_storage service to AliasManager::__construct() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Pass the new dependencies instead. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED);
$alias_repository = \Drupal::service('path.alias_repository');
}
$this->pathAliasRepository = $alias_repository;
$this->languageManager = $language_manager; $this->languageManager = $language_manager;
$this->whitelist = $whitelist; $this->whitelist = $whitelist;
$this->cache = $cache; $this->cache = $cache;
@ -166,9 +178,9 @@ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface {
} }
// Look for path in storage. // Look for path in storage.
if ($path = $this->storage->lookupPathSource($alias, $langcode)) { if ($path_alias = $this->pathAliasRepository->lookupByAlias($alias, $langcode)) {
$this->lookupMap[$langcode][$path] = $alias; $this->lookupMap[$langcode][$path_alias['path']] = $alias;
return $path; return $path_alias['path'];
} }
// We can't record anything into $this->lookupMap because we didn't find any // We can't record anything into $this->lookupMap because we didn't find any
@ -220,7 +232,7 @@ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface {
// Load paths from cache. // Load paths from cache.
if (!empty($this->preloadedPathLookups[$langcode])) { if (!empty($this->preloadedPathLookups[$langcode])) {
$this->lookupMap[$langcode] = $this->storage->preloadPathAlias($this->preloadedPathLookups[$langcode], $langcode); $this->lookupMap[$langcode] = $this->pathAliasRepository->preloadPathAlias($this->preloadedPathLookups[$langcode], $langcode);
// Keep a record of paths with no alias to avoid querying twice. // Keep a record of paths with no alias to avoid querying twice.
$this->noAlias[$langcode] = array_flip(array_diff_key($this->preloadedPathLookups[$langcode], array_keys($this->lookupMap[$langcode]))); $this->noAlias[$langcode] = array_flip(array_diff_key($this->preloadedPathLookups[$langcode], array_keys($this->lookupMap[$langcode])));
} }
@ -237,9 +249,9 @@ class AliasManager implements AliasManagerInterface, CacheDecoratorInterface {
} }
// Try to load alias from storage. // Try to load alias from storage.
if ($alias = $this->storage->lookupPathAlias($path, $langcode)) { if ($path_alias = $this->pathAliasRepository->lookupBySystemPath($path, $langcode)) {
$this->lookupMap[$langcode][$path] = $alias; $this->lookupMap[$langcode][$path] = $path_alias['alias'];
return $alias; return $path_alias['alias'];
} }
// We can't record anything into $this->lookupMap because we didn't find any // We can't record anything into $this->lookupMap because we didn't find any

View File

@ -4,8 +4,6 @@ namespace Drupal\Core\Path;
/** /**
* Find an alias for a path and vice versa. * Find an alias for a path and vice versa.
*
* @see \Drupal\Core\Path\AliasStorageInterface
*/ */
interface AliasManagerInterface { interface AliasManagerInterface {

View File

@ -0,0 +1,142 @@
<?php
namespace Drupal\Core\Path;
use Drupal\Core\Database\Connection;
use Drupal\Core\Database\Query\Condition;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\Language\LanguageInterface;
/**
* Provides the default path alias lookup operations.
*/
class AliasRepository implements AliasRepositoryInterface {
/**
* The database connection.
*
* @var \Drupal\Core\Database\Connection
*/
protected $connection;
/**
* Constructs an AliasRepository object.
*
* @param \Drupal\Core\Database\Connection $connection
* A database connection for reading and writing path aliases.
*/
public function __construct(Connection $connection) {
$this->connection = $connection;
}
/**
* {@inheritdoc}
*/
public function preloadPathAlias($preloaded, $langcode) {
$select = $this->getBaseQuery()
->fields('base_table', ['path', 'alias']);
if (!empty($preloaded)) {
$conditions = new Condition('OR');
foreach ($preloaded as $preloaded_item) {
$conditions->condition('base_table.path', $this->connection->escapeLike($preloaded_item), 'LIKE');
}
$select->condition($conditions);
}
$this->addLanguageFallback($select, $langcode);
// We order by ID ASC so that fetchAllKeyed() returns the most recently
// created alias for each source. Subsequent queries using fetchField() must
// use ID DESC to have the same effect.
$select->orderBy('base_table.id', 'ASC');
return $select->execute()->fetchAllKeyed();
}
/**
* {@inheritdoc}
*/
public function lookupBySystemPath($path, $langcode) {
// See the queries above. Use LIKE for case-insensitive matching.
$select = $this->getBaseQuery()
->fields('base_table', ['id', 'path', 'alias', 'langcode'])
->condition('base_table.path', $this->connection->escapeLike($path), 'LIKE');
$this->addLanguageFallback($select, $langcode);
$select->orderBy('base_table.id', 'DESC');
return $select->execute()->fetchAssoc() ?: NULL;
}
/**
* {@inheritdoc}
*/
public function lookupByAlias($alias, $langcode) {
// See the queries above. Use LIKE for case-insensitive matching.
$select = $this->getBaseQuery()
->fields('base_table', ['id', 'path', 'alias', 'langcode'])
->condition('base_table.alias', $this->connection->escapeLike($alias), 'LIKE');
$this->addLanguageFallback($select, $langcode);
$select->orderBy('base_table.id', 'DESC');
return $select->execute()->fetchAssoc() ?: NULL;
}
/**
* {@inheritdoc}
*/
public function pathHasMatchingAlias($initial_substring) {
$query = $this->getBaseQuery();
$query->addExpression(1);
return (bool) $query
->condition('base_table.path', $this->connection->escapeLike($initial_substring) . '%', 'LIKE')
->range(0, 1)
->execute()
->fetchField();
}
/**
* Returns a SELECT query for the path_alias base table.
*
* @return \Drupal\Core\Database\Query\SelectInterface
* A Select query object.
*/
protected function getBaseQuery() {
$query = $this->connection->select('path_alias', 'base_table');
$query->condition('base_table.status', 1);
return $query;
}
/**
* Adds path alias language fallback conditions to a select query object.
*
* @param \Drupal\Core\Database\Query\SelectInterface $query
* A Select query object.
* @param string $langcode
* Language code to search the path with. If there's no path defined for
* that language it will search paths without language.
*/
protected function addLanguageFallback(SelectInterface $query, $langcode) {
// 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.
$langcode_list = [$langcode, LanguageInterface::LANGCODE_NOT_SPECIFIED];
if ($langcode === LanguageInterface::LANGCODE_NOT_SPECIFIED) {
array_pop($langcode_list);
}
elseif ($langcode > LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$query->orderBy('base_table.langcode', 'DESC');
}
else {
$query->orderBy('base_table.langcode', 'ASC');
}
$query->condition('base_table.langcode', $langcode_list, 'IN');
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace Drupal\Core\Path;
/**
* Provides an interface for path alias lookup operations.
*
* The path alias repository service is only used internally in order to
* optimize alias lookup queries needed in the critical path of each request.
* However, it is not marked as an internal service because alternative storage
* backends still need to override it if they provide a different storage class
* for the PathAlias entity type.
*
* Whenever you need to determine whether an alias exists for a system path, or
* whether a system path has an alias, the 'path.alias_manager' service should
* be used instead.
*/
interface AliasRepositoryInterface {
/**
* Pre-loads path alias information for a given list of system paths.
*
* @param array $preloaded
* System paths that need preloading of aliases.
* @param string $langcode
* Language code to search the path with. If there's no path defined for
* that language it will search paths without language.
*
* @return string[]
* System paths (keys) to alias (values) mapping.
*/
public function preloadPathAlias($preloaded, $langcode);
/**
* Searches a path alias for a given Drupal system path.
*
* The default implementation performs case-insensitive matching on the
* 'path' and 'alias' strings.
*
* @param string $path
* The system path to investigate for corresponding path aliases.
* @param string $langcode
* Language code to search the path with. If there's no path defined for
* that language it will search paths without language.
*
* @return array|null
* An array containing the 'id', 'path', 'alias' and 'langcode' properties
* of a path alias, or NULL if none was found.
*/
public function lookupBySystemPath($path, $langcode);
/**
* Searches a path alias for a given alias.
*
* The default implementation performs case-insensitive matching on the
* 'path' and 'alias' strings.
*
* @param string $alias
* The alias to investigate for corresponding system paths.
* @param string $langcode
* Language code to search the alias with. If there's no alias defined for
* that language it will search aliases without language.
*
* @return array|null
* An array containing the 'id', 'path', 'alias' and 'langcode' properties
* of a path alias, or NULL if none was found.
*/
public function lookupByAlias($alias, $langcode);
/**
* Check if any alias exists starting with $initial_substring.
*
* @param string $initial_substring
* Initial system path substring to test against.
*
* @return bool
* TRUE if any alias exists, FALSE otherwise.
*/
public function pathHasMatchingAlias($initial_substring);
}

View File

@ -9,12 +9,21 @@ use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
@trigger_error('\Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED);
/** /**
* Provides a class for CRUD operations on path aliases. * Provides a class for CRUD operations on path aliases.
* *
* All queries perform case-insensitive matching on the 'source' and 'alias' * All queries perform case-insensitive matching on the 'source' and 'alias'
* fields, so the aliases '/test-alias' and '/test-Alias' are considered to be * 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. * the same, and will both refer to the same internal system path.
*
* @deprecated \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and
* is removed from drupal:9.0.0. Use the "path.alias_repository" service
* instead, or the entity storage handler for the "path_alias" entity type
* for CRUD methods.
*
* @see https://www.drupal.org/node/3013865
*/ */
class AliasStorage implements AliasStorageInterface { class AliasStorage implements AliasStorageInterface {

View File

@ -6,6 +6,13 @@ use Drupal\Core\Language\LanguageInterface;
/** /**
* Provides a class for CRUD operations on path aliases. * Provides a class for CRUD operations on path aliases.
*
* @deprecated \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and
* is removed from drupal:9.0.0. Use the "path.alias_repository" service
* instead, or the entity storage handler for the "path_alias" entity type
* for CRUD methods.
*
* @see https://www.drupal.org/node/3013865
*/ */
interface AliasStorageInterface { interface AliasStorageInterface {

View File

@ -4,6 +4,7 @@ namespace Drupal\Core\Path;
use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Cache\CacheCollector; use Drupal\Core\Cache\CacheCollector;
use Drupal\Core\DependencyInjection\DeprecatedServicePropertyTrait;
use Drupal\Core\State\StateInterface; use Drupal\Core\State\StateInterface;
use Drupal\Core\Lock\LockBackendInterface; use Drupal\Core\Lock\LockBackendInterface;
@ -12,6 +13,13 @@ use Drupal\Core\Lock\LockBackendInterface;
*/ */
class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface { class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface {
use DeprecatedServicePropertyTrait;
/**
* {@inheritdoc}
*/
protected $deprecatedProperties = ['aliasStorage' => 'path.alias_storage'];
/** /**
* The Key/Value Store to use for state. * The Key/Value Store to use for state.
* *
@ -20,11 +28,11 @@ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface {
protected $state; protected $state;
/** /**
* The Path CRUD service. * The path alias repository.
* *
* @var \Drupal\Core\Path\AliasStorageInterface * @var \Drupal\Core\Path\AliasRepositoryInterface
*/ */
protected $aliasStorage; protected $pathAliasRepository;
/** /**
* Constructs an AliasWhitelist object. * Constructs an AliasWhitelist object.
@ -37,13 +45,18 @@ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface {
* The lock backend. * The lock backend.
* @param \Drupal\Core\State\StateInterface $state * @param \Drupal\Core\State\StateInterface $state
* The state keyvalue store. * The state keyvalue store.
* @param \Drupal\Core\Path\AliasStorageInterface $alias_storage * @param \Drupal\Core\Path\AliasRepositoryInterface $alias_repository
* The alias storage service. * The path alias repository.
*/ */
public function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $lock, StateInterface $state, AliasStorageInterface $alias_storage) { public function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $lock, StateInterface $state, $alias_repository) {
parent::__construct($cid, $cache, $lock); parent::__construct($cid, $cache, $lock);
$this->state = $state; $this->state = $state;
$this->aliasStorage = $alias_storage;
if (!$alias_repository instanceof AliasRepositoryInterface) {
@trigger_error('Passing the path.alias_storage service to AliasWhitelist::__construct() is deprecated in drupal:8.8.0 and will be removed before drupal:9.0.0. Pass the new dependencies instead. See https://www.drupal.org/node/3013865.', E_USER_DEPRECATED);
$alias_repository = \Drupal::service('path.alias_repository');
}
$this->pathAliasRepository = $alias_repository;
} }
/** /**
@ -101,7 +114,7 @@ class AliasWhitelist extends CacheCollector implements AliasWhitelistInterface {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function resolveCacheMiss($root) { public function resolveCacheMiss($root) {
$exists = $this->aliasStorage->pathHasMatchingAlias('/' . $root); $exists = $this->pathAliasRepository->pathHasMatchingAlias('/' . $root);
$this->storage[$root] = $exists; $this->storage[$root] = $exists;
$this->persist($root); $this->persist($root);
if ($exists) { if ($exists) {

View File

@ -13,6 +13,7 @@ use Drupal\link\LinkItemInterface;
use Drupal\node\NodeInterface; use Drupal\node\NodeInterface;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\field\Entity\FieldStorageConfig; use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests link field widgets and formatters. * Tests link field widgets and formatters.
@ -21,6 +22,8 @@ use Drupal\field\Entity\FieldStorageConfig;
*/ */
class LinkFieldTest extends BrowserTestBase { class LinkFieldTest extends BrowserTestBase {
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
* *
@ -100,7 +103,7 @@ class LinkFieldTest extends BrowserTestBase {
$this->assertRaw('placeholder="http://example.com"'); $this->assertRaw('placeholder="http://example.com"');
// Create a path alias. // Create a path alias.
\Drupal::service('path.alias_storage')->save('/admin', '/a/path/alias'); $this->createPathAlias('/admin', '/a/path/alias');
// Create a node to test the link widget. // Create a node to test the link widget.
$node = $this->drupalCreateNode(); $node = $this->drupalCreateNode();

View File

@ -5,14 +5,18 @@ namespace Drupal\Tests\locale\Functional;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests you can configure a language for individual URL aliases. * Tests you can configure a language for individual URL aliases.
* *
* @group locale * @group locale
* @group path
*/ */
class LocalePathTest extends BrowserTestBase { class LocalePathTest extends BrowserTestBase {
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
* *
@ -96,44 +100,24 @@ class LocalePathTest extends BrowserTestBase {
$custom_path = $this->randomMachineName(8); $custom_path = $this->randomMachineName(8);
// Check priority of language for alias by source path. // Check priority of language for alias by source path.
$edit = [ $path_alias = $this->createPathAlias('/node/' . $node->id(), '/' . $custom_path, LanguageInterface::LANGCODE_NOT_SPECIFIED);
'path[0][value]' => '/node/' . $node->id(),
'alias[0][value]' => '/' . $custom_path,
'langcode[0][value]' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
$this->container->get('path.alias_storage')->save($edit['path[0][value]'], $edit['alias[0][value]'], $edit['langcode[0][value]']);
$lookup_path = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $node->id(), 'en'); $lookup_path = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $node->id(), 'en');
$this->assertEqual('/' . $english_path, $lookup_path, 'English language alias has priority.'); $this->assertEqual('/' . $english_path, $lookup_path, 'English language alias has priority.');
// Same check for language 'xx'. // Same check for language 'xx'.
$lookup_path = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $node->id(), $prefix); $lookup_path = $this->container->get('path.alias_manager')->getAliasByPath('/node/' . $node->id(), $prefix);
$this->assertEqual('/' . $custom_language_path, $lookup_path, 'Custom language alias has priority.'); $this->assertEqual('/' . $custom_language_path, $lookup_path, 'Custom language alias has priority.');
$path_alias = [ $path_alias->delete();
'path' => $edit['path[0][value]'],
'alias' => $edit['alias[0][value]'],
'langcode' => $edit['langcode[0][value]'],
];
$this->container->get('path.alias_storage')->delete($path_alias);
// Create language nodes to check priority of aliases. // Create language nodes to check priority of aliases.
$first_node = $this->drupalCreateNode(['type' => 'page', 'promote' => 1, 'langcode' => 'en']); $first_node = $this->drupalCreateNode(['type' => 'page', 'promote' => 1, 'langcode' => 'en']);
$second_node = $this->drupalCreateNode(['type' => 'page', 'promote' => 1, 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED]); $second_node = $this->drupalCreateNode(['type' => 'page', 'promote' => 1, 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED]);
// Assign a custom path alias to the first node with the English language. // Assign a custom path alias to the first node with the English language.
$edit = [ $this->createPathAlias('/node/' . $first_node->id(), '/' . $custom_path, $first_node->language()->getId());
'path[0][value]' => '/node/' . $first_node->id(),
'alias[0][value]' => '/' . $custom_path,
'langcode[0][value]' => $first_node->language()->getId(),
];
$this->container->get('path.alias_storage')->save($edit['path[0][value]'], $edit['alias[0][value]'], $edit['langcode[0][value]']);
// Assign a custom path alias to second node with // Assign a custom path alias to second node with
// LanguageInterface::LANGCODE_NOT_SPECIFIED. // LanguageInterface::LANGCODE_NOT_SPECIFIED.
$edit = [ $this->createPathAlias('/node/' . $second_node->id(), '/' . $custom_path, $second_node->language()->getId());
'path[0][value]' => '/node/' . $second_node->id(),
'alias[0][value]' => '/' . $custom_path,
'langcode[0][value]' => $second_node->language()->getId(),
];
$this->container->get('path.alias_storage')->save($edit['path[0][value]'], $edit['alias[0][value]'], $edit['langcode[0][value]']);
// Test that both node titles link to our path alias. // Test that both node titles link to our path alias.
$this->drupalGet('admin/content'); $this->drupalGet('admin/content');

View File

@ -3,18 +3,21 @@
namespace Drupal\Tests\menu_link_content\Kernel; namespace Drupal\Tests\menu_link_content\Kernel;
use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Menu\MenuTreeParameters; use Drupal\Core\Menu\MenuTreeParameters;
use Drupal\menu_link_content\Entity\MenuLinkContent; use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Ensures that the menu tree adapts to path alias changes. * Ensures that the menu tree adapts to path alias changes.
* *
* @group menu_link_content * @group menu_link_content
* @group path
*/ */
class PathAliasMenuLinkContentTest extends KernelTestBase { class PathAliasMenuLinkContentTest extends KernelTestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -52,11 +55,7 @@ class PathAliasMenuLinkContentTest extends KernelTestBase {
public function testPathAliasChange() { public function testPathAliasChange() {
\Drupal::service('router.builder')->rebuild(); \Drupal::service('router.builder')->rebuild();
/** @var \Drupal\Core\Path\AliasStorageInterface $path_alias_storage */ $path_alias = $this->createPathAlias('/test-page', '/my-blog');
$path_alias_storage = \Drupal::service('path.alias_storage');
$alias = $path_alias_storage->save('/test-page', '/my-blog');
$pid = $alias['pid'];
$menu_link_content = MenuLinkContent::create([ $menu_link_content = MenuLinkContent::create([
'title' => 'Menu title', 'title' => 'Menu title',
'link' => ['uri' => 'internal:/my-blog'], 'link' => ['uri' => 'internal:/my-blog'],
@ -68,13 +67,15 @@ class PathAliasMenuLinkContentTest extends KernelTestBase {
$this->assertEqual('test_page_test.test_page', $tree[$menu_link_content->getPluginId()]->link->getPluginDefinition()['route_name']); $this->assertEqual('test_page_test.test_page', $tree[$menu_link_content->getPluginId()]->link->getPluginDefinition()['route_name']);
// Saving an alias should clear the alias manager cache. // Saving an alias should clear the alias manager cache.
$path_alias_storage->save('/test-render-title', '/my-blog', LanguageInterface::LANGCODE_NOT_SPECIFIED, $pid); $path_alias->setPath('/test-render-title');
$path_alias->setAlias('/my-blog');
$path_alias->save();
$tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters());
$this->assertEqual('test_page_test.render_title', $tree[$menu_link_content->getPluginId()]->link->getPluginDefinition()['route_name']); $this->assertEqual('test_page_test.render_title', $tree[$menu_link_content->getPluginId()]->link->getPluginDefinition()['route_name']);
// Delete the alias. // Delete the alias.
$path_alias_storage->delete(['pid' => $pid]); $path_alias->delete();
$tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters()); $tree = \Drupal::menuTree()->load('tools', new MenuTreeParameters());
$this->assertTrue(isset($tree[$menu_link_content->getPluginId()])); $this->assertTrue(isset($tree[$menu_link_content->getPluginId()]));
$this->assertEqual('', $tree[$menu_link_content->getPluginId()]->link->getRouteName()); $this->assertEqual('', $tree[$menu_link_content->getPluginId()]->link->getRouteName());

View File

@ -4,7 +4,6 @@ namespace Drupal\path\Plugin\Field\FieldType;
use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResult;
use Drupal\Core\Field\FieldItemList; use Drupal\Core\Field\FieldItemList;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Session\AccountInterface; use Drupal\Core\Session\AccountInterface;
use Drupal\Core\TypedData\ComputedItemListTrait; use Drupal\Core\TypedData\ComputedItemListTrait;
@ -27,21 +26,15 @@ class PathFieldItemList extends FieldItemList {
$entity = $this->getEntity(); $entity = $this->getEntity();
if (!$entity->isNew()) { if (!$entity->isNew()) {
$conditions = [ /** @var \Drupal\Core\Path\AliasRepositoryInterface $path_alias_repository */
'source' => '/' . $entity->toUrl()->getInternalPath(), $path_alias_repository = \Drupal::service('path.alias_repository');
'langcode' => $this->getLangcode(),
];
$alias = \Drupal::service('path.alias_storage')->load($conditions);
if ($alias === FALSE) {
// Fall back to non-specific language.
if ($this->getLangcode() !== LanguageInterface::LANGCODE_NOT_SPECIFIED) {
$conditions['langcode'] = LanguageInterface::LANGCODE_NOT_SPECIFIED;
$alias = \Drupal::service('path.alias_storage')->load($conditions);
}
}
if ($alias) { if ($path_alias = $path_alias_repository->lookupBySystemPath('/' . $entity->toUrl()->getInternalPath(), $this->getLangcode())) {
$value = $alias; $value = [
'alias' => $path_alias['alias'],
'pid' => $path_alias['id'],
'langcode' => $path_alias['langcode'],
];
} }
} }
@ -64,11 +57,12 @@ class PathFieldItemList extends FieldItemList {
public function delete() { public function delete() {
// Delete all aliases associated with this entity in the current language. // Delete all aliases associated with this entity in the current language.
$entity = $this->getEntity(); $entity = $this->getEntity();
$conditions = [ $path_alias_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
'source' => '/' . $entity->toUrl()->getInternalPath(), $entities = $path_alias_storage->loadByProperties([
'path' => '/' . $entity->toUrl()->getInternalPath(),
'langcode' => $entity->language()->getId(), 'langcode' => $entity->language()->getId(),
]; ]);
\Drupal::service('path.alias_storage')->delete($conditions); $path_alias_storage->delete($entities);
} }
} }

View File

@ -87,15 +87,22 @@ class PathWidget extends WidgetBase {
if (!empty($alias)) { if (!empty($alias)) {
$form_state->setValueForElement($element['alias'], $alias); $form_state->setValueForElement($element['alias'], $alias);
// Validate that the submitted alias does not exist yet. /** @var \Drupal\Core\Path\PathAliasInterface $path_alias */
$is_exists = \Drupal::service('path.alias_storage')->aliasExists($alias, $element['langcode']['#value'], $element['source']['#value']); $path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([
if ($is_exists) { 'path' => $element['source']['#value'],
$form_state->setError($element['alias'], t('The alias is already in use.')); 'alias' => $alias,
} 'langcode' => $element['langcode']['#value'],
} ]);
$violations = $path_alias->validate();
if ($alias && $alias[0] !== '/') { foreach ($violations as $violation) {
$form_state->setError($element['alias'], t('The alias needs to start with a slash.')); // Newly created entities do not have a system path yet, so we need to
// disregard some violations.
if (!$path_alias->getPath() && $violation->getPropertyPath() === 'path') {
continue;
}
$form_state->setError($element['alias'], $violation->getMessage());
}
} }
} }

View File

@ -14,7 +14,7 @@ abstract class UrlAliasBase extends DrupalSqlBase {
*/ */
public function query() { public function query() {
// The order of the migration is significant since // The order of the migration is significant since
// \Drupal\Core\Path\AliasStorage::lookupPathAlias() orders by pid before // \Drupal\Core\Path\AliasRepository::lookupPathAlias() orders by pid before
// returning a result. Postgres does not automatically order by primary key // returning a result. Postgres does not automatically order by primary key
// therefore we need to add a specific order by. // therefore we need to add a specific order by.
return $this->select('url_alias', 'ua')->fields('ua')->orderBy('pid'); return $this->select('url_alias', 'ua')->fields('ua')->orderBy('pid');

View File

@ -283,7 +283,7 @@ class PathAliasTest extends PathTestBase {
$this->drupalPostForm('node/' . $node2->id() . '/edit', $edit, t('Save')); $this->drupalPostForm('node/' . $node2->id() . '/edit', $edit, t('Save'));
// Confirm that the alias didn't make a duplicate. // Confirm that the alias didn't make a duplicate.
$this->assertText(t('The alias is already in use.'), 'Attempt to moved alias was rejected.'); $this->assertSession()->pageTextContains("The alias {$edit['path[0][alias]']} is already in use in this language.");
// Delete alias. // Delete alias.
$this->drupalPostForm('node/' . $node1->id() . '/edit', ['path[0][alias]' => ''], t('Save')); $this->drupalPostForm('node/' . $node1->id() . '/edit', ['path[0][alias]' => ''], t('Save'));
@ -326,7 +326,7 @@ class PathAliasTest extends PathTestBase {
// Delete the node and check that the path alias is also deleted. // Delete the node and check that the path alias is also deleted.
$node5->delete(); $node5->delete();
$path_alias = \Drupal::service('path.alias_storage')->lookupPathAlias('/node/' . $node5->id(), $node5->language()->getId()); $path_alias = \Drupal::service('path.alias_repository')->lookUpBySystemPath('/node/' . $node5->id(), $node5->language()->getId());
$this->assertFalse($path_alias, 'Alias was successfully deleted when the referenced node was deleted.'); $this->assertFalse($path_alias, 'Alias was successfully deleted when the referenced node was deleted.');
// Create sixth test node. // Create sixth test node.
@ -388,7 +388,7 @@ class PathAliasTest extends PathTestBase {
// Now create another node and try to set the same alias. // Now create another node and try to set the same alias.
$node_two = $this->drupalCreateNode(); $node_two = $this->drupalCreateNode();
$this->drupalPostForm('node/' . $node_two->id() . '/edit', $edit, t('Save')); $this->drupalPostForm('node/' . $node_two->id() . '/edit', $edit, t('Save'));
$this->assertText(t('The alias is already in use.')); $this->assertSession()->pageTextContains("The alias {$edit['path[0][alias]']} is already in use in this language.");
$this->assertFieldByXPath("//input[@name='path[0][alias]' and contains(@class, 'error')]", $edit['path[0][alias]'], 'Textfield exists and has the error class.'); $this->assertFieldByXPath("//input[@name='path[0][alias]' and contains(@class, 'error')]", $edit['path[0][alias]'], 'Textfield exists and has the error class.');
// Behavior here differs with the inline_form_errors module enabled. // Behavior here differs with the inline_form_errors module enabled.
@ -399,7 +399,7 @@ class PathAliasTest extends PathTestBase {
// Attempt to edit the second node again, as before. // Attempt to edit the second node again, as before.
$this->drupalPostForm('node/' . $node_two->id() . '/edit', $edit, t('Preview')); $this->drupalPostForm('node/' . $node_two->id() . '/edit', $edit, t('Preview'));
// This error should still be present next to the field. // This error should still be present next to the field.
$this->assertSession()->pageTextContains(t('The alias is already in use.'), 'Field error found with expected text.'); $this->assertSession()->pageTextContains("The alias {$edit['path[0][alias]']} is already in use in this language.");
// The validation error set for the page should include this text. // The validation error set for the page should include this text.
$this->assertSession()->pageTextContains(t('1 error has been found: URL alias'), 'Form error found with expected text.'); $this->assertSession()->pageTextContains(t('1 error has been found: URL alias'), 'Form error found with expected text.');
// The text 'URL alias' should be a link. // The text 'URL alias' should be a link.

View File

@ -184,11 +184,11 @@ class PathLanguageTest extends PathTestBase {
// Confirm that the alias is removed if the translation is deleted. // Confirm that the alias is removed if the translation is deleted.
$english_node->removeTranslation('fr'); $english_node->removeTranslation('fr');
$english_node->save(); $english_node->save();
$this->assertFalse($this->container->get('path.alias_storage')->aliasExists('/' . $french_alias, 'fr'), 'Alias for French translation is removed when translation is deleted.'); $this->assertPathAliasNotExists('/' . $french_alias, 'fr', NULL, 'Alias for French translation is removed when translation is deleted.');
// Check that the English alias still works. // Check that the English alias still works.
$this->drupalGet($english_alias); $this->drupalGet($english_alias);
$this->assertTrue($this->container->get('path.alias_storage')->aliasExists('/' . $english_alias, 'en'), 'English alias is not deleted when French translation is removed.'); $this->assertPathAliasExists('/' . $english_alias, 'en', NULL, 'English alias is not deleted when French translation is removed.');
$this->assertText($english_node->body->value, 'English alias still works'); $this->assertText($english_node->body->value, 'English alias still works');
} }

View File

@ -3,12 +3,15 @@
namespace Drupal\Tests\path\Functional; namespace Drupal\Tests\path\Functional;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Provides a base class for testing the Path module. * Provides a base class for testing the Path module.
*/ */
abstract class PathTestBase extends BrowserTestBase { abstract class PathTestBase extends BrowserTestBase {
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
* *

View File

@ -2,9 +2,11 @@
namespace Drupal\Tests\path\Kernel\Migrate\d6; namespace Drupal\Tests\path\Kernel\Migrate\d6;
use Drupal\Core\Path\PathAliasInterface;
use Drupal\migrate\Plugin\MigrateIdMapInterface; use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase; use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* URL alias migration. * URL alias migration.
@ -13,6 +15,8 @@ use Drupal\Tests\migrate_drupal\Kernel\d6\MigrateDrupal6TestBase;
*/ */
class MigrateUrlAliasTest extends MigrateDrupal6TestBase { class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -47,20 +51,20 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
} }
/** /**
* Assert a path. * Asserts that a path alias matches a set of conditions.
* *
* @param string $pid * @param int $pid
* The path id. * The path alias ID.
* @param array $conditions * @param array $conditions
* The path conditions. * The path conditions.
* @param array $path * @param \Drupal\Core\Path\PathAliasInterface $path_alias
* The path. * The path alias.
*/ */
private function assertPath($pid, $conditions, $path) { private function assertPath($pid, $conditions, PathAliasInterface $path_alias) {
$this->assertTrue($path, "Path alias for " . $conditions['source'] . " successfully loaded."); $this->assertSame($pid, (int) $path_alias->id());
$this->assertIdentical($conditions['alias'], $path['alias']); $this->assertSame($conditions['alias'], $path_alias->getAlias());
$this->assertIdentical($conditions['langcode'], $path['langcode']); $this->assertSame($conditions['langcode'], $path_alias->get('langcode')->value);
$this->assertIdentical($conditions['source'], $path['source']); $this->assertSame($conditions['path'], $path_alias->getPath());
} }
/** /**
@ -70,21 +74,21 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
$id_map = $this->getMigration('d6_url_alias')->getIdMap(); $id_map = $this->getMigration('d6_url_alias')->getIdMap();
// Test that the field exists. // Test that the field exists.
$conditions = [ $conditions = [
'source' => '/node/1', 'path' => '/node/1',
'alias' => '/alias-one', 'alias' => '/alias-one',
'langcode' => 'af', 'langcode' => 'af',
]; ];
$path = \Drupal::service('path.alias_storage')->load($conditions); $path_alias = $this->loadPathAliasByConditions($conditions);
$this->assertPath('1', $conditions, $path); $this->assertPath(1, $conditions, $path_alias);
$this->assertIdentical($id_map->lookupDestinationIds([$path['pid']]), [['1']], "Test IdMap"); $this->assertSame([['1']], $id_map->lookupDestinationIds([$path_alias->id()]), "Test IdMap");
$conditions = [ $conditions = [
'source' => '/node/2', 'path' => '/node/2',
'alias' => '/alias-two', 'alias' => '/alias-two',
'langcode' => 'en', 'langcode' => 'en',
]; ];
$path = \Drupal::service('path.alias_storage')->load($conditions); $path_alias = $this->loadPathAliasByConditions($conditions);
$this->assertPath('2', $conditions, $path); $this->assertPath(2, $conditions, $path_alias);
// Test that we can re-import using the UrlAlias destination. // Test that we can re-import using the UrlAlias destination.
Database::getConnection('default', 'migrate') Database::getConnection('default', 'migrate')
@ -100,54 +104,53 @@ class MigrateUrlAliasTest extends MigrateDrupal6TestBase {
$migration = $this->getMigration('d6_url_alias'); $migration = $this->getMigration('d6_url_alias');
$this->executeMigration($migration); $this->executeMigration($migration);
$path = \Drupal::service('path.alias_storage')->load(['pid' => $path['pid']]); $path_alias = $this->loadPathAliasByConditions(['id' => $path_alias->id()]);
$conditions['alias'] = '/new-url-alias'; $conditions['alias'] = '/new-url-alias';
$this->assertPath('2', $conditions, $path); $this->assertPath(2, $conditions, $path_alias);
$conditions = [ $conditions = [
'source' => '/node/3', 'path' => '/node/3',
'alias' => '/alias-three', 'alias' => '/alias-three',
'langcode' => 'und', 'langcode' => 'und',
]; ];
$path = \Drupal::service('path.alias_storage')->load($conditions); $path_alias = $this->loadPathAliasByConditions($conditions);
$this->assertPath('3', $conditions, $path); $this->assertPath(3, $conditions, $path_alias);
$path = \Drupal::service('path.alias_storage')->load(['alias' => '/source-noslash']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/source-noslash']);
$conditions = [ $conditions = [
'source' => '/admin', 'path' => '/admin',
'alias' => '/source-noslash', 'alias' => '/source-noslash',
'langcode' => 'und', 'langcode' => 'und',
]; ];
$this->assertPath('2', $conditions, $path); $this->assertPath(8, $conditions, $path_alias);
} }
/** /**
* Test the URL alias migration with translated nodes. * Test the URL alias migration with translated nodes.
*/ */
public function testUrlAliasWithTranslatedNodes() { public function testUrlAliasWithTranslatedNodes() {
$alias_storage = $this->container->get('path.alias_storage');
// Alias for the 'The Real McCoy' node in English. // Alias for the 'The Real McCoy' node in English.
$path = $alias_storage->load(['alias' => '/the-real-mccoy']);
$this->assertSame('/node/10', $path['source']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/the-real-mccoy']);
$this->assertSame('en', $path['langcode']); $this->assertSame('/node/10', $path_alias->getPath());
$this->assertSame('en', $path_alias->get('langcode')->value);
// Alias for the 'The Real McCoy' French translation, // Alias for the 'The Real McCoy' French translation,
// which should now point to node/10 instead of node/11. // which should now point to node/10 instead of node/11.
$path = $alias_storage->load(['alias' => '/le-vrai-mccoy']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/le-vrai-mccoy']);
$this->assertSame('/node/10', $path['source']); $this->assertSame('/node/10', $path_alias->getPath());
$this->assertSame('fr', $path['langcode']); $this->assertSame('fr', $path_alias->get('langcode')->value);
// Alias for the 'Abantu zulu' node in Zulu. // Alias for the 'Abantu zulu' node in Zulu.
$path = $alias_storage->load(['alias' => '/abantu-zulu']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/abantu-zulu']);
$this->assertSame('/node/12', $path['source']); $this->assertSame('/node/12', $path_alias->getPath());
$this->assertSame('zu', $path['langcode']); $this->assertSame('zu', $path_alias->get('langcode')->value);
// Alias for the 'Abantu zulu' English translation, // Alias for the 'Abantu zulu' English translation,
// which should now point to node/12 instead of node/13. // which should now point to node/12 instead of node/13.
$path = $alias_storage->load(['alias' => '/the-zulu-people']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/the-zulu-people']);
$this->assertSame('/node/12', $path['source']); $this->assertSame('/node/12', $path_alias->getPath());
$this->assertSame('en', $path['langcode']); $this->assertSame('en', $path_alias->get('langcode')->value);
} }
} }

View File

@ -32,29 +32,27 @@ class MigrateUrlAliasTest extends MigrateUrlAliasTestBase {
* Test the URL alias migration with translated nodes. * Test the URL alias migration with translated nodes.
*/ */
public function testUrlAliasWithTranslatedNodes() { public function testUrlAliasWithTranslatedNodes() {
$alias_storage = $this->container->get('path.alias_storage');
// Alias for the 'The thing about Deep Space 9' node in English. // Alias for the 'The thing about Deep Space 9' node in English.
$path = $alias_storage->load(['alias' => '/deep-space-9']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/deep-space-9']);
$this->assertSame('/node/2', $path['source']); $this->assertSame('/node/2', $path_alias->getPath());
$this->assertSame('en', $path['langcode']); $this->assertSame('en', $path_alias->get('langcode')->value);
// Alias for the 'The thing about Deep Space 9' Icelandic translation, // Alias for the 'The thing about Deep Space 9' Icelandic translation,
// which should now point to node/2 instead of node/3. // which should now point to node/2 instead of node/3.
$path = $alias_storage->load(['alias' => '/deep-space-9-is']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/deep-space-9-is']);
$this->assertSame('/node/2', $path['source']); $this->assertSame('/node/2', $path_alias->getPath());
$this->assertSame('is', $path['langcode']); $this->assertSame('is', $path_alias->get('langcode')->value);
// Alias for the 'The thing about Firefly' node in Icelandic. // Alias for the 'The thing about Firefly' node in Icelandic.
$path = $alias_storage->load(['alias' => '/firefly-is']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/firefly-is']);
$this->assertSame('/node/4', $path['source']); $this->assertSame('/node/4', $path_alias->getPath());
$this->assertSame('is', $path['langcode']); $this->assertSame('is', $path_alias->get('langcode')->value);
// Alias for the 'The thing about Firefly' English translation, // Alias for the 'The thing about Firefly' English translation,
// which should now point to node/4 instead of node/5. // which should now point to node/4 instead of node/5.
$path = $alias_storage->load(['alias' => '/firefly']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/firefly']);
$this->assertSame('/node/4', $path['source']); $this->assertSame('/node/4', $path_alias->getPath());
$this->assertSame('en', $path['langcode']); $this->assertSame('en', $path_alias->get('langcode')->value);
} }
} }

View File

@ -3,6 +3,7 @@
namespace Drupal\Tests\path\Kernel\Migrate\d7; namespace Drupal\Tests\path\Kernel\Migrate\d7;
use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase; use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests URL alias migration. * Tests URL alias migration.
@ -11,6 +12,8 @@ use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
*/ */
abstract class MigrateUrlAliasTestBase extends MigrateDrupal7TestBase { abstract class MigrateUrlAliasTestBase extends MigrateDrupal7TestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -45,21 +48,19 @@ abstract class MigrateUrlAliasTestBase extends MigrateDrupal7TestBase {
* Test the URL alias migration. * Test the URL alias migration.
*/ */
public function testUrlAlias() { public function testUrlAlias() {
$alias_storage = $this->container->get('path.alias_storage'); $path_alias = $this->loadPathAliasByConditions([
'path' => '/taxonomy/term/4',
$path = $alias_storage->load([
'source' => '/taxonomy/term/4',
'alias' => '/term33', 'alias' => '/term33',
'langcode' => 'und', 'langcode' => 'und',
]); ]);
$this->assertIdentical('/taxonomy/term/4', $path['source']); $this->assertIdentical('/taxonomy/term/4', $path_alias->getPath());
$this->assertIdentical('/term33', $path['alias']); $this->assertIdentical('/term33', $path_alias->getAlias());
$this->assertIdentical('und', $path['langcode']); $this->assertIdentical('und', $path_alias->language()->getId());
// Alias with no slash. // Alias with no slash.
$path = $alias_storage->load(['alias' => '/source-noslash']); $path_alias = $this->loadPathAliasByConditions(['alias' => '/source-noslash']);
$this->assertSame('/admin', $path['source']); $this->assertSame('/admin', $path_alias->getPath());
$this->assertSame('und', $path['langcode']); $this->assertSame('und', $path_alias->language()->getId());
} }
} }

View File

@ -44,9 +44,8 @@ class PathItemTest extends KernelTestBase {
* Test creating, loading, updating and deleting aliases through PathItem. * Test creating, loading, updating and deleting aliases through PathItem.
*/ */
public function testPathItem() { public function testPathItem() {
/** @var \Drupal\Core\Path\AliasRepositoryInterface $alias_repository */
/** @var \Drupal\Core\Path\AliasStorageInterface $alias_storage */ $alias_repository = \Drupal::service('path.alias_repository');
$alias_storage = \Drupal::service('path.alias_storage');
$node_storage = \Drupal::entityTypeManager()->getStorage('node'); $node_storage = \Drupal::entityTypeManager()->getStorage('node');
@ -62,8 +61,8 @@ class PathItemTest extends KernelTestBase {
$this->assertFalse($node->get('path')->isEmpty()); $this->assertFalse($node->get('path')->isEmpty());
$this->assertEquals('/foo', $node->get('path')->alias); $this->assertEquals('/foo', $node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foo', $stored_alias); $this->assertEquals('/foo', $stored_alias['alias']);
$node_storage->resetCache(); $node_storage->resetCache();
@ -97,10 +96,10 @@ class PathItemTest extends KernelTestBase {
$translation = $loaded_node->getTranslation('de'); $translation = $loaded_node->getTranslation('de');
$this->assertEquals('/furchtbar', $translation->path->alias); $this->assertEquals('/furchtbar', $translation->path->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foo', $stored_alias); $this->assertEquals('/foo', $stored_alias['alias']);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $translation->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $translation->language()->getId());
$this->assertEquals('/furchtbar', $stored_alias); $this->assertEquals('/furchtbar', $stored_alias['alias']);
$loaded_node->get('path')->alias = '/bar'; $loaded_node->get('path')->alias = '/bar';
$this->assertFalse($loaded_node->get('path')->isEmpty()); $this->assertFalse($loaded_node->get('path')->isEmpty());
@ -123,11 +122,11 @@ class PathItemTest extends KernelTestBase {
$this->assertFalse($loaded_node->get('path')->isEmpty()); $this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/bar', $loaded_node->get('path')->alias); $this->assertEquals('/bar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/bar', $stored_alias); $this->assertEquals('/bar', $stored_alias['alias']);
$old_alias = $alias_storage->lookupPathSource('/foo', $node->language()->getId()); $old_alias = $alias_repository->lookupByAlias('/foo', $node->language()->getId());
$this->assertFalse($old_alias); $this->assertNull($old_alias);
// Reload the node to make sure that it is possible to set a value // Reload the node to make sure that it is possible to set a value
// immediately after loading. // immediately after loading.
@ -140,19 +139,19 @@ class PathItemTest extends KernelTestBase {
$loaded_node = $node_storage->load($node->id()); $loaded_node = $node_storage->load($node->id());
$this->assertFalse($loaded_node->get('path')->isEmpty()); $this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foobar', $loaded_node->get('path')->alias); $this->assertEquals('/foobar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foobar', $stored_alias); $this->assertEquals('/foobar', $stored_alias['alias']);
$old_alias = $alias_storage->lookupPathSource('/bar', $node->language()->getId()); $old_alias = $alias_repository->lookupByAlias('/bar', $node->language()->getId());
$this->assertFalse($old_alias); $this->assertNull($old_alias);
$loaded_node->get('path')->alias = ''; $loaded_node->get('path')->alias = '';
$this->assertEquals('', $loaded_node->get('path')->alias); $this->assertEquals('', $loaded_node->get('path')->alias);
$loaded_node->save(); $loaded_node->save();
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertFalse($stored_alias); $this->assertNull($stored_alias);
// Check that reading, updating and reading the computed alias again in the // Check that reading, updating and reading the computed alias again in the
// same request works without clearing any caches in between. // same request works without clearing any caches in between.
@ -162,16 +161,16 @@ class PathItemTest extends KernelTestBase {
$this->assertFalse($loaded_node->get('path')->isEmpty()); $this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foo', $loaded_node->get('path')->alias); $this->assertEquals('/foo', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foo', $stored_alias); $this->assertEquals('/foo', $stored_alias['alias']);
$loaded_node->get('path')->alias = '/foobar'; $loaded_node->get('path')->alias = '/foobar';
$loaded_node->save(); $loaded_node->save();
$this->assertFalse($loaded_node->get('path')->isEmpty()); $this->assertFalse($loaded_node->get('path')->isEmpty());
$this->assertEquals('/foobar', $loaded_node->get('path')->alias); $this->assertEquals('/foobar', $loaded_node->get('path')->alias);
$stored_alias = $alias_storage->lookupPathAlias('/' . $node->toUrl()->getInternalPath(), $node->language()->getId()); $stored_alias = $alias_repository->lookupBySystemPath('/' . $node->toUrl()->getInternalPath(), $node->language()->getId());
$this->assertEquals('/foobar', $stored_alias); $this->assertEquals('/foobar', $stored_alias['alias']);
// Check that \Drupal\Core\Field\FieldItemList::equals() for the path field // Check that \Drupal\Core\Field\FieldItemList::equals() for the path field
// type. // type.

View File

@ -8,6 +8,7 @@ use Drupal\Core\Url;
use Drupal\shortcut\Entity\Shortcut; use Drupal\shortcut\Entity\Shortcut;
use Drupal\shortcut\Entity\ShortcutSet; use Drupal\shortcut\Entity\ShortcutSet;
use Drupal\Tests\block\Functional\AssertBlockAppearsTrait; use Drupal\Tests\block\Functional\AssertBlockAppearsTrait;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
use Drupal\views\Entity\View; use Drupal\views\Entity\View;
/** /**
@ -18,6 +19,7 @@ use Drupal\views\Entity\View;
class ShortcutLinksTest extends ShortcutTestBase { class ShortcutLinksTest extends ShortcutTestBase {
use AssertBlockAppearsTrait; use AssertBlockAppearsTrait;
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
@ -42,11 +44,7 @@ class ShortcutLinksTest extends ShortcutTestBase {
$set = $this->set; $set = $this->set;
// Create an alias for the node so we can test aliases. // Create an alias for the node so we can test aliases.
$path = [ $path_alias = $this->createPathAlias('/node/' . $this->node->id(), '/' . $this->randomMachineName(8));
'source' => '/node/' . $this->node->id(),
'alias' => '/' . $this->randomMachineName(8),
];
$this->container->get('path.alias_storage')->save($path['source'], $path['alias']);
// Create some paths to test. // Create some paths to test.
$test_cases = [ $test_cases = [
@ -54,7 +52,7 @@ class ShortcutLinksTest extends ShortcutTestBase {
'/admin', '/admin',
'/admin/config/system/site-information', '/admin/config/system/site-information',
'/node/' . $this->node->id() . '/edit', '/node/' . $this->node->id() . '/edit',
$path['alias'], $path_alias->getAlias(),
'/router_test/test2', '/router_test/test2',
'/router_test/test3/value', '/router_test/test3/value',
]; ];

View File

@ -7,14 +7,17 @@ use Drupal\Core\Database\Database;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\taxonomy\Entity\Term; use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests altering the inbound path and the outbound path. * Tests altering the inbound path and the outbound path.
* *
* @group Path * @group path
*/ */
class UrlAlterFunctionalTest extends BrowserTestBase { class UrlAlterFunctionalTest extends BrowserTestBase {
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
* *
@ -43,8 +46,7 @@ class UrlAlterFunctionalTest extends BrowserTestBase {
$this->assertUrlOutboundAlter("/user/$uid", "/user/$name"); $this->assertUrlOutboundAlter("/user/$uid", "/user/$name");
// Test that a path always uses its alias. // Test that a path always uses its alias.
$path = ['source' => "/user/$uid/test1", 'alias' => '/alias/test1']; $this->createPathAlias("/user/$uid/test1", '/alias/test1');
$this->container->get('path.alias_storage')->save($path['source'], $path['alias']);
$this->rebuildContainer(); $this->rebuildContainer();
$this->assertUrlInboundAlter('/alias/test1', "/user/$uid/test1"); $this->assertUrlInboundAlter('/alias/test1', "/user/$uid/test1");
$this->assertUrlOutboundAlter("/user/$uid/test1", '/alias/test1'); $this->assertUrlOutboundAlter("/user/$uid/test1", '/alias/test1');

View File

@ -2,13 +2,15 @@
namespace Drupal\Tests\system\Kernel; namespace Drupal\Tests\system\Kernel;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Path\AliasManagerInterface; use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Path\Entity\PathAlias;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Prophecy\Argument; use Prophecy\Argument;
/** /**
* @group Drupal * @coversDefaultClass \Drupal\Core\Path\Entity\PathAlias
*
* @group path
*/ */
class PathHooksTest extends KernelTestBase { class PathHooksTest extends KernelTestBase {
@ -27,38 +29,43 @@ class PathHooksTest extends KernelTestBase {
} }
/** /**
* Test system_path_alias_*() correctly clears caches. * Tests that the PathAlias entity clears caches correctly.
*
* @covers ::postSave
* @covers ::postDelete
*/ */
public function testPathHooks() { public function testPathHooks() {
$source = '/' . $this->randomMachineName(); $path_alias = PathAlias::create([
$alias = '/' . $this->randomMachineName(); 'path' => '/' . $this->randomMachineName(),
'alias' => '/' . $this->randomMachineName(),
]);
// Check system_path_alias_insert(); // Check \Drupal\Core\Path\Entity\PathAlias::postSave() for new path alias
// entities.
$alias_manager = $this->prophesize(AliasManagerInterface::class); $alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1); $alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($source)->shouldBeCalledTimes(1); $alias_manager->cacheClear($path_alias->getPath())->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal()); \Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal());
$alias_storage = \Drupal::service('path.alias_storage'); $path_alias->save();
$alias_storage->save($source, $alias);
$new_source = '/' . $this->randomMachineName(); $new_source = '/' . $this->randomMachineName();
$path = $alias_storage->load(['source' => $source]);
// Check system_path_alias_update(); // Check \Drupal\Core\Path\Entity\PathAlias::postSave() for existing path
// alias entities.
$alias_manager = $this->prophesize(AliasManagerInterface::class); $alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(2); $alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(2);
$alias_manager->cacheClear($source)->shouldBeCalledTimes(1); $alias_manager->cacheClear($path_alias->getPath())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1); $alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal()); \Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal());
$alias_storage->save($new_source, $alias, LanguageInterface::LANGCODE_NOT_SPECIFIED, $path['pid']); $path_alias->setPath($new_source);
$path_alias->save();
// Check system_path_alias_delete(); // Check \Drupal\Core\Path\Entity\PathAlias::postDelete().
$alias_manager = $this->prophesize(AliasManagerInterface::class); $alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1); $alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1); $alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal()); \Drupal::getContainer()->set('path.alias_manager', $alias_manager->reveal());
$alias_storage->delete(['pid' => $path['pid']]); $path_alias->delete();
} }
} }

View File

@ -2,15 +2,12 @@
namespace Drupal\workspaces; namespace Drupal\workspaces;
use Drupal\Core\Database\Connection; use Drupal\Core\Path\AliasRepository;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Path\AliasStorage as CoreAliasStorage;
/** /**
* Provides workspace-specific path alias lookup queries. * Provides workspace-specific path alias lookup queries.
*/ */
class AliasStorage extends CoreAliasStorage { class WorkspacesAliasRepository extends AliasRepository {
/** /**
* The workspace manager. * The workspace manager.
@ -20,20 +17,16 @@ class AliasStorage extends CoreAliasStorage {
protected $workspaceManager; protected $workspaceManager;
/** /**
* AliasStorage constructor. * Sets the workspace manager.
* *
* @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.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
* The workspace manager service. * The workspace manager service.
*
* @return $this
*/ */
public function __construct(Connection $connection, ModuleHandlerInterface $module_handler, EntityTypeManagerInterface $entity_type_manager, WorkspaceManagerInterface $workspace_manager) { public function setWorkspacesManager(WorkspaceManagerInterface $workspace_manager) {
parent::__construct($connection, $module_handler, $entity_type_manager);
$this->workspaceManager = $workspace_manager; $this->workspaceManager = $workspace_manager;
return $this;
} }
/** /**

View File

@ -20,10 +20,10 @@ class WorkspacesServiceProvider extends ServiceProviderBase {
$renderer_config['required_cache_contexts'][] = 'workspace'; $renderer_config['required_cache_contexts'][] = 'workspace';
$container->setParameter('renderer.config', $renderer_config); $container->setParameter('renderer.config', $renderer_config);
// Replace the class of the 'path.alias_storage' service. // Replace the class of the 'path.alias_repository' service.
$container->getDefinition('path.alias_storage') $container->getDefinition('path.alias_repository')
->setClass(AliasStorage::class) ->setClass(WorkspacesAliasRepository::class)
->addArgument(new Reference('workspaces.manager')); ->addMethodCall('setWorkspacesManager', [new Reference('workspaces.manager')]);
} }
} }

View File

@ -36,7 +36,7 @@ class DistributionProfileTest extends InstallerTestBase {
$path = $this->siteDirectory . '/profiles/mydistro'; $path = $this->siteDirectory . '/profiles/mydistro';
mkdir($path, 0777, TRUE); mkdir($path, 0777, TRUE);
file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info)); file_put_contents("$path/mydistro.info.yml", Yaml::encode($this->info));
file_put_contents("$path/mydistro.install", "<?php function mydistro_install() {\Drupal::service('path.alias_storage')->save('/user/1', '/myrootuser');}"); file_put_contents("$path/mydistro.install", "<?php function mydistro_install() {\Drupal::entityTypeManager()->getStorage('path_alias')->create(['path' => '/user/1', 'alias' => '/myrootuser'])->save();}");
} }
/** /**

View File

@ -4,14 +4,18 @@ namespace Drupal\FunctionalTests\Routing;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests url generation and routing for route paths with encoded characters. * Tests url generation and routing for route paths with encoded characters.
* *
* @group path
* @group routing * @group routing
*/ */
class PathEncodedTest extends BrowserTestBase { class PathEncodedTest extends BrowserTestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -35,12 +39,10 @@ class PathEncodedTest extends BrowserTestBase {
'path_encoded_test.atsign' => '/bloggy/@Dries', 'path_encoded_test.atsign' => '/bloggy/@Dries',
'path_encoded_test.parens' => '/cat(box)', 'path_encoded_test.parens' => '/cat(box)',
]; ];
/** @var \Drupal\Core\Path\AliasStorageInterface $alias_storage */
$alias_storage = $this->container->get('path.alias_storage');
$aliases = []; $aliases = [];
foreach ($route_paths as $route_name => $path) { foreach ($route_paths as $route_name => $path) {
$aliases[$route_name] = $this->randomMachineName(); $aliases[$route_name] = $this->randomMachineName();
$alias_storage->save($path, '/' . $aliases[$route_name]); $this->createPathAlias($path, '/' . $aliases[$route_name]);
} }
foreach ($route_paths as $route_name => $path) { foreach ($route_paths as $route_name => $path) {
// The alias may be only a suffix of the generated path when the test is // The alias may be only a suffix of the generated path when the test is

View File

@ -5,6 +5,7 @@ namespace Drupal\FunctionalTests\Routing;
use Drupal\language\Entity\ConfigurableLanguage; use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\BrowserTestBase; use Drupal\Tests\BrowserTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests the route cache when the language is not in the path. * Tests the route cache when the language is not in the path.
@ -13,6 +14,8 @@ use Drupal\Tests\BrowserTestBase;
*/ */
class RouteCachingNonPathLanguageNegotiationTest extends BrowserTestBase { class RouteCachingNonPathLanguageNegotiationTest extends BrowserTestBase {
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
* *
@ -71,7 +74,7 @@ class RouteCachingNonPathLanguageNegotiationTest extends BrowserTestBase {
// on the french page exist in english, no matter which language is // on the french page exist in english, no matter which language is
// checked first. Create the alias after visiting frontpage to make sure // checked first. Create the alias after visiting frontpage to make sure
// there is no existing cache entry for this that affects the tests. // there is no existing cache entry for this that affects the tests.
\Drupal::service('path.alias_storage')->save('/user/' . $this->adminUser->id(), '/user-page', 'en'); $this->createPathAlias('/user/' . $this->adminUser->id(), '/user-page', 'en');
$this->clickLink('French'); $this->clickLink('French');
$this->drupalGet('user-page'); $this->drupalGet('user-page');

View File

@ -8,6 +8,7 @@ use Drupal\Core\Config\DatabaseStorage;
use Drupal\Core\Database\Database; use Drupal\Core\Database\Database;
use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
use Drupal\user\Entity\User; use Drupal\user\Entity\User;
use Symfony\Component\Console\Tester\CommandTester; use Symfony\Component\Console\Tester\CommandTester;
use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Reference;
@ -19,6 +20,8 @@ use Symfony\Component\DependencyInjection\Reference;
*/ */
class DbDumpTest extends KernelTestBase { class DbDumpTest extends KernelTestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -109,7 +112,7 @@ class DbDumpTest extends KernelTestBase {
$account->save(); $account->save();
// Create a path alias. // Create a path alias.
$this->container->get('path.alias_storage')->save('/user/' . $account->id(), '/user/example'); $this->createPathAlias('/user/' . $account->id(), '/user/example');
// Create a cache table (this will create 'cache_discovery'). // Create a cache table (this will create 'cache_discovery').
\Drupal::cache('discovery')->set('test', $this->data); \Drupal::cache('discovery')->set('test', $this->data);

View File

@ -1,83 +0,0 @@
<?php
namespace Drupal\KernelTests\Core\Path;
use Drupal\Core\Language\LanguageInterface;
use Drupal\KernelTests\KernelTestBase;
/**
* @coversDefaultClass \Drupal\Core\Path\AliasStorage
* @group path
*/
class AliasStorageTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* @var \Drupal\Core\Path\AliasStorage
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('path_alias');
$this->storage = $this->container->get('path.alias_storage');
}
/**
* @covers ::load
*/
public function testLoad() {
$this->storage->save('/test-source-Case', '/test-alias-Case');
$expected = [
'pid' => 1,
'alias' => '/test-alias-Case',
'source' => '/test-source-Case',
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
$this->assertEquals($expected, $this->storage->load(['alias' => '/test-alias-Case']));
$this->assertEquals($expected, $this->storage->load(['alias' => '/test-alias-case']));
$this->assertEquals($expected, $this->storage->load(['source' => '/test-source-Case']));
$this->assertEquals($expected, $this->storage->load(['source' => '/test-source-case']));
}
/**
* @covers ::lookupPathAlias
*/
public function testLookupPathAlias() {
$this->storage->save('/test-source-Case', '/test-alias');
$this->assertEquals('/test-alias', $this->storage->lookupPathAlias('/test-source-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->assertEquals('/test-alias', $this->storage->lookupPathAlias('/test-source-case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
/**
* @covers ::lookupPathSource
*/
public function testLookupPathSource() {
$this->storage->save('/test-source', '/test-alias-Case');
$this->assertEquals('/test-source', $this->storage->lookupPathSource('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->assertEquals('/test-source', $this->storage->lookupPathSource('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
/**
* @covers ::aliasExists
*/
public function testAliasExists() {
$this->storage->save('/test-source-Case', '/test-alias-Case');
$this->assertTrue($this->storage->aliasExists('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->assertTrue($this->storage->aliasExists('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
}

View File

@ -2,20 +2,24 @@
namespace Drupal\KernelTests\Core\Path; namespace Drupal\KernelTests\Core\Path;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Cache\MemoryCounterBackend; use Drupal\Core\Cache\MemoryCounterBackend;
use Drupal\Core\Database\Database; use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Path\AliasManager; use Drupal\Core\Path\AliasManager;
use Drupal\Core\Path\AliasWhitelist; use Drupal\Core\Path\AliasWhitelist;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/** /**
* Tests path alias CRUD and lookup functionality. * Tests path alias CRUD and lookup functionality.
* *
* @group Path * @coversDefaultClass \Drupal\Core\Path\AliasRepository
*
* @group path
*/ */
class AliasTest extends KernelTestBase { class AliasTest extends KernelTestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -29,166 +33,76 @@ class AliasTest extends KernelTestBase {
$this->installEntitySchema('path_alias'); $this->installEntitySchema('path_alias');
} }
public function testCRUD() { /**
// Prepare database table. * @covers ::lookupBySystemPath
$connection = Database::getConnection(); */
public function testLookupBySystemPath() {
$this->createPathAlias('/test-source-Case', '/test-alias');
// Create Path object. $path_alias_repository = $this->container->get('path.alias_repository');
$aliasStorage = $this->container->get('path.alias_storage'); $this->assertEquals('/test-alias', $path_alias_repository->lookupBySystemPath('/test-source-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['alias']);
$this->assertEquals('/test-alias', $path_alias_repository->lookupBySystemPath('/test-source-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['alias']);
$aliases = $this->sampleUrlAliases();
// Create a few aliases
foreach ($aliases as $idx => $alias) {
$aliasStorage->save($alias['source'], $alias['alias'], $alias['langcode']);
$result = $connection->query('SELECT * FROM {path_alias} WHERE path = :path AND alias= :alias AND langcode = :langcode', [':path' => $alias['source'], ':alias' => $alias['alias'], ':langcode' => $alias['langcode']]);
$rows = $result->fetchAll();
$this->assertEqual(count($rows), 1, new FormattableMarkup('Created an entry for %alias.', ['%alias' => $alias['alias']]));
// Cache the pid for further tests.
$aliases[$idx]['pid'] = $rows[0]->id;
}
// Load a few aliases
foreach ($aliases as $alias) {
$pid = $alias['pid'];
$loadedAlias = $aliasStorage->load(['pid' => $pid]);
$this->assertEqual($loadedAlias, $alias, new FormattableMarkup('Loaded the expected path with pid %pid.', ['%pid' => $pid]));
}
// Load alias by source path.
$loadedAlias = $aliasStorage->load(['source' => '/node/1']);
$this->assertEqual($loadedAlias['alias'], '/alias_for_node_1_und', 'The last created alias loaded by default.');
// Update a few aliases
foreach ($aliases as $alias) {
$fields = $aliasStorage->save($alias['source'], $alias['alias'] . '_updated', $alias['langcode'], $alias['pid']);
$this->assertEqual($alias['alias'], $fields['original']['alias']);
$result = $connection->query('SELECT id FROM {path_alias} WHERE path = :path AND alias= :alias AND langcode = :langcode', [':path' => $alias['source'], ':alias' => $alias['alias'] . '_updated', ':langcode' => $alias['langcode']]);
$pid = $result->fetchField();
$this->assertEqual($pid, $alias['pid'], new FormattableMarkup('Updated entry for pid %pid.', ['%pid' => $pid]));
}
// Delete a few aliases
foreach ($aliases as $alias) {
$pid = $alias['pid'];
$aliasStorage->delete(['pid' => $pid]);
$result = $connection->query('SELECT * FROM {path_alias} WHERE id = :id', [':id' => $pid]);
$rows = $result->fetchAll();
$this->assertEqual(count($rows), 0, new FormattableMarkup('Deleted entry with pid %pid.', ['%pid' => $pid]));
}
} }
/** /**
* Returns an array of URL aliases for testing. * @covers ::lookupByAlias
*
* @return array of URL alias definitions.
*/ */
protected function sampleUrlAliases() { public function testLookupByAlias() {
return [ $this->createPathAlias('/test-source', '/test-alias-Case');
[
'source' => '/node/1', $path_alias_repository = $this->container->get('path.alias_repository');
'alias' => '/alias_for_node_1_en', $this->assertEquals('/test-source', $path_alias_repository->lookupByAlias('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['path']);
'langcode' => 'en', $this->assertEquals('/test-source', $path_alias_repository->lookupByAlias('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['path']);
],
[
'source' => '/node/2',
'alias' => '/alias_for_node_2_en',
'langcode' => 'en',
],
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_fr',
'langcode' => 'fr',
],
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_und',
'langcode' => 'und',
],
];
} }
/**
* @covers \Drupal\Core\Path\AliasManager::getPathByAlias
* @covers \Drupal\Core\Path\AliasManager::getAliasByPath
*/
public function testLookupPath() { public function testLookupPath() {
// Create AliasManager and Path object. // Create AliasManager and Path object.
$aliasManager = $this->container->get('path.alias_manager'); $aliasManager = $this->container->get('path.alias_manager');
$aliasStorage = $this->container->get('path.alias_storage');
// Test the situation where the source is the same for multiple aliases. // Test the situation where the source is the same for multiple aliases.
// Start with a language-neutral alias, which we will override. // Start with a language-neutral alias, which we will override.
$path = [ $path_alias = $this->createPathAlias('/user/1', '/foo');
'source' => "/user/1", $this->assertEquals($path_alias->getAlias(), $aliasManager->getAliasByPath($path_alias->getPath()), 'Basic alias lookup works.');
'alias' => '/foo', $this->assertEquals($path_alias->getPath(), $aliasManager->getPathByAlias($path_alias->getAlias()), 'Basic source lookup works.');
];
$aliasStorage->save($path['source'], $path['alias']);
$this->assertEqual($aliasManager->getAliasByPath($path['source']), $path['alias'], 'Basic alias lookup works.');
$this->assertEqual($aliasManager->getPathByAlias($path['alias']), $path['source'], 'Basic source lookup works.');
// Create a language specific alias for the default language (English). // Create a language specific alias for the default language (English).
$path = [ $path_alias = $this->createPathAlias('/user/1', '/users/Dries', 'en');
'source' => "/user/1",
'alias' => "/users/Dries", $this->assertEquals($path_alias->getAlias(), $aliasManager->getAliasByPath($path_alias->getPath()), 'English alias overrides language-neutral alias.');
'langcode' => 'en', $this->assertEquals($path_alias->getPath(), $aliasManager->getPathByAlias($path_alias->getAlias()), 'English source overrides language-neutral source.');
];
$aliasStorage->save($path['source'], $path['alias'], $path['langcode']);
// Hook that clears cache is not executed with unit tests.
\Drupal::service('path.alias_manager')->cacheClear();
$this->assertEqual($aliasManager->getAliasByPath($path['source']), $path['alias'], 'English alias overrides language-neutral alias.');
$this->assertEqual($aliasManager->getPathByAlias($path['alias']), $path['source'], 'English source overrides language-neutral source.');
// Create a language-neutral alias for the same path, again. // Create a language-neutral alias for the same path, again.
$path = [ $path_alias = $this->createPathAlias('/user/1', '/bar');
'source' => "/user/1", $this->assertEquals("/users/Dries", $aliasManager->getAliasByPath($path_alias->getPath()), 'English alias still returned after entering a language-neutral alias.');
'alias' => '/bar',
];
$aliasStorage->save($path['source'], $path['alias']);
$this->assertEqual($aliasManager->getAliasByPath($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. // Create a language-specific (xx-lolspeak) alias for the same path.
$path = [ $path_alias = $this->createPathAlias('/user/1', '/LOL', 'xx-lolspeak');
'source' => "/user/1", $this->assertEquals("/users/Dries", $aliasManager->getAliasByPath($path_alias->getPath()), 'English alias still returned after entering a LOLspeak alias.');
'alias' => '/LOL',
'langcode' => 'xx-lolspeak',
];
$aliasStorage->save($path['source'], $path['alias'], $path['langcode']);
$this->assertEqual($aliasManager->getAliasByPath($path['source']), "/users/Dries", 'English alias still returned after entering a LOLspeak alias.');
// The LOLspeak alias should be returned if we really want LOLspeak. // The LOLspeak alias should be returned if we really want LOLspeak.
$this->assertEqual($aliasManager->getAliasByPath($path['source'], 'xx-lolspeak'), '/LOL', 'LOLspeak alias returned if we specify xx-lolspeak to the alias manager.'); $this->assertEquals('/LOL', $aliasManager->getAliasByPath($path_alias->getPath(), 'xx-lolspeak'), '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 // Create a new alias for this path in English, which should override the
// previous alias for "user/1". // previous alias for "user/1".
$path = [ $path_alias = $this->createPathAlias('/user/1', '/users/my-new-path', 'en');
'source' => "/user/1", $this->assertEquals($path_alias->getAlias(), $aliasManager->getAliasByPath($path_alias->getPath()), 'Recently created English alias returned.');
'alias' => '/users/my-new-path', $this->assertEquals($path_alias->getPath(), $aliasManager->getPathByAlias($path_alias->getAlias()), 'Recently created English source returned.');
'langcode' => 'en',
];
$aliasStorage->save($path['source'], $path['alias'], $path['langcode']);
// Hook that clears cache is not executed with unit tests.
$aliasManager->cacheClear();
$this->assertEqual($aliasManager->getAliasByPath($path['source']), $path['alias'], 'Recently created English alias returned.');
$this->assertEqual($aliasManager->getPathByAlias($path['alias']), $path['source'], 'Recently created English source returned.');
// Remove the English aliases, which should cause a fallback to the most // Remove the English aliases, which should cause a fallback to the most
// recently created language-neutral alias, 'bar'. // recently created language-neutral alias, 'bar'.
$aliasStorage->delete(['langcode' => 'en']); $path_alias_storage = $this->container->get('entity_type.manager')->getStorage('path_alias');
// Hook that clears cache is not executed with unit tests. $entities = $path_alias_storage->loadByProperties(['langcode' => 'en']);
$aliasManager->cacheClear(); $path_alias_storage->delete($entities);
$this->assertEqual($aliasManager->getAliasByPath($path['source']), '/bar', 'Path lookup falls back to recently created language-neutral alias.'); $this->assertEquals('/bar', $aliasManager->getAliasByPath($path_alias->getPath()), 'Path lookup falls back to recently created language-neutral alias.');
// Test the situation where the alias and language are the same, but // Test the situation where the alias and language are the same, but
// the source differs. The newer alias record should be returned. // the source differs. The newer alias record should be returned.
$aliasStorage->save('/user/2', '/bar'); $this->createPathAlias('/user/2', '/bar');
// Hook that clears cache is not executed with unit tests.
$aliasManager->cacheClear(); $aliasManager->cacheClear();
$this->assertEqual($aliasManager->getPathByAlias('/bar'), '/user/2', 'Newer alias record is returned when comparing two LanguageInterface::LANGCODE_NOT_SPECIFIED paths with the same alias.'); $this->assertEquals('/user/2', $aliasManager->getPathByAlias('/bar'), 'Newer alias record is returned when comparing two LanguageInterface::LANGCODE_NOT_SPECIFIED paths with the same alias.');
} }
/** /**
@ -198,9 +112,8 @@ class AliasTest extends KernelTestBase {
$memoryCounterBackend = new MemoryCounterBackend(); $memoryCounterBackend = new MemoryCounterBackend();
// Create AliasManager and Path object. // Create AliasManager and Path object.
$aliasStorage = $this->container->get('path.alias_storage'); $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository'));
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $aliasStorage); $aliasManager = new AliasManager($this->container->get('path.alias_repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend);
$aliasManager = new AliasManager($aliasStorage, $whitelist, $this->container->get('language_manager'), $memoryCounterBackend);
// No alias for user and admin yet, so should be NULL. // No alias for user and admin yet, so should be NULL.
$this->assertNull($whitelist->get('user')); $this->assertNull($whitelist->get('user'));
@ -211,21 +124,23 @@ class AliasTest extends KernelTestBase {
$this->assertNull($whitelist->get($this->randomMachineName())); $this->assertNull($whitelist->get($this->randomMachineName()));
// Add an alias for user/1, user should get whitelisted now. // Add an alias for user/1, user should get whitelisted now.
$aliasStorage->save('/user/1', '/' . $this->randomMachineName()); $this->createPathAlias('/user/1', '/' . $this->randomMachineName());
$aliasManager->cacheClear(); $aliasManager->cacheClear();
$this->assertTrue($whitelist->get('user')); $this->assertTrue($whitelist->get('user'));
$this->assertNull($whitelist->get('admin')); $this->assertNull($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName())); $this->assertNull($whitelist->get($this->randomMachineName()));
// Add an alias for admin, both should get whitelisted now. // Add an alias for admin, both should get whitelisted now.
$aliasStorage->save('/admin/something', '/' . $this->randomMachineName()); $this->createPathAlias('/admin/something', '/' . $this->randomMachineName());
$aliasManager->cacheClear(); $aliasManager->cacheClear();
$this->assertTrue($whitelist->get('user')); $this->assertTrue($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin')); $this->assertTrue($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName())); $this->assertNull($whitelist->get($this->randomMachineName()));
// Remove the user alias again, whitelist entry should be removed. // Remove the user alias again, whitelist entry should be removed.
$aliasStorage->delete(['source' => '/user/1']); $path_alias_storage = $this->container->get('entity_type.manager')->getStorage('path_alias');
$entities = $path_alias_storage->loadByProperties(['path' => '/user/1']);
$path_alias_storage->delete($entities);
$aliasManager->cacheClear(); $aliasManager->cacheClear();
$this->assertNull($whitelist->get('user')); $this->assertNull($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin')); $this->assertTrue($whitelist->get('admin'));
@ -238,7 +153,7 @@ class AliasTest extends KernelTestBase {
// Re-initialize the whitelist using the same cache backend, should load // Re-initialize the whitelist using the same cache backend, should load
// from cache. // from cache.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $aliasStorage); $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository'));
$this->assertNull($whitelist->get('user')); $this->assertNull($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin')); $this->assertTrue($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName())); $this->assertNull($whitelist->get($this->randomMachineName()));
@ -258,17 +173,15 @@ class AliasTest extends KernelTestBase {
$memoryCounterBackend = new MemoryCounterBackend(); $memoryCounterBackend = new MemoryCounterBackend();
// Create AliasManager and Path object. // Create AliasManager and Path object.
$aliasStorage = $this->container->get('path.alias_storage'); $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository'));
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $aliasStorage); $aliasManager = new AliasManager($this->container->get('path.alias_repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend);
$aliasManager = new AliasManager($aliasStorage, $whitelist, $this->container->get('language_manager'), $memoryCounterBackend);
// Whitelist cache should not exist at all yet. // Whitelist cache should not exist at all yet.
$this->assertFalse($memoryCounterBackend->get('path_alias_whitelist')); $this->assertFalse($memoryCounterBackend->get('path_alias_whitelist'));
// Add some aliases for both menu routes we have. // Add some aliases for both menu routes we have.
$aliasStorage->save('/admin/something', '/' . $this->randomMachineName()); $this->createPathAlias('/admin/something', '/' . $this->randomMachineName());
$aliasStorage->save('/user/something', '/' . $this->randomMachineName()); $this->createPathAlias('/user/something', '/' . $this->randomMachineName());
$aliasManager->cacheClear();
// Lookup admin path in whitelist. It will query the DB and figure out // Lookup admin path in whitelist. It will query the DB and figure out
// that it indeed has an alias, and add it to the internal whitelist and // that it indeed has an alias, and add it to the internal whitelist and
@ -288,7 +201,7 @@ class AliasTest extends KernelTestBase {
// Whitelist should load data from its cache, see that it hasn't done a // Whitelist should load data from its cache, see that it hasn't done a
// check for 'user' yet, perform the check, then mark the result to be // check for 'user' yet, perform the check, then mark the result to be
// persisted to cache. // persisted to cache.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $aliasStorage); $whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path.alias_repository'));
$this->assertTrue($whitelist->get('user')); $this->assertTrue($whitelist->get('user'));
// Delete the whitelist cache. This could happen from an outside process, // Delete the whitelist cache. This could happen from an outside process,

View File

@ -0,0 +1,238 @@
<?php
namespace Drupal\KernelTests\Core\Path;
use Drupal\Core\Language\LanguageInterface;
use Drupal\KernelTests\KernelTestBase;
/**
* @coversDefaultClass \Drupal\Core\Path\AliasStorage
* @group path
* @group legacy
*/
class LegacyAliasStorageTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system'];
/**
* @var \Drupal\Core\Path\AliasStorage
*/
protected $storage;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('path_alias');
$this->storage = $this->container->get('path.alias_storage');
}
/**
* @covers ::load
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testLoad() {
$this->storage->save('/test-source-Case', '/test-alias-Case');
$expected = [
'pid' => 1,
'alias' => '/test-alias-Case',
'source' => '/test-source-Case',
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
];
$this->assertEquals($expected, $this->storage->load(['alias' => '/test-alias-Case']));
$this->assertEquals($expected, $this->storage->load(['alias' => '/test-alias-case']));
$this->assertEquals($expected, $this->storage->load(['source' => '/test-source-Case']));
$this->assertEquals($expected, $this->storage->load(['source' => '/test-source-case']));
}
/**
* @covers ::load
* @covers ::save
* @covers ::delete
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testCRUD() {
$entity_storage = \Drupal::entityTypeManager()->getStorage('path_alias');
$aliases = $this->sampleUrlAliases();
// Create a few aliases
foreach ($aliases as $idx => $alias) {
$this->storage->save($alias['source'], $alias['alias'], $alias['langcode']);
$result = $entity_storage->getQuery()
->condition('path', $alias['source'])
->condition('alias', $alias['alias'])
->condition('langcode', $alias['langcode'])
->execute();
$this->assertCount(1, $result, "Created an entry for {$alias['alias']}.");
// Cache the pid for further tests.
$aliases[$idx]['pid'] = reset($result);
}
// Load a few aliases
foreach ($aliases as $alias) {
$pid = $alias['pid'];
$loadedAlias = $this->storage->load(['pid' => $pid]);
$this->assertEquals($alias, $loadedAlias, "Loaded the expected path with pid $pid.");
}
// Load alias by source path.
$loadedAlias = $this->storage->load(['source' => '/node/1']);
$this->assertEquals('/alias_for_node_1_und', $loadedAlias['alias'], 'The last created alias loaded by default.');
// Update a few aliases
foreach ($aliases as $alias) {
$fields = $this->storage->save($alias['source'], $alias['alias'] . '_updated', $alias['langcode'], $alias['pid']);
$this->assertEquals($alias['alias'], $fields['original']['alias']);
$result = $entity_storage->getQuery()
->condition('path', $alias['source'])
->condition('alias', $alias['alias'] . '_updated')
->condition('langcode', $alias['langcode'])
->execute();
$pid = reset($result);
$this->assertEquals($alias['pid'], $pid, "Updated entry for pid $pid.");
}
// Delete a few aliases
foreach ($aliases as $alias) {
$pid = $alias['pid'];
$this->storage->delete(['pid' => $pid]);
$result = $entity_storage->getQuery()->condition('id', $pid)->execute();
$this->assertCount(0, $result, "Deleted entry with pid $pid.");
}
}
/**
* Returns an array of URL aliases for testing.
*
* @return array of URL alias definitions.
*/
protected function sampleUrlAliases() {
return [
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_en',
'langcode' => 'en',
],
[
'source' => '/node/2',
'alias' => '/alias_for_node_2_en',
'langcode' => 'en',
],
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_fr',
'langcode' => 'fr',
],
[
'source' => '/node/1',
'alias' => '/alias_for_node_1_und',
'langcode' => 'und',
],
];
}
/**
* @covers ::preloadPathAlias
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testPreLoadPathAlias() {
$this->storage->save('/test-source-Case', '/test-alias');
$this->assertEquals(['/test-source-Case' => '/test-alias'], $this->storage->preloadPathAlias(['/test-source-Case'], LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
/**
* @covers ::lookupPathAlias
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testLookupPathAlias() {
$this->storage->save('/test-source-Case', '/test-alias');
$this->assertEquals('/test-alias', $this->storage->lookupPathAlias('/test-source-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->assertEquals('/test-alias', $this->storage->lookupPathAlias('/test-source-case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
/**
* @covers ::lookupPathSource
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testLookupPathSource() {
$this->storage->save('/test-source', '/test-alias-Case');
$this->assertEquals('/test-source', $this->storage->lookupPathSource('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->assertEquals('/test-source', $this->storage->lookupPathSource('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
/**
* @covers ::aliasExists
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testAliasExists() {
$this->storage->save('/test-source-Case', '/test-alias-Case');
$this->assertTrue($this->storage->aliasExists('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
$this->assertTrue($this->storage->aliasExists('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED));
}
/**
* @covers ::languageAliasExists
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testLanguageAliasExists() {
$this->assertFalse($this->storage->languageAliasExists());
$this->storage->save('/test-source-Case', '/test-alias-Case', 'en');
$this->assertTrue($this->storage->languageAliasExists());
}
/**
* @covers ::getAliasesForAdminListing
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testGetAliasesForAdminListing() {
$this->storage->save('/test-source-Case', '/test-alias-Case');
$this->storage->save('/another-test', '/another-test-alias');
$expected_alias_1 = new \stdClass();
$expected_alias_1->pid = '2';
$expected_alias_1->source = '/another-test';
$expected_alias_1->alias = '/another-test-alias';
$expected_alias_1->langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
$expected_alias_2 = new \stdClass();
$expected_alias_2->pid = '1';
$expected_alias_2->source = '/test-source-Case';
$expected_alias_2->alias = '/test-alias-Case';
$expected_alias_2->langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
$header = [['field' => 'alias', 'sort' => 'asc']];
$this->assertEquals([$expected_alias_1, $expected_alias_2], $this->storage->getAliasesForAdminListing($header));
}
/**
* @covers ::pathHasMatchingAlias
* @expectedDeprecation \Drupal\Core\Path\AliasStorage is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Use the "path.alias_repository" service instead, or the entity storage handler for the "path_alias" entity type for CRUD methods. See https://www.drupal.org/node/3013865.
*/
public function testPathHasMatchingAlias() {
$this->storage->save('/test-source-Case', '/test-alias-Case');
$this->assertTrue($this->storage->pathHasMatchingAlias('/test'));
$this->assertFalse($this->storage->pathHasMatchingAlias('/another'));
}
}

View File

@ -4,6 +4,7 @@ namespace Drupal\KernelTests\Core\Routing;
use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -14,6 +15,8 @@ use Symfony\Component\HttpFoundation\Response;
*/ */
class ContentNegotiationRoutingTest extends KernelTestBase { class ContentNegotiationRoutingTest extends KernelTestBase {
use PathAliasTestTrait;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@ -46,13 +49,11 @@ class ContentNegotiationRoutingTest extends KernelTestBase {
* Tests the content negotiation aspect of routing. * Tests the content negotiation aspect of routing.
*/ */
public function testContentRouting() { public function testContentRouting() {
/** @var \Drupal\Core\Path\AliasStorageInterface $path_alias_storage */
$path_alias_storage = $this->container->get('path.alias_storage');
// Alias with extension pointing to no extension/constant content-type. // Alias with extension pointing to no extension/constant content-type.
$path_alias_storage->save('/conneg/html', '/alias.html'); $this->createPathAlias('/conneg/html', '/alias.html');
// Alias with extension pointing to dynamic extension/linked content-type. // Alias with extension pointing to dynamic extension/linked content-type.
$path_alias_storage->save('/conneg/html?_format=json', '/alias.json'); $this->createPathAlias('/conneg/html?_format=json', '/alias.json');
$tests = [ $tests = [
// ['path', 'accept', 'content-type'], // ['path', 'accept', 'content-type'],

View File

@ -18,6 +18,7 @@ use Drupal\Core\State\State;
use Drupal\KernelTests\KernelTestBase; use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage; use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\Core\Routing\RoutingFixtures; use Drupal\Tests\Core\Routing\RoutingFixtures;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\ResourceNotFoundException;
@ -32,6 +33,8 @@ use Symfony\Component\Routing\RouteCollection;
*/ */
class RouteProviderTest extends KernelTestBase { class RouteProviderTest extends KernelTestBase {
use PathAliasTestTrait;
/** /**
* Modules to enable. * Modules to enable.
*/ */
@ -572,9 +575,7 @@ class RouteProviderTest extends KernelTestBase {
$this->assertEqual(2, count($cache->data['routes'])); $this->assertEqual(2, count($cache->data['routes']));
// A path with a path alias. // A path with a path alias.
/** @var \Drupal\Core\Path\AliasStorageInterface $path_storage */ $this->createPathAlias('/path/add/one', '/path/add-one');
$path_storage = \Drupal::service('path.alias_storage');
$path_storage->save('/path/add/one', '/path/add-one');
/** @var \Drupal\Core\Path\AliasManagerInterface $alias_manager */ /** @var \Drupal\Core\Path\AliasManagerInterface $alias_manager */
$alias_manager = \Drupal::service('path.alias_manager'); $alias_manager = \Drupal::service('path.alias_manager');
$alias_manager->cacheClear(); $alias_manager->cacheClear();

View File

@ -5,11 +5,12 @@ namespace Drupal\Tests\Core\Path;
use Drupal\Core\Language\Language; use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Path\AliasManager; use Drupal\Core\Path\AliasManager;
use Drupal\Core\Path\AliasRepositoryInterface;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
* @coversDefaultClass \Drupal\Core\Path\AliasManager * @coversDefaultClass \Drupal\Core\Path\AliasManager
* @group Path * @group path
*/ */
class AliasManagerTest extends UnitTestCase { class AliasManagerTest extends UnitTestCase {
@ -27,6 +28,13 @@ class AliasManagerTest extends UnitTestCase {
*/ */
protected $aliasStorage; protected $aliasStorage;
/**
* Alias repository.
*
* @var \Drupal\Core\Path\AliasRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $aliasRepository;
/** /**
* Alias whitelist. * Alias whitelist.
* *
@ -68,12 +76,12 @@ class AliasManagerTest extends UnitTestCase {
protected function setUp() { protected function setUp() {
parent::setUp(); parent::setUp();
$this->aliasStorage = $this->createMock('Drupal\Core\Path\AliasStorageInterface'); $this->aliasRepository = $this->createMock(AliasRepositoryInterface::class);
$this->aliasWhitelist = $this->createMock('Drupal\Core\Path\AliasWhitelistInterface'); $this->aliasWhitelist = $this->createMock('Drupal\Core\Path\AliasWhitelistInterface');
$this->languageManager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface'); $this->languageManager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
$this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface'); $this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface');
$this->aliasManager = new AliasManager($this->aliasStorage, $this->aliasWhitelist, $this->languageManager, $this->cache); $this->aliasManager = new AliasManager($this->aliasRepository, $this->aliasWhitelist, $this->languageManager, $this->cache);
} }
@ -92,8 +100,8 @@ class AliasManagerTest extends UnitTestCase {
->with(LanguageInterface::TYPE_URL) ->with(LanguageInterface::TYPE_URL)
->will($this->returnValue($language)); ->will($this->returnValue($language));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathSource') ->method('lookupByAlias')
->with($alias, $language->getId()) ->with($alias, $language->getId())
->will($this->returnValue(NULL)); ->will($this->returnValue(NULL));
@ -113,10 +121,10 @@ class AliasManagerTest extends UnitTestCase {
$language = $this->setUpCurrentLanguage(); $language = $this->setUpCurrentLanguage();
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathSource') ->method('lookupByAlias')
->with($alias, $language->getId()) ->with($alias, $language->getId())
->will($this->returnValue($path)); ->will($this->returnValue(['path' => $path]));
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias)); $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias));
// Call it twice to test the static cache. // Call it twice to test the static cache.
@ -135,10 +143,10 @@ class AliasManagerTest extends UnitTestCase {
$this->languageManager->expects($this->never()) $this->languageManager->expects($this->never())
->method('getCurrentLanguage'); ->method('getCurrentLanguage');
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathSource') ->method('lookupByAlias')
->with($alias, 'de') ->with($alias, 'de')
->will($this->returnValue($path)); ->will($this->returnValue(['path' => $path]));
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, 'de')); $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, 'de'));
// Call it twice to test the static cache. // Call it twice to test the static cache.
@ -164,8 +172,8 @@ class AliasManagerTest extends UnitTestCase {
// The whitelist returns FALSE for that path part, so the storage should // The whitelist returns FALSE for that path part, so the storage should
// never be called. // never be called.
$this->aliasStorage->expects($this->never()) $this->aliasRepository->expects($this->never())
->method('lookupPathAlias'); ->method('lookupBySystemPath');
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path)); $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
} }
@ -189,8 +197,8 @@ class AliasManagerTest extends UnitTestCase {
->with($path_part1) ->with($path_part1)
->will($this->returnValue(TRUE)); ->will($this->returnValue(TRUE));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathAlias') ->method('lookupBySystemPath')
->with($path, $language->getId()) ->with($path, $language->getId())
->will($this->returnValue(NULL)); ->will($this->returnValue(NULL));
@ -227,10 +235,10 @@ class AliasManagerTest extends UnitTestCase {
->with($path_part1) ->with($path_part1)
->will($this->returnValue(TRUE)); ->will($this->returnValue(TRUE));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathAlias') ->method('lookupBySystemPath')
->with($path, $language->getId()) ->with($path, $language->getId())
->will($this->returnValue($alias)); ->will($this->returnValue(['alias' => $alias]));
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path)); $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache. // Call it twice to test the static cache.
@ -272,14 +280,14 @@ class AliasManagerTest extends UnitTestCase {
->with($path_part1) ->with($path_part1)
->will($this->returnValue(TRUE)); ->will($this->returnValue(TRUE));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('preloadPathAlias') ->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId()) ->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$path => $alias])); ->will($this->returnValue([$path => $alias]));
// LookupPathAlias should not be called. // LookupPathAlias should not be called.
$this->aliasStorage->expects($this->never()) $this->aliasRepository->expects($this->never())
->method('lookupPathAlias'); ->method('lookupBySystemPath');
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path)); $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache. // Call it twice to test the static cache.
@ -322,12 +330,12 @@ class AliasManagerTest extends UnitTestCase {
// The requested language is different than the cached, so this will // The requested language is different than the cached, so this will
// need to load. // need to load.
$this->aliasStorage->expects($this->never()) $this->aliasRepository->expects($this->never())
->method('preloadPathAlias'); ->method('preloadPathAlias');
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathAlias') ->method('lookupBySystemPath')
->with($path, $language->getId()) ->with($path, $language->getId())
->will($this->returnValue($alias)); ->will($this->returnValue(['alias' => $alias]));
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path)); $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache. // Call it twice to test the static cache.
@ -369,14 +377,14 @@ class AliasManagerTest extends UnitTestCase {
->with($path_part1) ->with($path_part1)
->will($this->returnValue(TRUE)); ->will($this->returnValue(TRUE));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('preloadPathAlias') ->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId()) ->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$cached_path => $cached_alias])); ->will($this->returnValue([$cached_path => $cached_alias]));
// LookupPathAlias() should not be called. // LookupPathAlias() should not be called.
$this->aliasStorage->expects($this->never()) $this->aliasRepository->expects($this->never())
->method('lookupPathAlias'); ->method('lookupBySystemPath');
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path)); $this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache. // Call it twice to test the static cache.
@ -417,13 +425,13 @@ class AliasManagerTest extends UnitTestCase {
->with($path_part1) ->with($path_part1)
->will($this->returnValue(TRUE)); ->will($this->returnValue(TRUE));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('preloadPathAlias') ->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId()) ->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$cached_path => $cached_alias])); ->will($this->returnValue([$cached_path => $cached_alias]));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathAlias') ->method('lookupBySystemPath')
->with($path, $language->getId()) ->with($path, $language->getId())
->will($this->returnValue(NULL)); ->will($this->returnValue(NULL));
@ -445,10 +453,10 @@ class AliasManagerTest extends UnitTestCase {
$path = '/path'; $path = '/path';
$alias = '/alias'; $alias = '/alias';
$language = $this->setUpCurrentLanguage(); $language = $this->setUpCurrentLanguage();
$this->aliasStorage->expects($this->exactly(2)) $this->aliasRepository->expects($this->exactly(2))
->method('lookupPathAlias') ->method('lookupBySystemPath')
->with($path, $language->getId()) ->with($path, $language->getId())
->willReturn($alias); ->willReturn(['alias' => $alias]);
$this->aliasWhitelist->expects($this->any()) $this->aliasWhitelist->expects($this->any())
->method('get') ->method('get')
->willReturn(TRUE); ->willReturn(TRUE);
@ -457,9 +465,8 @@ class AliasManagerTest extends UnitTestCase {
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path, $language->getId())); $this->assertEquals($alias, $this->aliasManager->getAliasByPath($path, $language->getId()));
// Check that the cache is populated. // Check that the cache is populated.
$original_storage = clone $this->aliasStorage; $this->aliasRepository->expects($this->never())
$this->aliasStorage->expects($this->never()) ->method('lookupByAlias');
->method('lookupPathSource');
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, $language->getId())); $this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, $language->getId()));
// Clear specific source. // Clear specific source.
@ -506,15 +513,15 @@ class AliasManagerTest extends UnitTestCase {
->with($path_part1) ->with($path_part1)
->will($this->returnValue(TRUE)); ->will($this->returnValue(TRUE));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('preloadPathAlias') ->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId()) ->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$cached_path => $cached_alias])); ->will($this->returnValue([$cached_path => $cached_alias]));
$this->aliasStorage->expects($this->once()) $this->aliasRepository->expects($this->once())
->method('lookupPathAlias') ->method('lookupBySystemPath')
->with($path, $language->getId()) ->with($path, $language->getId())
->will($this->returnValue($new_alias)); ->will($this->returnValue(['alias' => $new_alias]));
$this->assertEquals($new_alias, $this->aliasManager->getAliasByPath($path)); $this->assertEquals($new_alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache. // Call it twice to test the static cache.

View File

@ -0,0 +1,112 @@
<?php
namespace Drupal\Tests\Traits\Core;
use Drupal\Core\Language\LanguageInterface;
/**
* Provides methods to create and assert path_alias entities.
*
* This trait is meant to be used only by test classes.
*/
trait PathAliasTestTrait {
/**
* Creates a new path alias.
*
* @param string $path
* The system path.
* @param string $alias
* The alias for the system path.
* @param string $langcode
* (optional) A language code for the path alias. Defaults to
* \Drupal\Core\Language\LanguageInterface::LANGCODE_NOT_SPECIFIED.
*
* @return \Drupal\Core\Path\PathAliasInterface
* A path alias entity.
*/
protected function createPathAlias($path, $alias, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED) {
/** @var \Drupal\Core\Path\PathAliasInterface $path_alias */
$path_alias = \Drupal::entityTypeManager()->getStorage('path_alias')->create([
'path' => $path,
'alias' => $alias,
'langcode' => $langcode,
]);
$path_alias->save();
return $path_alias;
}
/**
* Gets the first result from a 'load by properties' storage call.
*
* @param array $conditions
* An array of query conditions.
*
* @return \Drupal\Core\Path\PathAliasInterface|null
* A path alias entity or NULL.
*/
protected function loadPathAliasByConditions($conditions) {
$storage = \Drupal::entityTypeManager()->getStorage('path_alias');
$query = $storage->getQuery();
foreach ($conditions as $field => $value) {
$query->condition($field, $value);
}
$entities = $storage->loadMultiple($query->execute());
return $entities ? reset($entities) : NULL;
}
/**
* Asserts that a path alias exists in the storage.
*
* @param string $alias
* The path alias.
* @param string|null $langcode
* (optional) The language code of the path alias.
* @param string|null $path
* (optional) The system path of the path alias.
* @param string|null $message
* (optional) A message to display with the assertion.
*/
protected function assertPathAliasExists($alias, $langcode = NULL, $path = NULL, $message = NULL) {
$query = \Drupal::entityTypeManager()->getStorage('path_alias')->getQuery();
$query->condition('alias', $alias, '=');
if ($langcode) {
$query->condition('langcode', $langcode, '=');
}
if ($path) {
$query->condition('path', $path, '=');
}
$query->count();
$this->assertTrue((bool) $query->execute(), $message);
}
/**
* Asserts that a path alias does not exist in the storage.
*
* @param string $alias
* The path alias.
* @param string|null $langcode
* (optional) The language code of the path alias.
* @param string|null $path
* (optional) The system path of the path alias.
* @param string|null $message
* (optional) A message to display with the assertion.
*/
protected function assertPathAliasNotExists($alias, $langcode = NULL, $path = NULL, $message = NULL) {
$query = \Drupal::entityTypeManager()->getStorage('path_alias')->getQuery();
$query->condition('alias', $alias, '=');
if ($langcode) {
$query->condition('langcode', $langcode, '=');
}
if ($path) {
$query->condition('path', $path, '=');
}
$query->count();
$this->assertFalse((bool) $query->execute(), $message);
}
}