first commit

This commit is contained in:
2020-06-08 23:57:36 +02:00
commit 6277454f7a
16057 changed files with 1715382 additions and 0 deletions
@@ -0,0 +1,7 @@
name: Path alias
type: module
description: 'Provides the API allowing to rename URLs.'
package: Core
version: VERSION
required: true
hidden: true
@@ -0,0 +1,25 @@
services:
path_alias.subscriber:
class: Drupal\path_alias\EventSubscriber\PathAliasSubscriber
tags:
- { name: event_subscriber }
arguments: ['@path_alias.manager', '@path.current']
path_alias.path_processor:
class: Drupal\path_alias\PathProcessor\AliasPathProcessor
tags:
- { name: path_processor_inbound, priority: 100 }
- { name: path_processor_outbound, priority: 300 }
arguments: ['@path_alias.manager']
path_alias.manager:
class: Drupal\path_alias\AliasManager
arguments: ['@path_alias.repository', '@path_alias.whitelist', '@language_manager', '@cache.data']
path_alias.repository:
class: Drupal\path_alias\AliasRepository
arguments: ['@database']
tags:
- { name: backend_overridable }
path_alias.whitelist:
class: Drupal\path_alias\AliasWhitelist
tags:
- { name: needs_destruction }
arguments: [path_alias_whitelist, '@cache.bootstrap', '@lock', '@state', '@path_alias.repository']
@@ -0,0 +1,10 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Path\AliasManager as CoreAliasManager;
/**
* The default alias manager implementation.
*/
class AliasManager extends CoreAliasManager implements AliasManagerInterface {}
@@ -0,0 +1,12 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Path\AliasManagerInterface as CoreAliasManagerInterface;
/**
* Find an alias for a path and vice versa.
*
* @see \Drupal\Core\Path\AliasStorageInterface
*/
interface AliasManagerInterface extends CoreAliasManagerInterface {}
@@ -0,0 +1,10 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Path\AliasRepository as CoreAliasRepository;
/**
* Provides the default path alias lookup operations.
*/
class AliasRepository extends CoreAliasRepository implements AliasRepositoryInterface {}
@@ -0,0 +1,20 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Path\AliasRepositoryInterface as CoreAliasRepositoryInterface;
/**
* 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 extends CoreAliasRepositoryInterface {}
@@ -0,0 +1,10 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Path\AliasWhitelist as CoreAliasWhitelist;
/**
* Extends CacheCollector to build the path alias whitelist over time.
*/
class AliasWhitelist extends CoreAliasWhitelist implements AliasWhitelistInterface {}
@@ -0,0 +1,15 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Path\AliasWhitelistInterface as CoreAliasWhitelistInterface;
/**
* Cache the alias whitelist.
*
* The whitelist contains the first element of the router paths of all
* aliases. For example, if /node/12345 has an alias then "node" is added to
* the whitelist. This optimization allows skipping the lookup for every
* /user/{user} path if "user" is not in the whitelist.
*/
interface AliasWhitelistInterface extends CoreAliasWhitelistInterface {}
@@ -0,0 +1,172 @@
<?php
namespace Drupal\path_alias\Entity;
use Drupal\Core\Entity\ContentEntityBase;
use Drupal\Core\Entity\EntityPublishedTrait;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\path_alias\PathAliasInterface;
/**
* Defines the path_alias entity class.
*
* @ContentEntityType(
* id = "path_alias",
* label = @Translation("URL alias"),
* label_collection = @Translation("URL aliases"),
* label_singular = @Translation("URL alias"),
* label_plural = @Translation("URL aliases"),
* label_count = @PluralTranslation(
* singular = "@count URL alias",
* plural = "@count URL aliases"
* ),
* handlers = {
* "storage" = "Drupal\path_alias\PathAliasStorage",
* "storage_schema" = "Drupal\path_alias\PathAliasStorageSchema",
* },
* base_table = "path_alias",
* revision_table = "path_alias_revision",
* entity_keys = {
* "id" = "id",
* "revision" = "revision_id",
* "langcode" = "langcode",
* "uuid" = "uuid",
* "published" = "status",
* },
* admin_permission = "administer url aliases",
* list_cache_tags = { "route_match" },
* constraints = {
* "UniquePathAlias" = {}
* }
* )
*/
class PathAlias extends ContentEntityBase implements PathAliasInterface {
use EntityPublishedTrait;
/**
* {@inheritdoc}
*/
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
$fields = parent::baseFieldDefinitions($entity_type);
$fields['path'] = BaseFieldDefinition::create('string')
->setLabel(new TranslatableMarkup('System path'))
->setDescription(new TranslatableMarkup('The path that this alias belongs to.'))
->setRequired(TRUE)
->setRevisionable(TRUE)
->addPropertyConstraints('value', [
'Regex' => [
'pattern' => '/^\//i',
'message' => new TranslatableMarkup('The source path has to start with a slash.'),
],
])
->addPropertyConstraints('value', ['ValidPath' => []]);
$fields['alias'] = BaseFieldDefinition::create('string')
->setLabel(new TranslatableMarkup('URL alias'))
->setDescription(new TranslatableMarkup('An alias used with this path.'))
->setRequired(TRUE)
->setRevisionable(TRUE)
->addPropertyConstraints('value', [
'Regex' => [
'pattern' => '/^\//i',
'message' => new TranslatableMarkup('The alias path has to start with a slash.'),
],
]);
$fields['langcode']->setDefaultValue(LanguageInterface::LANGCODE_NOT_SPECIFIED);
// Add the published field.
$fields += static::publishedBaseFieldDefinitions($entity_type);
$fields['status']->setTranslatable(FALSE);
return $fields;
}
/**
* {@inheritdoc}
*/
public function preSave(EntityStorageInterface $storage) {
parent::preSave($storage);
// Trim the alias value of whitespace and slashes. Ensure to not trim the
// slash on the left side.
$alias = rtrim(trim($this->getAlias()), "\\/");
$this->setAlias($alias);
}
/**
* {@inheritdoc}
*/
public function postSave(EntityStorageInterface $storage, $update = TRUE) {
parent::postSave($storage, $update);
$alias_manager = \Drupal::service('path_alias.manager');
$alias_manager->cacheClear($this->getPath());
if ($update) {
$alias_manager->cacheClear($this->original->getPath());
}
}
/**
* {@inheritdoc}
*/
public static function postDelete(EntityStorageInterface $storage, array $entities) {
parent::postDelete($storage, $entities);
$alias_manager = \Drupal::service('path_alias.manager');
foreach ($entities as $entity) {
$alias_manager->cacheClear($entity->getPath());
}
}
/**
* {@inheritdoc}
*/
public function getPath() {
return $this->get('path')->value;
}
/**
* {@inheritdoc}
*/
public function setPath($path) {
$this->set('path', $path);
return $this;
}
/**
* {@inheritdoc}
*/
public function getAlias() {
return $this->get('alias')->value;
}
/**
* {@inheritdoc}
*/
public function setAlias($alias) {
$this->set('alias', $alias);
return $this;
}
/**
* {@inheritdoc}
*/
public function label() {
return $this->getAlias();
}
/**
* {@inheritdoc}
*/
public function getCacheTagsToInvalidate() {
return ['route_match'];
}
}
@@ -0,0 +1,10 @@
<?php
namespace Drupal\path_alias\EventSubscriber;
use Drupal\Core\EventSubscriber\PathSubscriber;
/**
* Provides a path subscriber that converts path aliases.
*/
class PathAliasSubscriber extends PathSubscriber {}
@@ -0,0 +1,49 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityPublishedInterface;
/**
* Provides an interface defining a path_alias entity.
*/
interface PathAliasInterface extends ContentEntityInterface, EntityPublishedInterface {
/**
* Gets the source path of the alias.
*
* @return string
* The source path.
*/
public function getPath();
/**
* Sets the source path of the alias.
*
* @param string $path
* The source path.
*
* @return $this
*/
public function setPath($path);
/**
* Gets the alias for this path.
*
* @return string
* The alias for this path.
*/
public function getAlias();
/**
* Sets the alias for this path.
*
* @param string $alias
* The path alias.
*
* @return $this
*/
public function setAlias($alias);
}
@@ -0,0 +1,51 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
/**
* Defines the storage handler class for path_alias entities.
*/
class PathAliasStorage extends SqlContentEntityStorage {
/**
* {@inheritdoc}
*/
protected function invokeHook($hook, EntityInterface $entity) {
parent::invokeHook($hook, $entity);
// Invoke the deprecated hook_path_OPERATION() hooks.
if ($hook === 'insert' || $hook === 'update' || $hook === 'delete') {
$values = [
'pid' => $entity->id(),
'source' => $entity->getPath(),
'alias' => $entity->getAlias(),
'langcode' => $entity->language()->getId(),
];
if ($hook === 'update') {
$values['original'] = [
'pid' => $entity->id(),
'source' => $entity->original->getPath(),
'alias' => $entity->original->getAlias(),
'langcode' => $entity->original->language()->getId(),
];
}
$this->moduleHandler()->invokeAllDeprecated("It will be removed before Drupal 9.0.0. Use hook_ENTITY_TYPE_{$hook}() for the 'path_alias' entity type instead. See https://www.drupal.org/node/3013865.", 'path_' . $hook, [$values]);
}
}
/**
* {@inheritdoc}
*/
public function createWithSampleValues($bundle = FALSE, array $values = []) {
$entity = parent::createWithSampleValues($bundle, ['path' => '/<front>'] + $values);
// Ensure the alias is only 255 characters long.
$entity->set('alias', substr('/' . $entity->get('alias')->value, 0, 255));
return $entity;
}
}
@@ -0,0 +1,27 @@
<?php
namespace Drupal\path_alias;
use Drupal\Core\Entity\ContentEntityTypeInterface;
use Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema;
/**
* Defines the path_alias schema handler.
*/
class PathAliasStorageSchema extends SqlContentEntityStorageSchema {
/**
* {@inheritdoc}
*/
protected function getEntitySchema(ContentEntityTypeInterface $entity_type, $reset = FALSE) {
$schema = parent::getEntitySchema($entity_type, $reset);
$schema[$this->storage->getBaseTable()]['indexes'] += [
'path_alias__alias_langcode_id_status' => ['alias', 'langcode', 'id', 'status'],
'path_alias__path_langcode_id_status' => ['path', 'langcode', 'id', 'status'],
];
return $schema;
}
}
@@ -0,0 +1,10 @@
<?php
namespace Drupal\path_alias\PathProcessor;
use Drupal\Core\PathProcessor\PathProcessorAlias;
/**
* Processes the inbound path using path alias lookups.
*/
class AliasPathProcessor extends PathProcessorAlias {}
@@ -0,0 +1,5 @@
name: 'Path Alias deprecated test'
type: module
description: 'Support module for testing deprecated functionality for path aliases.'
package: Testing
version: VERSION
@@ -0,0 +1,5 @@
services:
path_alias_deprecated_test.path.alias_manager:
class: Drupal\path_alias_deprecated_test\AliasManagerDecorator
decorates: path.alias_manager
arguments: ['@path_alias_deprecated_test.path.alias_manager.inner']
@@ -0,0 +1,50 @@
<?php
namespace Drupal\path_alias_deprecated_test;
use Drupal\Core\Path\AliasManagerInterface;
/**
* Test alias manager decorator.
*/
class AliasManagerDecorator implements AliasManagerInterface {
/**
* The decorated alias manager.
*
* @var \Drupal\Core\Path\AliasManagerInterface
*/
protected $aliasManager;
/**
* AliasManagerDecorator constructor.
*
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
* The decorated alias manager.
*/
public function __construct(AliasManagerInterface $alias_manager) {
$this->aliasManager = $alias_manager;
}
/**
* {@inheritdoc}
*/
public function getPathByAlias($alias, $langcode = NULL) {
$this->aliasManager->getPathByAlias($alias, $langcode);
}
/**
* {@inheritdoc}
*/
public function getAliasByPath($path, $langcode = NULL) {
return $this->aliasManager->getAliasByPath($path, $langcode);
}
/**
* {@inheritdoc}
*/
public function cacheClear($source = NULL) {
$this->aliasManager->cacheClear($source);
}
}
@@ -0,0 +1,30 @@
<?php
namespace Drupal\path_alias_deprecated_test;
use Drupal\Core\Path\AliasManagerInterface;
/**
* New test implementation for the alias manager.
*/
class NewAliasManager implements AliasManagerInterface {
/**
* {@inheritdoc}
*/
public function getPathByAlias($alias, $langcode = NULL) {
}
/**
* {@inheritdoc}
*/
public function getAliasByPath($path, $langcode = NULL) {
}
/**
* {@inheritdoc}
*/
public function cacheClear($source = NULL) {
}
}
@@ -0,0 +1,10 @@
<?php
namespace Drupal\path_alias_deprecated_test;
use Drupal\Core\Path\AliasManager;
/**
* Overridden test implementation for the alias manager.
*/
class OverriddenAliasManager extends AliasManager {}
@@ -0,0 +1,44 @@
<?php
namespace Drupal\path_alias_deprecated_test;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceModifierInterface;
/**
* Test service provider to test path alias deprecated services BC logic.
*/
class PathAliasDeprecatedTestServiceProvider implements ServiceModifierInterface {
/**
* The name of the new implementation class for the alias manager.
*
* @var string
*/
public static $newClass;
/**
* Whether to use a decorator to wrap the alias manager implementation.
*
* @var bool
*/
public static $useDecorator = FALSE;
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
if (isset(static::$newClass)) {
$definition = $container->getDefinition('path.alias_manager');
$definition->setClass(static::$newClass);
}
if (!static::$useDecorator) {
$decorator_id = 'path_alias_deprecated_test.path.alias_manager';
if ($container->hasDefinition($decorator_id)) {
$container->removeDefinition($decorator_id);
}
}
}
}
@@ -0,0 +1,35 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Hal;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* @group hal
* @group path_alias
*/
class PathAliasHalJsonAnonTest extends PathAliasHalJsonTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
}
@@ -0,0 +1,40 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Hal;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* @group hal
* @group path_alias
*/
class PathAliasHalJsonBasicAuthTest extends PathAliasHalJsonTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal', 'basic_auth'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,40 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Hal;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* @group hal
* @group path_alias
*/
class PathAliasHalJsonCookieTest extends PathAliasHalJsonTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['hal'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $format = 'hal_json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/hal+json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
}
@@ -0,0 +1,56 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Hal;
use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
use Drupal\Tests\path_alias\Functional\Rest\PathAliasResourceTestBase;
/**
* Base hal_json test class for the path_alias entity type.
*/
abstract class PathAliasHalJsonTestBase extends PathAliasResourceTestBase {
use HalEntityNormalizationTrait;
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
$default_normalization = parent::getExpectedNormalizedEntity();
$normalization = $this->applyHalFieldNormalization($default_normalization);
return $normalization + [
'_links' => [
'self' => [
'href' => $this->baseUrl . '/entity/path_alias/1?_format=hal_json',
],
'type' => [
'href' => $this->baseUrl . '/rest/type/path_alias/path_alias',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return parent::getNormalizedPostEntity() + [
'_links' => [
'type' => [
'href' => $this->baseUrl . '/rest/type/path_alias/path_alias',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheContexts() {
return [
'url.site',
'user.permissions',
];
}
}
@@ -0,0 +1,31 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
/**
* Test path_alias entities for unauthenticated JSON requests.
*
* @group path_alias
*/
class PathAliasJsonAnonTest extends PathAliasResourceTestBase {
use AnonResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
}
@@ -0,0 +1,41 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
/**
* Test path_alias entities for JSON requests via basic auth.
*
* @group path_alias
*/
class PathAliasJsonBasicAuthTest extends PathAliasResourceTestBase {
use BasicAuthResourceTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,36 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
/**
* Test path_alias entities for JSON requests with cookie authentication.
*
* @group path_alias
*/
class PathAliasJsonCookieTest extends PathAliasResourceTestBase {
use CookieResourceTestTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'json';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'application/json';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
}
@@ -0,0 +1,129 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Core\Language\LanguageInterface;
use Drupal\path_alias\Entity\PathAlias;
use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
/**
* Base class for path_alias EntityResource tests.
*/
abstract class PathAliasResourceTestBase extends EntityResourceTestBase {
use BcTimestampNormalizerUnixTestTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['path_alias'];
/**
* {@inheritdoc}
*/
protected static $entityTypeId = 'path_alias';
/**
* {@inheritdoc}
*/
protected static $patchProtectedFieldNames = [];
/**
* {@inheritdoc}
*/
protected static $firstCreatedEntityId = 3;
/**
* {@inheritdoc}
*/
protected static $secondCreatedEntityId = 4;
/**
* {@inheritdoc}
*/
protected function setUpAuthorization($method) {
$this->grantPermissionsToTestedRole(['administer url aliases']);
}
/**
* {@inheritdoc}
*/
protected function createEntity() {
$path_alias = PathAlias::create([
'path' => '/<front>',
'alias' => '/frontpage1',
]);
$path_alias->save();
return $path_alias;
}
/**
* {@inheritdoc}
*/
protected function getExpectedNormalizedEntity() {
return [
'id' => [
[
'value' => 1,
],
],
'revision_id' => [
[
'value' => 1,
],
],
'langcode' => [
[
'value' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
],
],
'path' => [
[
'value' => '/<front>',
],
],
'alias' => [
[
'value' => '/frontpage1',
],
],
'status' => [
[
'value' => TRUE,
],
],
'uuid' => [
[
'value' => $this->entity->uuid(),
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getNormalizedPostEntity() {
return [
'path' => [
[
'value' => '/<front>',
],
],
'alias' => [
[
'value' => '/frontpage1',
],
],
];
}
/**
* {@inheritdoc}
*/
protected function getExpectedCacheContexts() {
return ['user.permissions'];
}
}
@@ -0,0 +1,33 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* Test path_alias entities for unauthenticated XML requests.
*
* @group path_alias
*/
class PathAliasXmlAnonTest extends PathAliasResourceTestBase {
use AnonResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
}
@@ -0,0 +1,43 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* Test path_alias entities for XML requests with cookie authentication.
*
* @group path_alias
*/
class PathAliasXmlBasicAuthTest extends PathAliasResourceTestBase {
use BasicAuthResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
public static $modules = ['basic_auth'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'basic_auth';
}
@@ -0,0 +1,38 @@
<?php
namespace Drupal\Tests\path_alias\Functional\Rest;
use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
use Drupal\Tests\rest\Functional\EntityResource\XmlEntityNormalizationQuirksTrait;
/**
* Test path_alias entities for XML requests.
*
* @group path_alias
*/
class PathAliasXmlCookieTest extends PathAliasResourceTestBase {
use CookieResourceTestTrait;
use XmlEntityNormalizationQuirksTrait;
/**
* {@inheritdoc}
*/
protected static $format = 'xml';
/**
* {@inheritdoc}
*/
protected static $mimeType = 'text/xml; charset=UTF-8';
/**
* {@inheritdoc}
*/
protected static $auth = 'cookie';
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
}
@@ -0,0 +1,126 @@
<?php
namespace Drupal\Tests\path_alias\Functional;
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Database\Database;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
use Drupal\taxonomy\Entity\Term;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/**
* Tests altering the inbound path and the outbound path.
*
* @group path_alias
*/
class UrlAlterFunctionalTest extends BrowserTestBase {
use PathAliasTestTrait;
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['path', 'forum', 'url_alter_test'];
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* Test that URL altering works and that it occurs in the correct order.
*/
public function testUrlAlter() {
// Ensure that the path_alias table exists after Drupal installation.
$this->assertTrue(Database::getConnection()->schema()->tableExists('path_alias'), 'The path_alias table exists after Drupal installation.');
// User names can have quotes and plus signs so we should ensure that URL
// altering works with this.
$account = $this->drupalCreateUser(['administer url aliases'], "a'foo+bar");
$this->drupalLogin($account);
$uid = $account->id();
$name = $account->getAccountName();
// Test a single altered path.
$this->drupalGet("user/$name");
$this->assertSession()->statusCodeEquals(200);
$this->assertUrlOutboundAlter("/user/$uid", "/user/$name");
// Test that a path always uses its alias.
$this->createPathAlias("/user/$uid/test1", '/alias/test1');
$this->rebuildContainer();
$this->assertUrlInboundAlter('/alias/test1', "/user/$uid/test1");
$this->assertUrlOutboundAlter("/user/$uid/test1", '/alias/test1');
// Test adding an alias via the UI.
$edit = ['path[0][value]' => "/user/$uid/edit", 'alias[0][value]' => '/alias/test2'];
$this->drupalPostForm('admin/config/search/path/add', $edit, t('Save'));
$this->assertText(t('The alias has been saved.'));
$this->drupalGet('alias/test2');
$this->assertSession()->statusCodeEquals(200);
$this->assertUrlOutboundAlter("/user/$uid/edit", '/alias/test2');
// Test a non-existent user is not altered.
$uid++;
$this->assertUrlOutboundAlter("/user/$uid", "/user/$uid");
// Test that 'forum' is altered to 'community' correctly, both at the root
// level and for a specific existing forum.
$this->drupalGet('community');
$this->assertText('General discussion', 'The community path gets resolved correctly');
$this->assertUrlOutboundAlter('/forum', '/community');
$forum_vid = $this->config('forum.settings')->get('vocabulary');
$term_name = $this->randomMachineName();
$term = Term::create([
'name' => $term_name,
'vid' => $forum_vid,
]);
$term->save();
$this->drupalGet("community/" . $term->id());
$this->assertText($term_name, 'The community/{tid} path gets resolved correctly');
$this->assertUrlOutboundAlter("/forum/" . $term->id(), "/community/" . $term->id());
// Test outbound query string altering.
$url = Url::fromRoute('user.login');
$this->assertIdentical(\Drupal::request()->getBaseUrl() . '/user/login?foo=bar', $url->toString());
}
/**
* Assert that an outbound path is altered to an expected value.
*
* @param $original
* A string with the original path that is run through generateFrommPath().
* @param $final
* A string with the expected result after generateFrommPath().
*
* @return
* TRUE if $original was correctly altered to $final, FALSE otherwise.
*/
protected function assertUrlOutboundAlter($original, $final) {
// Test outbound altering.
$result = $this->container->get('path_processor_manager')->processOutbound($original);
return $this->assertIdentical($result, $final, new FormattableMarkup('Altered outbound URL %original, expected %final, and got %result.', ['%original' => $original, '%final' => $final, '%result' => $result]));
}
/**
* Assert that a inbound path is altered to an expected value.
*
* @param $original
* The original path before it has been altered by inbound URL processing.
* @param $final
* A string with the expected result.
*
* @return
* TRUE if $original was correctly altered to $final, FALSE otherwise.
*/
protected function assertUrlInboundAlter($original, $final) {
// Test inbound altering.
$result = $this->container->get('path_alias.manager')->getPathByAlias($original);
return $this->assertIdentical($result, $final, new FormattableMarkup('Altered inbound URL %original, expected %final, and got %result.', ['%original' => $original, '%final' => $final, '%result' => $result]));
}
}
@@ -0,0 +1,226 @@
<?php
namespace Drupal\Tests\path_alias\Kernel;
use Drupal\Core\Cache\MemoryCounterBackend;
use Drupal\Core\Language\LanguageInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\path_alias\AliasManager;
use Drupal\path_alias\AliasWhitelist;
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
/**
* Tests path alias CRUD and lookup functionality.
*
* @coversDefaultClass \Drupal\path_alias\AliasRepository
*
* @group path_alias
*/
class AliasTest extends KernelTestBase {
use PathAliasTestTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['path_alias'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// The alias whitelist expects that the menu path roots are set by a
// menu router rebuild.
\Drupal::state()->set('router.path_roots', ['user', 'admin']);
$this->installEntitySchema('path_alias');
}
/**
* @covers ::lookupBySystemPath
*/
public function testLookupBySystemPath() {
$this->createPathAlias('/test-source-Case', '/test-alias');
$path_alias_repository = $this->container->get('path_alias.repository');
$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']);
}
/**
* @covers ::lookupByAlias
*/
public function testLookupByAlias() {
$this->createPathAlias('/test-source', '/test-alias-Case');
$path_alias_repository = $this->container->get('path_alias.repository');
$this->assertEquals('/test-source', $path_alias_repository->lookupByAlias('/test-alias-Case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['path']);
$this->assertEquals('/test-source', $path_alias_repository->lookupByAlias('/test-alias-case', LanguageInterface::LANGCODE_NOT_SPECIFIED)['path']);
}
/**
* @covers \Drupal\path_alias\AliasManager::getPathByAlias
* @covers \Drupal\path_alias\AliasManager::getAliasByPath
*/
public function testLookupPath() {
// Create AliasManager and Path object.
$aliasManager = $this->container->get('path_alias.manager');
// Test the situation where the source is the same for multiple aliases.
// Start with a language-neutral alias, which we will override.
$path_alias = $this->createPathAlias('/user/1', '/foo');
$this->assertEquals($path_alias->getAlias(), $aliasManager->getAliasByPath($path_alias->getPath()), 'Basic alias lookup works.');
$this->assertEquals($path_alias->getPath(), $aliasManager->getPathByAlias($path_alias->getAlias()), 'Basic source lookup works.');
// Create a language specific alias for the default language (English).
$path_alias = $this->createPathAlias('/user/1', '/users/Dries', 'en');
$this->assertEquals($path_alias->getAlias(), $aliasManager->getAliasByPath($path_alias->getPath()), 'English alias overrides language-neutral alias.');
$this->assertEquals($path_alias->getPath(), $aliasManager->getPathByAlias($path_alias->getAlias()), 'English source overrides language-neutral source.');
// Create a language-neutral alias for the same path, again.
$path_alias = $this->createPathAlias('/user/1', '/bar');
$this->assertEquals("/users/Dries", $aliasManager->getAliasByPath($path_alias->getPath()), 'English alias still returned after entering a language-neutral alias.');
// Create a language-specific (xx-lolspeak) alias for the same path.
$path_alias = $this->createPathAlias('/user/1', '/LOL', 'xx-lolspeak');
$this->assertEquals("/users/Dries", $aliasManager->getAliasByPath($path_alias->getPath()), 'English alias still returned after entering a LOLspeak alias.');
// The LOLspeak alias should be returned if we really want LOLspeak.
$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
// previous alias for "user/1".
$path_alias = $this->createPathAlias('/user/1', '/users/my-new-path', 'en');
$this->assertEquals($path_alias->getAlias(), $aliasManager->getAliasByPath($path_alias->getPath()), 'Recently created English alias returned.');
$this->assertEquals($path_alias->getPath(), $aliasManager->getPathByAlias($path_alias->getAlias()), 'Recently created English source returned.');
// Remove the English aliases, which should cause a fallback to the most
// recently created language-neutral alias, 'bar'.
$path_alias_storage = $this->container->get('entity_type.manager')->getStorage('path_alias');
$entities = $path_alias_storage->loadByProperties(['langcode' => 'en']);
$path_alias_storage->delete($entities);
$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
// the source differs. The newer alias record should be returned.
$this->createPathAlias('/user/2', '/bar');
$aliasManager->cacheClear();
$this->assertEquals('/user/2', $aliasManager->getPathByAlias('/bar'), 'Newer alias record is returned when comparing two LanguageInterface::LANGCODE_NOT_SPECIFIED paths with the same alias.');
}
/**
* Tests the alias whitelist.
*/
public function testWhitelist() {
$memoryCounterBackend = new MemoryCounterBackend();
// Create AliasManager and Path object.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
$aliasManager = new AliasManager($this->container->get('path_alias.repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend);
// No alias for user and admin yet, so should be NULL.
$this->assertNull($whitelist->get('user'));
$this->assertNull($whitelist->get('admin'));
// Non-existing path roots should be NULL too. Use a length of 7 to avoid
// possible conflict with random aliases below.
$this->assertNull($whitelist->get($this->randomMachineName()));
// Add an alias for user/1, user should get whitelisted now.
$this->createPathAlias('/user/1', '/' . $this->randomMachineName());
$aliasManager->cacheClear();
$this->assertTrue($whitelist->get('user'));
$this->assertNull($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName()));
// Add an alias for admin, both should get whitelisted now.
$this->createPathAlias('/admin/something', '/' . $this->randomMachineName());
$aliasManager->cacheClear();
$this->assertTrue($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName()));
// Remove the user alias again, whitelist entry should be removed.
$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();
$this->assertNull($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName()));
// Destruct the whitelist so that the caches are written.
$whitelist->destruct();
$this->assertEqual($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 1);
$memoryCounterBackend->resetCounter();
// Re-initialize the whitelist using the same cache backend, should load
// from cache.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
$this->assertNull($whitelist->get('user'));
$this->assertTrue($whitelist->get('admin'));
$this->assertNull($whitelist->get($this->randomMachineName()));
$this->assertEqual($memoryCounterBackend->getCounter('get', 'path_alias_whitelist'), 1);
$this->assertEqual($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 0);
// Destruct the whitelist, should not attempt to write the cache again.
$whitelist->destruct();
$this->assertEqual($memoryCounterBackend->getCounter('get', 'path_alias_whitelist'), 1);
$this->assertEqual($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 0);
}
/**
* Tests situation where the whitelist cache is deleted mid-request.
*/
public function testWhitelistCacheDeletionMidRequest() {
$memoryCounterBackend = new MemoryCounterBackend();
// Create AliasManager and Path object.
$whitelist = new AliasWhitelist('path_alias_whitelist', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
$aliasManager = new AliasManager($this->container->get('path_alias.repository'), $whitelist, $this->container->get('language_manager'), $memoryCounterBackend);
// Whitelist cache should not exist at all yet.
$this->assertFalse($memoryCounterBackend->get('path_alias_whitelist'));
// Add some aliases for both menu routes we have.
$this->createPathAlias('/admin/something', '/' . $this->randomMachineName());
$this->createPathAlias('/user/something', '/' . $this->randomMachineName());
// 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
// flag it to be persisted to cache.
$this->assertTrue($whitelist->get('admin'));
// Destruct the whitelist so it persists its cache.
$whitelist->destruct();
$this->assertEquals($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 1);
// Cache data should have data for 'user' and 'admin', even though just
// 'admin' was looked up. This is because the cache is primed with all
// menu router base paths.
$this->assertEquals(['user' => FALSE, 'admin' => TRUE], $memoryCounterBackend->get('path_alias_whitelist')->data);
$memoryCounterBackend->resetCounter();
// Re-initialize the whitelist and lookup an alias for the 'user' path.
// 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
// persisted to cache.
$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'));
// Delete the whitelist cache. This could happen from an outside process,
// like a code deployment that performs a cache rebuild.
$memoryCounterBackend->delete('path_alias_whitelist');
// Destruct whitelist so it attempts to save the whitelist data to cache.
// However it should recognize that the previous cache entry was deleted
// from underneath it and not save anything to cache, to protect from
// cache corruption.
$whitelist->destruct();
$this->assertEquals($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 0);
$this->assertFalse($memoryCounterBackend->get('path_alias_whitelist'));
$memoryCounterBackend->resetCounter();
}
}
@@ -0,0 +1,190 @@
<?php
namespace Drupal\Tests\path_alias\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Core\Path\AliasManager as CoreAliasManager;
use Drupal\path_alias\AliasManager;
use Drupal\path_alias\Entity\PathAlias;
use Drupal\path_alias_deprecated_test\AliasManagerDecorator;
use Drupal\path_alias_deprecated_test\NewAliasManager;
use Drupal\path_alias_deprecated_test\OverriddenAliasManager;
use Drupal\path_alias_deprecated_test\PathAliasDeprecatedTestServiceProvider;
/**
* Tests deprecation of path alias core services and the related BC logic.
*
* @group path_alias
* @group legacy
*/
class DeprecatedServicesTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['path_alias', 'path_alias_deprecated_test'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('path_alias');
}
/**
* @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086
* @expectedDeprecation The "path_processor_alias" service is deprecated. Use "path_alias.path_processor" instead. See https://drupal.org/node/3092086
* @expectedDeprecation The "path_subscriber" service is deprecated. Use "path_alias.subscriber" instead. See https://drupal.org/node/3092086
*/
public function testAliasServicesDeprecation() {
$this->container->get('path.alias_manager');
$this->container->get('path_processor_alias');
$this->container->get('path_subscriber');
}
/**
* @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086
* @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086
*/
public function testOverriddenServiceImplementation() {
$class = $this->setServiceClass(OverriddenAliasManager::class);
$this->assertServiceClass('path.alias_manager', $class);
$this->assertServiceClass('path_alias.manager', AliasManager::class);
}
/**
* @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086
*/
public function testNewServiceImplementation() {
$class = $this->setServiceClass(NewAliasManager::class);
$this->assertServiceClass('path.alias_manager', $class);
$this->assertServiceClass('path_alias.manager', AliasManager::class);
}
/**
* @expectedDeprecation The "path_alias_deprecated_test.path.alias_manager.inner" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086
* @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086
*/
public function testDecoratorForOverriddenServiceImplementation() {
$this->setServiceClass(OverriddenAliasManager::class, TRUE);
$this->assertServiceClass('path.alias_manager', AliasManagerDecorator::class);
$this->assertServiceClass('path_alias.manager', AliasManager::class);
}
/**
* @expectedDeprecation The "path_alias_deprecated_test.path.alias_manager.inner" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086
*/
public function testDecoratorForNewServiceImplementation() {
$this->setServiceClass(NewAliasManager::class, TRUE);
$this->assertServiceClass('path.alias_manager', AliasManagerDecorator::class);
$this->assertServiceClass('path_alias.manager', AliasManager::class);
}
/**
* @expectedDeprecation The "path.alias_manager" service is deprecated. Use "path_alias.manager" instead. See https://drupal.org/node/3092086
*/
public function testDefaultImplementations() {
$this->assertServiceClass('path.alias_manager', CoreAliasManager::class);
$this->assertServiceClass('path_alias.manager', AliasManager::class);
}
/**
* No deprecation message expected.
*/
public function testRegularImplementation() {
$this->assertServiceClass('path_alias.manager', AliasManager::class);
}
/**
* Test that the new alias manager and the legacy ones share the same state.
*
* @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086
*/
public function testAliasManagerSharedState() {
/** @var \Drupal\Core\Path\AliasManager $legacy_alias_manager */
$legacy_alias_manager = $this->container->get('path.alias_manager');
/** @var \Drupal\path_alias\AliasManager $alias_manager */
$alias_manager = $this->container->get('path_alias.manager');
$cache_key = $this->randomMachineName();
$alias_manager->setCacheKey($cache_key);
$this->assertSharedProperty('preload-paths:' . $cache_key, $legacy_alias_manager, 'cacheKey');
$invalid_alias = '/' . $this->randomMachineName();
$alias_manager->getPathByAlias($invalid_alias);
$this->assertSharedProperty(['en' => [$invalid_alias => TRUE]], $legacy_alias_manager, 'noPath');
$this->assertSharedProperty(FALSE, $legacy_alias_manager, 'preloadedPathLookups');
/** @var \Drupal\path_alias\Entity\PathAlias $alias */
$alias = PathAlias::create([
'path' => '/' . $this->randomMachineName(),
'alias' => $invalid_alias . '2',
]);
$alias->save();
$this->assertSharedProperty([], $legacy_alias_manager, 'preloadedPathLookups');
/** @var \Drupal\Core\State\StateInterface $state */
$state = $this->container->get('state');
$state->set('router.path_roots', [ltrim($alias->getPath(), '/')]);
$alias_manager->getAliasByPath($alias->getPath());
$this->assertSharedProperty(['en' => [$alias->getPath() => $alias->getAlias()]], $legacy_alias_manager, 'lookupMap');
$invalid_path = $alias->getPath() . '/' . $this->randomMachineName();
$alias_manager->getAliasByPath($invalid_path);
$this->assertSharedProperty(['en' => [$invalid_path => TRUE]], $legacy_alias_manager, 'noAlias');
}
/**
* Asserts that a shared property has the expected value.
*
* @param mixed $expected
* The property expected value.
* @param \Drupal\Core\Path\AliasManager $legacy_alias_manager
* An instance of the legacy alias manager.
* @param string $property
* The property name.
*/
protected function assertSharedProperty($expected, CoreAliasManager $legacy_alias_manager, $property) {
$reflector = new \ReflectionProperty(get_class($legacy_alias_manager), $property);
$reflector->setAccessible(TRUE);
$this->assertSame($expected, $reflector->getValue($legacy_alias_manager));
}
/**
* Asserts that the specified service is implemented by the expected class.
*
* @param string $service_id
* A service ID.
* @param string $expected_class
* The name of the expected class.
*/
protected function assertServiceClass($service_id, $expected_class) {
$service = $this->container->get($service_id);
$this->assertSame(get_class($service), $expected_class);
}
/**
* Sets the specified implementation for the service being tested.
*
* @param string $class
* The name of the implementation class.
* @param bool $use_decorator
* (optional) Whether using a decorator service to wrap the specified class.
* Defaults to no decorator.
*
* @return string
* The specified class name.
*/
protected function setServiceClass($class, $use_decorator = FALSE) {
PathAliasDeprecatedTestServiceProvider::$newClass = $class;
PathAliasDeprecatedTestServiceProvider::$useDecorator = $use_decorator;
$this->container->get('kernel')->rebuildContainer();
return $class;
}
}
@@ -0,0 +1,71 @@
<?php
namespace Drupal\Tests\path_alias\Kernel;
use Drupal\KernelTests\KernelTestBase;
use Drupal\path_alias\AliasManagerInterface;
use Drupal\path_alias\Entity\PathAlias;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\path_alias\Entity\PathAlias
*
* @group path_alias
*/
class PathHooksTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['path_alias'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('path_alias');
}
/**
* Tests that the PathAlias entity clears caches correctly.
*
* @covers ::postSave
* @covers ::postDelete
*/
public function testPathHooks() {
$path_alias = PathAlias::create([
'path' => '/' . $this->randomMachineName(),
'alias' => '/' . $this->randomMachineName(),
]);
// Check \Drupal\Core\Path\Entity\PathAlias::postSave() for new path alias
// entities.
$alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($path_alias->getPath())->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path_alias.manager', $alias_manager->reveal());
$path_alias->save();
$new_source = '/' . $this->randomMachineName();
// Check \Drupal\Core\Path\Entity\PathAlias::postSave() for existing path
// alias entities.
$alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(2);
$alias_manager->cacheClear($path_alias->getPath())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path_alias.manager', $alias_manager->reveal());
$path_alias->setPath($new_source);
$path_alias->save();
// Check \Drupal\Core\Path\Entity\PathAlias::postDelete().
$alias_manager = $this->prophesize(AliasManagerInterface::class);
$alias_manager->cacheClear(Argument::any())->shouldBeCalledTimes(1);
$alias_manager->cacheClear($new_source)->shouldBeCalledTimes(1);
\Drupal::getContainer()->set('path_alias.manager', $alias_manager->reveal());
$path_alias->delete();
}
}
@@ -0,0 +1,554 @@
<?php
namespace Drupal\Tests\path_alias\Unit;
use Drupal\Core\Language\Language;
use Drupal\Core\Language\LanguageInterface;
use Drupal\path_alias\AliasRepositoryInterface;
use Drupal\path_alias\AliasManager;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\path_alias\AliasManager
* @group path_alias
*/
class AliasManagerTest extends UnitTestCase {
/**
* The alias manager.
*
* @var \Drupal\path_alias\AliasManager
*/
protected $aliasManager;
/**
* Alias storage.
*
* @var \Drupal\Core\Path\AliasStorageInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $aliasStorage;
/**
* Alias repository.
*
* @var \Drupal\path_alias\AliasRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $aliasRepository;
/**
* Alias whitelist.
*
* @var \Drupal\path_alias\AliasWhitelistInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $aliasWhitelist;
/**
* Language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $languageManager;
/**
* Cache backend.
*
* @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $cache;
/**
* The internal cache key used by the alias manager.
*
* @var string
*/
protected $cacheKey = 'preload-paths:key';
/**
* The cache key passed to the alias manager.
*
* @var string
*/
protected $path = 'key';
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->aliasRepository = $this->createMock(AliasRepositoryInterface::class);
$this->aliasWhitelist = $this->createMock('Drupal\path_alias\AliasWhitelistInterface');
$this->languageManager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
$this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface');
$this->aliasManager = new AliasManager($this->aliasRepository, $this->aliasWhitelist, $this->languageManager, $this->cache);
}
/**
* Tests the getPathByAlias method for an alias that have no matching path.
*
* @covers ::getPathByAlias
*/
public function testGetPathByAliasNoMatch() {
$alias = '/' . $this->randomMachineName();
$language = new Language(['id' => 'en']);
$this->languageManager->expects($this->any())
->method('getCurrentLanguage')
->with(LanguageInterface::TYPE_URL)
->will($this->returnValue($language));
$this->aliasRepository->expects($this->once())
->method('lookupByAlias')
->with($alias, $language->getId())
->will($this->returnValue(NULL));
$this->assertEquals($alias, $this->aliasManager->getPathByAlias($alias));
// Call it twice to test the static cache.
$this->assertEquals($alias, $this->aliasManager->getPathByAlias($alias));
}
/**
* Tests the getPathByAlias method for an alias that have a matching path.
*
* @covers ::getPathByAlias
*/
public function testGetPathByAliasNatch() {
$alias = $this->randomMachineName();
$path = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$this->aliasRepository->expects($this->once())
->method('lookupByAlias')
->with($alias, $language->getId())
->will($this->returnValue(['path' => $path]));
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias));
// Call it twice to test the static cache.
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias));
}
/**
* Tests the getPathByAlias method when a langcode is passed explicitly.
*
* @covers ::getPathByAlias
*/
public function testGetPathByAliasLangcode() {
$alias = $this->randomMachineName();
$path = $this->randomMachineName();
$this->languageManager->expects($this->never())
->method('getCurrentLanguage');
$this->aliasRepository->expects($this->once())
->method('lookupByAlias')
->with($alias, 'de')
->will($this->returnValue(['path' => $path]));
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, 'de'));
// Call it twice to test the static cache.
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, 'de'));
}
/**
* Tests the getAliasByPath method for a path that is not in the whitelist.
*
* @covers ::getAliasByPath
*/
public function testGetAliasByPathWhitelist() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$this->setUpCurrentLanguage();
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(FALSE));
// The whitelist returns FALSE for that path part, so the storage should
// never be called.
$this->aliasRepository->expects($this->never())
->method('lookupBySystemPath');
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
}
/**
* Tests the getAliasByPath method for a path that has no matching alias.
*
* @covers ::getAliasByPath
*/
public function testGetAliasByPathNoMatch() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$language = $this->setUpCurrentLanguage();
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
$this->aliasRepository->expects($this->once())
->method('lookupBySystemPath')
->with($path, $language->getId())
->will($this->returnValue(NULL));
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// This needs to write out the cache.
$this->cache->expects($this->once())
->method('set')
->with($this->cacheKey, [$language->getId() => [$path]], (int) $_SERVER['REQUEST_TIME'] + (60 * 60 * 24));
$this->aliasManager->writeCache();
}
/**
* Tests the getAliasByPath method for a path that has a matching alias.
*
* @covers ::getAliasByPath
* @covers ::writeCache
*/
public function testGetAliasByPathMatch() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$alias = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
$this->aliasRepository->expects($this->once())
->method('lookupBySystemPath')
->with($path, $language->getId())
->will($this->returnValue(['alias' => $alias]));
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// This needs to write out the cache.
$this->cache->expects($this->once())
->method('set')
->with($this->cacheKey, [$language->getId() => [$path]], (int) $_SERVER['REQUEST_TIME'] + (60 * 60 * 24));
$this->aliasManager->writeCache();
}
/**
* Tests the getAliasByPath method for a path that is preloaded.
*
* @covers ::getAliasByPath
* @covers ::writeCache
*/
public function testGetAliasByPathCachedMatch() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$alias = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$cached_paths = [$language->getId() => [$path]];
$this->cache->expects($this->once())
->method('get')
->with($this->cacheKey)
->will($this->returnValue((object) ['data' => $cached_paths]));
// Simulate a request so that the preloaded paths are fetched.
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
$this->aliasRepository->expects($this->once())
->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$path => $alias]));
// LookupPathAlias should not be called.
$this->aliasRepository->expects($this->never())
->method('lookupBySystemPath');
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// This must not write to the cache again.
$this->cache->expects($this->never())
->method('set');
$this->aliasManager->writeCache();
}
/**
* Tests the getAliasByPath cache when a different language is requested.
*
* @covers ::getAliasByPath
* @covers ::writeCache
*/
public function testGetAliasByPathCachedMissLanguage() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$alias = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$cached_language = new Language(['id' => 'de']);
$cached_paths = [$cached_language->getId() => [$path]];
$this->cache->expects($this->once())
->method('get')
->with($this->cacheKey)
->will($this->returnValue((object) ['data' => $cached_paths]));
// Simulate a request so that the preloaded paths are fetched.
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
// The requested language is different than the cached, so this will
// need to load.
$this->aliasRepository->expects($this->never())
->method('preloadPathAlias');
$this->aliasRepository->expects($this->once())
->method('lookupBySystemPath')
->with($path, $language->getId())
->will($this->returnValue(['alias' => $alias]));
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path));
// There is already a cache entry, so this should not write out to the
// cache.
$this->cache->expects($this->never())
->method('set');
$this->aliasManager->writeCache();
}
/**
* Tests the getAliasByPath cache with a preloaded path without alias.
*
* @covers ::getAliasByPath
* @covers ::writeCache
*/
public function testGetAliasByPathCachedMissNoAlias() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$cached_path = $this->randomMachineName();
$cached_alias = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$cached_paths = [$language->getId() => [$cached_path, $path]];
$this->cache->expects($this->once())
->method('get')
->with($this->cacheKey)
->will($this->returnValue((object) ['data' => $cached_paths]));
// Simulate a request so that the preloaded paths are fetched.
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
$this->aliasRepository->expects($this->once())
->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$cached_path => $cached_alias]));
// LookupPathAlias() should not be called.
$this->aliasRepository->expects($this->never())
->method('lookupBySystemPath');
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// This must not write to the cache again.
$this->cache->expects($this->never())
->method('set');
$this->aliasManager->writeCache();
}
/**
* Tests the getAliasByPath cache with an unpreloaded path without alias.
*
* @covers ::getAliasByPath
* @covers ::writeCache
*/
public function testGetAliasByPathUncachedMissNoAlias() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$cached_path = $this->randomMachineName();
$cached_alias = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$cached_paths = [$language->getId() => [$cached_path]];
$this->cache->expects($this->once())
->method('get')
->with($this->cacheKey)
->will($this->returnValue((object) ['data' => $cached_paths]));
// Simulate a request so that the preloaded paths are fetched.
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
$this->aliasRepository->expects($this->once())
->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$cached_path => $cached_alias]));
$this->aliasRepository->expects($this->once())
->method('lookupBySystemPath')
->with($path, $language->getId())
->will($this->returnValue(NULL));
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($path, $this->aliasManager->getAliasByPath($path));
// There is already a cache entry, so this should not write out to the
// cache.
$this->cache->expects($this->never())
->method('set');
$this->aliasManager->writeCache();
}
/**
* @covers ::cacheClear
*/
public function testCacheClear() {
$path = '/path';
$alias = '/alias';
$language = $this->setUpCurrentLanguage();
$this->aliasRepository->expects($this->exactly(2))
->method('lookupBySystemPath')
->with($path, $language->getId())
->willReturn(['alias' => $alias]);
$this->aliasWhitelist->expects($this->any())
->method('get')
->willReturn(TRUE);
// Populate the lookup map.
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path, $language->getId()));
// Check that the cache is populated.
$this->aliasRepository->expects($this->never())
->method('lookupByAlias');
$this->assertEquals($path, $this->aliasManager->getPathByAlias($alias, $language->getId()));
// Clear specific source.
$this->cache->expects($this->exactly(2))
->method('delete');
$this->aliasManager->cacheClear($path);
// Ensure cache has been cleared (this will be the 2nd call to
// `lookupPathAlias` if cache is cleared).
$this->assertEquals($alias, $this->aliasManager->getAliasByPath($path, $language->getId()));
// Clear non-existent source.
$this->aliasManager->cacheClear('non-existent');
}
/**
* Tests the getAliasByPath cache with an unpreloaded path with alias.
*
* @covers ::getAliasByPath
* @covers ::writeCache
*/
public function testGetAliasByPathUncachedMissWithAlias() {
$path_part1 = $this->randomMachineName();
$path_part2 = $this->randomMachineName();
$path = '/' . $path_part1 . '/' . $path_part2;
$cached_path = $this->randomMachineName();
$cached_no_alias_path = $this->randomMachineName();
$cached_alias = $this->randomMachineName();
$new_alias = $this->randomMachineName();
$language = $this->setUpCurrentLanguage();
$cached_paths = [$language->getId() => [$cached_path, $cached_no_alias_path]];
$this->cache->expects($this->once())
->method('get')
->with($this->cacheKey)
->will($this->returnValue((object) ['data' => $cached_paths]));
// Simulate a request so that the preloaded paths are fetched.
$this->aliasManager->setCacheKey($this->path);
$this->aliasWhitelist->expects($this->any())
->method('get')
->with($path_part1)
->will($this->returnValue(TRUE));
$this->aliasRepository->expects($this->once())
->method('preloadPathAlias')
->with($cached_paths[$language->getId()], $language->getId())
->will($this->returnValue([$cached_path => $cached_alias]));
$this->aliasRepository->expects($this->once())
->method('lookupBySystemPath')
->with($path, $language->getId())
->will($this->returnValue(['alias' => $new_alias]));
$this->assertEquals($new_alias, $this->aliasManager->getAliasByPath($path));
// Call it twice to test the static cache.
$this->assertEquals($new_alias, $this->aliasManager->getAliasByPath($path));
// There is already a cache entry, so this should not write out to the
// cache.
$this->cache->expects($this->never())
->method('set');
$this->aliasManager->writeCache();
}
/**
* Sets up the current language.
*
* @return \Drupal\Core\Language\LanguageInterface
* The current language object.
*/
protected function setUpCurrentLanguage() {
$language = new Language(['id' => 'en']);
$this->languageManager->expects($this->any())
->method('getCurrentLanguage')
->with(LanguageInterface::TYPE_URL)
->will($this->returnValue($language));
return $language;
}
}
@@ -0,0 +1,235 @@
<?php
namespace Drupal\Tests\path_alias\Unit;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\EventSubscriber\PathSubscriber;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Path\AliasManager as CoreAliasManager;
use Drupal\Core\Path\AliasManagerInterface as CoreAliasManagerInterface;
use Drupal\Core\Path\AliasWhitelist as CoreAliasWhitelist;
use Drupal\Core\Path\CurrentPathStack;
use Drupal\Core\PathProcessor\PathProcessorAlias;
use Drupal\Core\State\StateInterface;
use Drupal\path_alias\AliasManager;
use Drupal\path_alias\AliasManagerInterface;
use Drupal\path_alias\AliasRepositoryInterface;
use Drupal\path_alias\AliasWhitelist;
use Drupal\path_alias\AliasWhitelistInterface;
use Drupal\path_alias\EventSubscriber\PathAliasSubscriber;
use Drupal\path_alias\PathProcessor\AliasPathProcessor;
use Drupal\system\Form\SiteInformationForm;
use Drupal\system\Plugin\Condition\RequestPath;
use Drupal\Tests\UnitTestCase;
use Drupal\views\Plugin\views\argument_default\Raw;
/**
* Tests deprecation of path alias core service classes.
*
* @group path_alias
* @group legacy
*/
class DeprecatedClassesTest extends UnitTestCase {
/**
* @var \Drupal\path_alias\AliasManagerInterface
*/
protected $aliasManager;
/**
* @var \Drupal\path_alias\AliasRepositoryInterface
*/
protected $aliasRepository;
/**
* @var \Drupal\path_alias\AliasWhitelistInterface
*/
protected $aliasWhitelist;
/**
* @var \Drupal\Core\Cache\CacheBackendInterface
*/
protected $cache;
/**
* @var \Drupal\Core\Path\CurrentPathStack
*/
protected $currentPathStack;
/**
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lock;
/**
* @var \Drupal\Core\State\StateInterface
*/
protected $state;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->aliasManager = $this->prophesize(AliasManagerInterface::class)
->reveal();
$this->aliasRepository = $this->prophesize(AliasRepositoryInterface::class)
->reveal();
$this->aliasWhitelist = $this->prophesize(AliasWhitelistInterface::class)
->reveal();
$this->cache = $this->prophesize(CacheBackendInterface::class)
->reveal();
$this->currentPathStack = $this->prophesize(CurrentPathStack::class)
->reveal();
$this->languageManager = $this->prophesize(LanguageManagerInterface::class)
->reveal();
$this->lock = $this->prophesize(LockBackendInterface::class)
->reveal();
$this->state = $this->prophesize(StateInterface::class)
->reveal();
/** @var \Prophecy\Prophecy\ObjectProphecy $container */
$container = $this->prophesize(ContainerBuilder::class);
$container->get('path_alias.manager')
->willReturn($this->aliasManager);
\Drupal::setContainer($container->reveal());
}
/**
* @covers \Drupal\Core\EventSubscriber\PathSubscriber::__construct
*
* @expectedDeprecation The \Drupal\Core\EventSubscriber\PathSubscriber class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\EventSubscriber\PathAliasSubscriber. See https://drupal.org/node/3092086
*/
public function testPathSubscriber() {
new PathSubscriber($this->aliasManager, $this->currentPathStack);
}
/**
* @covers \Drupal\path_alias\EventSubscriber\PathAliasSubscriber::__construct
*/
public function testPathAliasSubscriber() {
$object = new PathAliasSubscriber($this->aliasManager, $this->currentPathStack);
$this->assertInstanceOf(PathSubscriber::class, $object);
}
/**
* @covers \Drupal\Core\PathProcessor\PathProcessorAlias::__construct
*
* @expectedDeprecation The \Drupal\Core\PathProcessor\PathProcessorAlias class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\PathProcessor\AliasPathProcessor. See https://drupal.org/node/3092086
*/
public function testPathProcessorAlias() {
new PathProcessorAlias($this->aliasManager);
}
/**
* @covers \Drupal\path_alias\PathProcessor\AliasPathProcessor::__construct
*/
public function testAliasPathProcessor() {
$object = new AliasPathProcessor($this->aliasManager);
$this->assertInstanceOf(PathProcessorAlias::class, $object);
}
/**
* @covers \Drupal\Core\Path\AliasManager::__construct
*
* @expectedDeprecation The \Drupal\Core\Path\AliasManager class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManager. See https://drupal.org/node/3092086
*/
public function testCoreAliasManager() {
new CoreAliasManager($this->aliasRepository, $this->aliasWhitelist, $this->languageManager, $this->cache);
}
/**
* @covers \Drupal\path_alias\AliasManager::__construct
*/
public function testAliasManager() {
$object = new AliasManager($this->aliasRepository, $this->aliasWhitelist, $this->languageManager, $this->cache);
$this->assertInstanceOf(CoreAliasManager::class, $object);
}
/**
* @covers \Drupal\Core\Path\AliasWhitelist::__construct
*
* @expectedDeprecation The \Drupal\Core\Path\AliasWhitelist class is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasWhitelist. See https://drupal.org/node/3092086
*/
public function testCoreAliasWhitelist() {
new CoreAliasWhitelist('path_alias_whitelist', $this->cache, $this->lock, $this->state, $this->aliasRepository);
}
/**
* @covers \Drupal\path_alias\AliasWhitelist::__construct
*/
public function testAliasWhitelist() {
$object = new AliasWhitelist('path_alias_whitelist', $this->cache, $this->lock, $this->state, $this->aliasRepository);
$this->assertInstanceOf(CoreAliasWhitelist::class, $object);
}
/**
* @covers \Drupal\system\Form\SiteInformationForm::__construct
*
* @expectedDeprecation Calling \Drupal\system\Form\SiteInformationForm::__construct with \Drupal\Core\Path\AliasManagerInterface instead of \Drupal\path_alias\AliasManagerInterface is deprecated in drupal:8.8.0. The new service will be required in drupal:9.0.0. See https://www.drupal.org/node/3092086
*/
public function testDeprecatedSystemInformationFormConstructorParameters() {
$this->assertDeprecatedConstructorParameter(SiteInformationForm::class);
}
/**
* @covers \Drupal\system\Plugin\Condition\RequestPath::__construct
*
* @expectedDeprecation Calling \Drupal\system\Plugin\Condition\RequestPath::__construct with \Drupal\Core\Path\AliasManagerInterface instead of \Drupal\path_alias\AliasManagerInterface is deprecated in drupal:8.8.0. The new service will be required in drupal:9.0.0. See https://www.drupal.org/node/3092086
*/
public function testDeprecatedRequestPathConstructorParameters() {
$this->assertDeprecatedConstructorParameter(RequestPath::class);
}
/**
* @covers \Drupal\views\Plugin\views\argument_default\Raw::__construct
*
* @expectedDeprecation Calling \Drupal\views\Plugin\views\argument_default\Raw::__construct with \Drupal\Core\Path\AliasManagerInterface instead of \Drupal\path_alias\AliasManagerInterface is deprecated in drupal:8.8.0. The new service will be required in drupal:9.0.0. See https://www.drupal.org/node/3092086
*/
public function testDeprecatedRawConstructorParameters() {
$this->assertDeprecatedConstructorParameter(Raw::class);
}
/**
* Test that deprecation for the \Drupal\Core\Path\AliasManagerInterface.
*
* @param string $tested_class_name
* The name of the tested class.
*
* @dataProvider deprecatedConstructorParametersProvider
*
* @expectedDeprecation The \Drupal\Core\Path\AliasManagerInterface interface is deprecated in drupal:8.8.0 and is removed from drupal:9.0.0. Instead, use \Drupal\path_alias\AliasManagerInterface. See https://drupal.org/node/3092086
*/
public function assertDeprecatedConstructorParameter($tested_class_name) {
$tested_class = new \ReflectionClass($tested_class_name);
$parameters = $tested_class->getConstructor()
->getParameters();
$args = [];
foreach ($parameters as $parameter) {
$name = $parameter->getName();
if ($name === 'alias_manager') {
$class_name = CoreAliasManagerInterface::class;
}
else {
$type = $parameter->getType();
$class_name = $type ? (string) $type : NULL;
}
$args[$name] = isset($class_name) && $class_name !== 'array' ? $this->prophesize($class_name)->reveal() : [];
}
$instance = $tested_class->newInstanceArgs($args);
$property = $tested_class->getProperty('aliasManager');
$property->setAccessible(TRUE);
$this->assertInstanceOf(AliasManagerInterface::class, $property->getValue($instance));
}
}
@@ -0,0 +1,87 @@
<?php
namespace Drupal\Tests\path_alias\Unit\PathProcessor;
use Drupal\Core\Cache\Cache;
use Drupal\path_alias\PathProcessor\AliasPathProcessor;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
/**
* @coversDefaultClass \Drupal\path_alias\PathProcessor\AliasPathProcessor
* @group PathProcessor
* @group path_alias
*/
class AliasPathProcessorTest extends UnitTestCase {
/**
* The mocked alias manager.
*
* @var \Drupal\path_alias\AliasManagerInterface|\PHPUnit\Framework\MockObject\MockObject
*/
protected $aliasManager;
/**
* The tested path processor.
*
* @var \Drupal\path_alias\PathProcessor\AliasPathProcessor
*/
protected $pathProcessor;
protected function setUp() {
$this->aliasManager = $this->createMock('Drupal\path_alias\AliasManagerInterface');
$this->pathProcessor = new AliasPathProcessor($this->aliasManager);
}
/**
* Tests the processInbound method.
*
* @see \Drupal\path_alias\PathProcessor\AliasPathProcessor::processInbound
*/
public function testProcessInbound() {
$this->aliasManager->expects($this->exactly(2))
->method('getPathByAlias')
->will($this->returnValueMap([
['urlalias', NULL, 'internal-url'],
['url', NULL, 'url'],
]));
$request = Request::create('/urlalias');
$this->assertEquals('internal-url', $this->pathProcessor->processInbound('urlalias', $request));
$request = Request::create('/url');
$this->assertEquals('url', $this->pathProcessor->processInbound('url', $request));
}
/**
* @covers ::processOutbound
*
* @dataProvider providerTestProcessOutbound
*/
public function testProcessOutbound($path, array $options, $expected_path) {
$this->aliasManager->expects($this->any())
->method('getAliasByPath')
->will($this->returnValueMap([
['internal-url', NULL, 'urlalias'],
['url', NULL, 'url'],
]));
$bubbleable_metadata = new BubbleableMetadata();
$this->assertEquals($expected_path, $this->pathProcessor->processOutbound($path, $options, NULL, $bubbleable_metadata));
// Cacheability of paths replaced with path aliases is permanent.
// @todo https://www.drupal.org/node/2480077
$this->assertEquals((new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), $bubbleable_metadata);
}
/**
* @return array
*/
public function providerTestProcessOutbound() {
return [
['internal-url', [], 'urlalias'],
['internal-url', ['alias' => TRUE], 'internal-url'],
['url', [], 'url'],
];
}
}