Initial Drupal 11 with DDEV setup
This commit is contained in:
		
							
								
								
									
										7
									
								
								web/core/modules/path_alias/path_alias.info.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								web/core/modules/path_alias/path_alias.info.yml
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										25
									
								
								web/core/modules/path_alias/path_alias.post_update.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								web/core/modules/path_alias/path_alias.post_update.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Post update functions for Path Alias.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_removed_post_updates().
 | 
			
		||||
 */
 | 
			
		||||
function path_alias_removed_post_updates(): array {
 | 
			
		||||
  return [
 | 
			
		||||
    'path_alias_post_update_drop_path_alias_status_index' => '11.0.0',
 | 
			
		||||
  ];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Update the path_alias_revision indices.
 | 
			
		||||
 */
 | 
			
		||||
function path_alias_post_update_update_path_alias_revision_indexes(): void {
 | 
			
		||||
  /** @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface $update_manager */
 | 
			
		||||
  $update_manager = \Drupal::service('entity.definition_update_manager');
 | 
			
		||||
  $entity_type = $update_manager->getEntityType('path_alias');
 | 
			
		||||
  $update_manager->updateEntityType($entity_type);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										36
									
								
								web/core/modules/path_alias/path_alias.services.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								web/core/modules/path_alias/path_alias.services.yml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
services:
 | 
			
		||||
  _defaults:
 | 
			
		||||
    autoconfigure: true
 | 
			
		||||
  path_alias.subscriber:
 | 
			
		||||
    class: Drupal\path_alias\EventSubscriber\PathAliasSubscriber
 | 
			
		||||
    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.prefix_list', '@language_manager', '@cache.data', '@datetime.time']
 | 
			
		||||
  Drupal\path_alias\AliasManagerInterface: '@path_alias.manager'
 | 
			
		||||
  path_alias.repository:
 | 
			
		||||
    class: Drupal\path_alias\AliasRepository
 | 
			
		||||
    arguments: ['@database']
 | 
			
		||||
    tags:
 | 
			
		||||
      - { name: backend_overridable }
 | 
			
		||||
  Drupal\path_alias\AliasRepositoryInterface: '@path_alias.repository'
 | 
			
		||||
  # cspell:ignore whitelist
 | 
			
		||||
  path_alias.whitelist:
 | 
			
		||||
    class: Drupal\path_alias\AliasWhitelist
 | 
			
		||||
    tags:
 | 
			
		||||
      - { name: needs_destruction }
 | 
			
		||||
    arguments: [path_alias_whitelist, '@cache.bootstrap', '@lock', '@state', '@path_alias.repository']
 | 
			
		||||
    deprecated:  The "%service_id%" service is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Use the 'router.prefix_list' service instead. See https://www.drupal.org/node/3467559
 | 
			
		||||
  Drupal\path_alias\AliasWhitelistInterface: '@path_alias.whitelist'
 | 
			
		||||
  path_alias.prefix_list:
 | 
			
		||||
    class: Drupal\path_alias\AliasPrefixList
 | 
			
		||||
    tags:
 | 
			
		||||
      - { name: needs_destruction }
 | 
			
		||||
    arguments: [path_alias_prefix_list, '@cache.bootstrap', '@lock', '@state', '@path_alias.repository']
 | 
			
		||||
  Drupal\path_alias\AliasPrefixListInterface: '@path_alias.prefix_list'
 | 
			
		||||
							
								
								
									
										271
									
								
								web/core/modules/path_alias/src/AliasManager.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								web/core/modules/path_alias/src/AliasManager.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,271 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
use Drupal\Component\Datetime\TimeInterface;
 | 
			
		||||
use Drupal\Core\Cache\CacheBackendInterface;
 | 
			
		||||
use Drupal\Core\Language\LanguageInterface;
 | 
			
		||||
use Drupal\Core\Language\LanguageManagerInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The default alias manager implementation.
 | 
			
		||||
 */
 | 
			
		||||
class AliasManager implements AliasManagerInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The cache key to use when caching paths.
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $cacheKey;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Whether the cache needs to be written.
 | 
			
		||||
   *
 | 
			
		||||
   * @var bool
 | 
			
		||||
   */
 | 
			
		||||
  protected $cacheNeedsWriting = FALSE;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Holds the map of path lookups per language.
 | 
			
		||||
   *
 | 
			
		||||
   * @var array
 | 
			
		||||
   */
 | 
			
		||||
  protected $lookupMap = [];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Holds an array of aliases for which no path was found.
 | 
			
		||||
   *
 | 
			
		||||
   * @var array
 | 
			
		||||
   */
 | 
			
		||||
  protected $noPath = [];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Holds an array of paths that have no alias.
 | 
			
		||||
   *
 | 
			
		||||
   * @var array
 | 
			
		||||
   */
 | 
			
		||||
  protected $noAlias = [];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Whether preloaded path lookups has already been loaded.
 | 
			
		||||
   *
 | 
			
		||||
   * @var array
 | 
			
		||||
   */
 | 
			
		||||
  protected $langcodePreloaded = [];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Holds an array of previously looked up paths for the current request path.
 | 
			
		||||
   *
 | 
			
		||||
   * This will only get populated if a cache key has been set, which for example
 | 
			
		||||
   * happens if the alias manager is used in the context of a request.
 | 
			
		||||
   *
 | 
			
		||||
   * @var array
 | 
			
		||||
   */
 | 
			
		||||
  protected $preloadedPathLookups = FALSE;
 | 
			
		||||
 | 
			
		||||
  public function __construct(
 | 
			
		||||
    protected AliasRepositoryInterface $pathAliasRepository,
 | 
			
		||||
    protected AliasPrefixListInterface $pathPrefixes,
 | 
			
		||||
    protected LanguageManagerInterface $languageManager,
 | 
			
		||||
    protected CacheBackendInterface $cache,
 | 
			
		||||
    protected TimeInterface $time,
 | 
			
		||||
  ) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function setCacheKey($key) {
 | 
			
		||||
    // Prefix the cache key to avoid clashes with other caches.
 | 
			
		||||
    $this->cacheKey = 'preload-paths:' . $key;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   *
 | 
			
		||||
   * Cache an array of the paths available on each page. We assume that aliases
 | 
			
		||||
   * will be needed for the majority of these paths during subsequent requests,
 | 
			
		||||
   * and load them in a single query during path alias lookup.
 | 
			
		||||
   */
 | 
			
		||||
  public function writeCache() {
 | 
			
		||||
    // Check if the paths for this page were loaded from cache in this request
 | 
			
		||||
    // to avoid writing to cache on every request.
 | 
			
		||||
    if ($this->cacheNeedsWriting && !empty($this->cacheKey)) {
 | 
			
		||||
      // Start with the preloaded path lookups, so that cached entries for other
 | 
			
		||||
      // languages will not be lost.
 | 
			
		||||
      $path_lookups = $this->preloadedPathLookups ?: [];
 | 
			
		||||
      foreach ($this->lookupMap as $langcode => $lookups) {
 | 
			
		||||
        $path_lookups[$langcode] = array_keys($lookups);
 | 
			
		||||
        if (!empty($this->noAlias[$langcode])) {
 | 
			
		||||
          $path_lookups[$langcode] = array_merge($path_lookups[$langcode], array_keys($this->noAlias[$langcode]));
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $twenty_four_hours = 60 * 60 * 24;
 | 
			
		||||
      $this->cache->set($this->cacheKey, $path_lookups, $this->time->getRequestTime() + $twenty_four_hours);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function getPathByAlias($alias, $langcode = NULL) {
 | 
			
		||||
    // If no language is explicitly specified we default to the current URL
 | 
			
		||||
    // language. If we used a language different from the one conveyed by the
 | 
			
		||||
    // requested URL, we might end up being unable to check if there is a path
 | 
			
		||||
    // alias matching the URL path.
 | 
			
		||||
    $langcode = $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId();
 | 
			
		||||
 | 
			
		||||
    // If we already know that there are no paths for this alias simply return.
 | 
			
		||||
    if (empty($alias) || !empty($this->noPath[$langcode][$alias])) {
 | 
			
		||||
      return $alias;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Look for the alias within the cached map.
 | 
			
		||||
    if (isset($this->lookupMap[$langcode]) && ($path = array_search($alias, $this->lookupMap[$langcode]))) {
 | 
			
		||||
      return $path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Look for path in storage.
 | 
			
		||||
    if ($path_alias = $this->pathAliasRepository->lookupByAlias($alias, $langcode)) {
 | 
			
		||||
      $this->lookupMap[$langcode][$path_alias['path']] = $alias;
 | 
			
		||||
      return $path_alias['path'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We can't record anything into $this->lookupMap because we didn't find any
 | 
			
		||||
    // paths for this alias. Thus cache to $this->noPath.
 | 
			
		||||
    $this->noPath[$langcode][$alias] = TRUE;
 | 
			
		||||
 | 
			
		||||
    return $alias;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function getAliasByPath($path, $langcode = NULL) {
 | 
			
		||||
    if (!str_starts_with($path, '/')) {
 | 
			
		||||
      throw new \InvalidArgumentException(sprintf('Source path %s has to start with a slash.', $path));
 | 
			
		||||
    }
 | 
			
		||||
    // If no language is explicitly specified we default to the current URL
 | 
			
		||||
    // language. If we used a language different from the one conveyed by the
 | 
			
		||||
    // requested URL, we might end up being unable to check if there is a path
 | 
			
		||||
    // alias matching the URL path.
 | 
			
		||||
    $langcode = $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId();
 | 
			
		||||
 | 
			
		||||
    // Check the path prefix, if the top-level part before the first / is not in
 | 
			
		||||
    // the list, then there is no need to do anything further, it is not in the
 | 
			
		||||
    // database.
 | 
			
		||||
    if ($path === '/' || !$this->pathPrefixes->get(strtok(trim($path, '/'), '/'))) {
 | 
			
		||||
      return $path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // During the first call to this method per language, load the expected
 | 
			
		||||
    // paths for the page from cache.
 | 
			
		||||
    if (empty($this->langcodePreloaded[$langcode])) {
 | 
			
		||||
      $this->langcodePreloaded[$langcode] = TRUE;
 | 
			
		||||
      $this->lookupMap[$langcode] = [];
 | 
			
		||||
 | 
			
		||||
      // Load the cached paths that should be used for preloading. This only
 | 
			
		||||
      // happens if a cache key has been set.
 | 
			
		||||
      if ($this->preloadedPathLookups === FALSE) {
 | 
			
		||||
        $this->preloadedPathLookups = [];
 | 
			
		||||
        if ($this->cacheKey) {
 | 
			
		||||
          if ($cached = $this->cache->get($this->cacheKey)) {
 | 
			
		||||
            $this->preloadedPathLookups = $cached->data;
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            $this->cacheNeedsWriting = TRUE;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Load paths from cache.
 | 
			
		||||
      if (!empty($this->preloadedPathLookups[$langcode])) {
 | 
			
		||||
        $this->lookupMap[$langcode] = $this->pathAliasRepository->preloadPathAlias($this->preloadedPathLookups[$langcode], $langcode);
 | 
			
		||||
        // Keep a record of paths with no alias to avoid querying twice.
 | 
			
		||||
        $this->noAlias[$langcode] = array_flip(array_diff($this->preloadedPathLookups[$langcode], array_keys($this->lookupMap[$langcode])));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If we already know that there are no aliases for this path simply return.
 | 
			
		||||
    if (!empty($this->noAlias[$langcode][$path])) {
 | 
			
		||||
      return $path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If the alias has already been loaded, return it from static cache.
 | 
			
		||||
    if (isset($this->lookupMap[$langcode][$path])) {
 | 
			
		||||
      return $this->lookupMap[$langcode][$path];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Try to load alias from storage.
 | 
			
		||||
    if ($path_alias = $this->pathAliasRepository->lookupBySystemPath($path, $langcode)) {
 | 
			
		||||
      $this->lookupMap[$langcode][$path] = $path_alias['alias'];
 | 
			
		||||
      return $path_alias['alias'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We can't record anything into $this->lookupMap because we didn't find any
 | 
			
		||||
    // aliases for this path. Thus cache to $this->noAlias.
 | 
			
		||||
    $this->noAlias[$langcode][$path] = TRUE;
 | 
			
		||||
    return $path;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function cacheClear($source = NULL) {
 | 
			
		||||
    // Note this method does not flush the preloaded path lookup cache. This is
 | 
			
		||||
    // because if a path is missing from this cache, it still results in the
 | 
			
		||||
    // alias being loaded correctly, only less efficiently.
 | 
			
		||||
 | 
			
		||||
    if ($source) {
 | 
			
		||||
      foreach (array_keys($this->lookupMap) as $lang) {
 | 
			
		||||
        unset($this->lookupMap[$lang][$source]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      $this->lookupMap = [];
 | 
			
		||||
    }
 | 
			
		||||
    $this->noPath = [];
 | 
			
		||||
    $this->noAlias = [];
 | 
			
		||||
    $this->langcodePreloaded = [];
 | 
			
		||||
    $this->preloadedPathLookups = [];
 | 
			
		||||
    $this->pathAliasPrefixListRebuild($source);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Rebuild the path alias prefix list.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $path
 | 
			
		||||
   *   An optional path for which an alias is being inserted.
 | 
			
		||||
   */
 | 
			
		||||
  protected function pathAliasPrefixListRebuild($path = NULL) {
 | 
			
		||||
    // When paths are inserted, only rebuild the prefix list if the path has a
 | 
			
		||||
    // top level component which is not already in the prefix list.
 | 
			
		||||
    if (!empty($path)) {
 | 
			
		||||
      if ($this->pathPrefixes->get(strtok($path, '/'))) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $this->pathPrefixes->clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Rebuild the path alias prefix list.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $path
 | 
			
		||||
   *   An optional path for which an alias is being inserted.
 | 
			
		||||
   *
 | 
			
		||||
   * @deprecated in drupal:11.1.0 and is removed from drupal:12.0.0.
 | 
			
		||||
   *  Use \Drupal\path_alias\AliasManager::pathAliasPrefixListRebuild instead.
 | 
			
		||||
   *
 | 
			
		||||
   * @see https://www.drupal.org/node/3467559
 | 
			
		||||
   *
 | 
			
		||||
   * cspell:ignore whitelist
 | 
			
		||||
   */
 | 
			
		||||
  protected function pathAliasWhitelistRebuild($path = NULL) {
 | 
			
		||||
    @trigger_error(__METHOD__ . '() is deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Use \Drupal\path_alias\AliasManager::pathAliasPrefixListRebuild() instead. See https://www.drupal.org/node/3467559', E_USER_DEPRECATED);
 | 
			
		||||
    $this->pathAliasPrefixListRebuild($path);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								web/core/modules/path_alias/src/AliasManagerInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								web/core/modules/path_alias/src/AliasManagerInterface.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Find an alias for a path and vice versa.
 | 
			
		||||
 *
 | 
			
		||||
 * @see \Drupal\path_alias\AliasStorageInterface
 | 
			
		||||
 */
 | 
			
		||||
interface AliasManagerInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Given the alias, return the path it represents.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $alias
 | 
			
		||||
   *   An alias.
 | 
			
		||||
   * @param string $langcode
 | 
			
		||||
   *   An optional language code to look up the path in.
 | 
			
		||||
   *
 | 
			
		||||
   * @return string
 | 
			
		||||
   *   The path represented by alias, or the alias if no path was found.
 | 
			
		||||
   *
 | 
			
		||||
   * @throws \InvalidArgumentException
 | 
			
		||||
   *   Thrown when the path does not start with a slash.
 | 
			
		||||
   */
 | 
			
		||||
  public function getPathByAlias($alias, $langcode = NULL);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Given a path, return the alias.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $path
 | 
			
		||||
   *   A path.
 | 
			
		||||
   * @param string $langcode
 | 
			
		||||
   *   An optional language code to look up the path in.
 | 
			
		||||
   *
 | 
			
		||||
   * @return string
 | 
			
		||||
   *   An alias that represents the path, or path if no alias was found.
 | 
			
		||||
   *
 | 
			
		||||
   * @throws \InvalidArgumentException
 | 
			
		||||
   *   Thrown when the path does not start with a slash.
 | 
			
		||||
   */
 | 
			
		||||
  public function getAliasByPath($path, $langcode = NULL);
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Clears the static caches in alias manager and rebuilds the prefix list.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string|null $source
 | 
			
		||||
   *   Source path of the alias that is being inserted/updated. If omitted, the
 | 
			
		||||
   *   entire lookup static cache will be cleared and the prefix list will be
 | 
			
		||||
   *   rebuilt.
 | 
			
		||||
   */
 | 
			
		||||
  public function cacheClear($source = NULL);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								web/core/modules/path_alias/src/AliasPrefixList.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								web/core/modules/path_alias/src/AliasPrefixList.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Cache\CacheBackendInterface;
 | 
			
		||||
use Drupal\Core\Cache\CacheCollector;
 | 
			
		||||
use Drupal\Core\Lock\LockBackendInterface;
 | 
			
		||||
use Drupal\Core\State\StateInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cache a list of valid alias prefixes.
 | 
			
		||||
 */
 | 
			
		||||
class AliasPrefixList extends CacheCollector implements AliasPrefixListInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The Key/Value Store to use for state.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\State\StateInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $state;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The path alias repository.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\path_alias\AliasRepositoryInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $pathAliasRepository;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Constructs an AliasPrefixList object.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $cid
 | 
			
		||||
   *   The cache id to use.
 | 
			
		||||
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
 | 
			
		||||
   *   The cache backend.
 | 
			
		||||
   * @param \Drupal\Core\Lock\LockBackendInterface $lock
 | 
			
		||||
   *   The lock backend.
 | 
			
		||||
   * @param \Drupal\Core\State\StateInterface $state
 | 
			
		||||
   *   The state keyvalue store.
 | 
			
		||||
   * @param \Drupal\path_alias\AliasRepositoryInterface $alias_repository
 | 
			
		||||
   *   The path alias repository.
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct($cid, CacheBackendInterface $cache, LockBackendInterface $lock, StateInterface $state, AliasRepositoryInterface $alias_repository) {
 | 
			
		||||
    parent::__construct($cid, $cache, $lock);
 | 
			
		||||
    $this->state = $state;
 | 
			
		||||
    $this->pathAliasRepository = $alias_repository;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function lazyLoadCache() {
 | 
			
		||||
    parent::lazyLoadCache();
 | 
			
		||||
 | 
			
		||||
    // On a cold start $this->storage will be empty and the prefix list will
 | 
			
		||||
    // need to be rebuilt from scratch. The prefix list is initialized from the
 | 
			
		||||
    // list of all valid path roots stored in the 'router.path_roots' state,
 | 
			
		||||
    // with values initialized to NULL. During the request, each path requested
 | 
			
		||||
    // that matches one of these keys will be looked up and the array value set
 | 
			
		||||
    // to either TRUE or FALSE. This ensures that paths which do not exist in
 | 
			
		||||
    // the router are not looked up, and that paths that do exist in the router
 | 
			
		||||
    // are only looked up once.
 | 
			
		||||
    if (empty($this->storage)) {
 | 
			
		||||
      $this->loadMenuPathRoots();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Loads menu path roots to prepopulate cache.
 | 
			
		||||
   */
 | 
			
		||||
  protected function loadMenuPathRoots() {
 | 
			
		||||
    if ($roots = $this->state->get('router.path_roots')) {
 | 
			
		||||
      foreach ($roots as $root) {
 | 
			
		||||
        $this->storage[$root] = NULL;
 | 
			
		||||
        $this->persist($root);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function get($offset) {
 | 
			
		||||
    $this->lazyLoadCache();
 | 
			
		||||
    // This may be called with paths that are not represented by menu router
 | 
			
		||||
    // items such as paths that will be rewritten by hook_url_outbound_alter().
 | 
			
		||||
    // Therefore internally TRUE is used to indicate valid paths. FALSE is
 | 
			
		||||
    // used to indicate paths that have already been checked but are not
 | 
			
		||||
    // valid, and NULL indicates paths that have not been checked yet.
 | 
			
		||||
    if (isset($this->storage[$offset])) {
 | 
			
		||||
      if ($this->storage[$offset]) {
 | 
			
		||||
        return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    elseif (array_key_exists($offset, $this->storage)) {
 | 
			
		||||
      return $this->resolveCacheMiss($offset);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function resolveCacheMiss($root) {
 | 
			
		||||
    $exists = $this->pathAliasRepository->pathHasMatchingAlias('/' . $root);
 | 
			
		||||
    $this->storage[$root] = $exists;
 | 
			
		||||
    $this->persist($root);
 | 
			
		||||
    if ($exists) {
 | 
			
		||||
      return TRUE;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function clear() {
 | 
			
		||||
    parent::clear();
 | 
			
		||||
    $this->loadMenuPathRoots();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								web/core/modules/path_alias/src/AliasPrefixListInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								web/core/modules/path_alias/src/AliasPrefixListInterface.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Cache\CacheCollectorInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cache a list of valid alias prefixes.
 | 
			
		||||
 *
 | 
			
		||||
 * The list 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 prefix list.
 | 
			
		||||
 * This optimization allows skipping the lookup for every /user/{user} path if
 | 
			
		||||
 * "user" is not in the list.
 | 
			
		||||
 */
 | 
			
		||||
interface AliasPrefixListInterface extends CacheCollectorInterface {}
 | 
			
		||||
							
								
								
									
										151
									
								
								web/core/modules/path_alias/src/AliasRepository.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								web/core/modules/path_alias/src/AliasRepository.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Database\Connection;
 | 
			
		||||
use Drupal\Core\Database\Query\SelectInterface;
 | 
			
		||||
use Drupal\Core\Database\Statement\FetchAs;
 | 
			
		||||
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 = $this->connection->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);
 | 
			
		||||
 | 
			
		||||
    $select->orderBy('base_table.id', 'DESC');
 | 
			
		||||
 | 
			
		||||
    // We want the most recently created alias for each source, however that
 | 
			
		||||
    // will be at the start of the result-set, so fetch everything and reverse
 | 
			
		||||
    // it. Note that it would not be sufficient to reverse the ordering of the
 | 
			
		||||
    // 'base_table.id' column, as that would not guarantee other conditions
 | 
			
		||||
    // added to the query, such as those in ::addLanguageFallback, would be
 | 
			
		||||
    // reversed.
 | 
			
		||||
    $results = $select->execute()->fetchAll(FetchAs::Associative);
 | 
			
		||||
    $aliases = [];
 | 
			
		||||
    foreach (array_reverse($results) as $result) {
 | 
			
		||||
      $aliases[$result['path']] = $result['alias'];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $aliases;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@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');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										81
									
								
								web/core/modules/path_alias/src/AliasRepositoryInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								web/core/modules/path_alias/src/AliasRepositoryInterface.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,81 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								web/core/modules/path_alias/src/AliasWhitelist.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								web/core/modules/path_alias/src/AliasWhitelist.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
// cspell:ignore whitelist
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cache a list of valid alias prefixes.
 | 
			
		||||
 *
 | 
			
		||||
 * @deprecated in drupal:11.1.0 and is removed from drupal:12.0.0. Use
 | 
			
		||||
 * \Drupal\path_alias\AliasPrefixList instead.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://www.drupal.org/node/3467559
 | 
			
		||||
 */
 | 
			
		||||
class AliasWhitelist extends AliasPrefixList {}
 | 
			
		||||
							
								
								
									
										15
									
								
								web/core/modules/path_alias/src/AliasWhitelistInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								web/core/modules/path_alias/src/AliasWhitelistInterface.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
// cspell:ignore whitelist
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Cache a list of valid alias prefixes.
 | 
			
		||||
 *
 | 
			
		||||
 * @deprecated in drupal:11.1.0 and is removed from drupal:12.0.0.
 | 
			
		||||
 * Use \Drupal\path_alias\AliasPrefixListInterface instead.
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://www.drupal.org/node/3467559
 | 
			
		||||
 */
 | 
			
		||||
interface AliasWhitelistInterface extends AliasPrefixListInterface {}
 | 
			
		||||
							
								
								
									
										174
									
								
								web/core/modules/path_alias/src/Entity/PathAlias.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								web/core/modules/path_alias/src/Entity/PathAlias.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,174 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias\Entity;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Entity\Attribute\ContentEntityType;
 | 
			
		||||
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;
 | 
			
		||||
use Drupal\path_alias\PathAliasStorage;
 | 
			
		||||
use Drupal\path_alias\PathAliasStorageSchema;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Defines the path_alias entity class.
 | 
			
		||||
 */
 | 
			
		||||
#[ContentEntityType(
 | 
			
		||||
  id: 'path_alias',
 | 
			
		||||
  label: new TranslatableMarkup('URL alias'),
 | 
			
		||||
  label_collection: new TranslatableMarkup('URL aliases'),
 | 
			
		||||
  label_singular: new TranslatableMarkup('URL alias'),
 | 
			
		||||
  label_plural: new TranslatableMarkup('URL aliases'),
 | 
			
		||||
  entity_keys: [
 | 
			
		||||
    'id' => 'id',
 | 
			
		||||
    'revision' => 'revision_id',
 | 
			
		||||
    'langcode' => 'langcode',
 | 
			
		||||
    'uuid' => 'uuid',
 | 
			
		||||
    'published' => 'status',
 | 
			
		||||
  ],
 | 
			
		||||
  handlers: [
 | 
			
		||||
    'storage' => PathAliasStorage::class,
 | 
			
		||||
    'storage_schema' => PathAliasStorageSchema::class,
 | 
			
		||||
  ],
 | 
			
		||||
  admin_permission: 'administer url aliases',
 | 
			
		||||
  base_table: 'path_alias',
 | 
			
		||||
  revision_table: 'path_alias_revision',
 | 
			
		||||
  label_count: [
 | 
			
		||||
    'singular' => '@count URL alias',
 | 
			
		||||
    'plural' => '@count 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->getOriginal()->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,78 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias\EventSubscriber;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Path\CurrentPathStack;
 | 
			
		||||
use Drupal\path_alias\AliasManagerInterface;
 | 
			
		||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 | 
			
		||||
use Symfony\Component\HttpKernel\KernelEvents;
 | 
			
		||||
use Symfony\Component\HttpKernel\Event\ControllerEvent;
 | 
			
		||||
use Symfony\Component\HttpKernel\Event\TerminateEvent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides a path subscriber that converts path aliases.
 | 
			
		||||
 */
 | 
			
		||||
class PathAliasSubscriber implements EventSubscriberInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The alias manager that caches alias lookups based on the request.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\path_alias\AliasManagerInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $aliasManager;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * The current path.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\Core\Path\CurrentPathStack
 | 
			
		||||
   */
 | 
			
		||||
  protected $currentPath;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Constructs a new PathSubscriber instance.
 | 
			
		||||
   *
 | 
			
		||||
   * @param \Drupal\path_alias\AliasManagerInterface $alias_manager
 | 
			
		||||
   *   The alias manager.
 | 
			
		||||
   * @param \Drupal\Core\Path\CurrentPathStack $current_path
 | 
			
		||||
   *   The current path.
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct(AliasManagerInterface $alias_manager, CurrentPathStack $current_path) {
 | 
			
		||||
    $this->aliasManager = $alias_manager;
 | 
			
		||||
    $this->currentPath = $current_path;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sets the cache key on the alias manager cache decorator.
 | 
			
		||||
   *
 | 
			
		||||
   * KernelEvents::CONTROLLER is used in order to be executed after routing.
 | 
			
		||||
   *
 | 
			
		||||
   * @param \Symfony\Component\HttpKernel\Event\ControllerEvent $event
 | 
			
		||||
   *   The Event to process.
 | 
			
		||||
   */
 | 
			
		||||
  public function onKernelController(ControllerEvent $event) {
 | 
			
		||||
    // Set the cache key on the alias manager cache decorator.
 | 
			
		||||
    if ($event->isMainRequest()) {
 | 
			
		||||
      $this->aliasManager->setCacheKey(rtrim($this->currentPath->getPath($event->getRequest()), '/'));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Ensures system paths for the request get cached.
 | 
			
		||||
   */
 | 
			
		||||
  public function onKernelTerminate(TerminateEvent $event) {
 | 
			
		||||
    $this->aliasManager->writeCache();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Registers the methods in this class that should be listeners.
 | 
			
		||||
   *
 | 
			
		||||
   * @return array
 | 
			
		||||
   *   An array of event listener definitions.
 | 
			
		||||
   */
 | 
			
		||||
  public static function getSubscribedEvents(): array {
 | 
			
		||||
    $events[KernelEvents::CONTROLLER][] = ['onKernelController', 200];
 | 
			
		||||
    $events[KernelEvents::TERMINATE][] = ['onKernelTerminate', 200];
 | 
			
		||||
    return $events;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								web/core/modules/path_alias/src/PathAliasInterface.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								web/core/modules/path_alias/src/PathAliasInterface.php
									
									
									
									
									
										Normal file
									
								
							@ -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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								web/core/modules/path_alias/src/PathAliasStorage.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								web/core/modules/path_alias/src/PathAliasStorage.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Defines the storage handler class for path_alias entities.
 | 
			
		||||
 */
 | 
			
		||||
class PathAliasStorage extends SqlContentEntityStorage {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								web/core/modules/path_alias/src/PathAliasStorageSchema.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								web/core/modules/path_alias/src/PathAliasStorageSchema.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
<?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);
 | 
			
		||||
    $base_table = $this->storage->getBaseTable();
 | 
			
		||||
    $revision_table = $this->storage->getRevisionTable();
 | 
			
		||||
 | 
			
		||||
    $schema[$base_table]['indexes'] += [
 | 
			
		||||
      'path_alias__alias_langcode_id_status' => ['alias', 'langcode', 'id', 'status'],
 | 
			
		||||
      'path_alias__path_langcode_id_status' => ['path', 'langcode', 'id', 'status'],
 | 
			
		||||
    ];
 | 
			
		||||
    $schema[$revision_table]['indexes'] += [
 | 
			
		||||
      'path_alias_revision__alias_langcode_id_status' => ['alias', 'langcode', 'id', 'status'],
 | 
			
		||||
      'path_alias_revision__path_langcode_id_status' => ['path', 'langcode', 'id', 'status'],
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    // Unset the path_alias__status index as it is slower than the above
 | 
			
		||||
    // indexes and MySQL 5.7 chooses to use it even though it is suboptimal.
 | 
			
		||||
    unset($schema[$base_table]['indexes']['path_alias__status']);
 | 
			
		||||
 | 
			
		||||
    return $schema;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,61 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace Drupal\path_alias\PathProcessor;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
 | 
			
		||||
use Drupal\Core\PathProcessor\OutboundPathProcessorInterface;
 | 
			
		||||
use Drupal\Core\Render\BubbleableMetadata;
 | 
			
		||||
use Drupal\path_alias\AliasManagerInterface;
 | 
			
		||||
use Symfony\Component\HttpFoundation\Request;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Processes the inbound and outbound path using path alias lookups.
 | 
			
		||||
 */
 | 
			
		||||
class AliasPathProcessor implements InboundPathProcessorInterface, OutboundPathProcessorInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * An alias manager for looking up the system path.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\path_alias\AliasManagerInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $aliasManager;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Constructs a AliasPathProcessor object.
 | 
			
		||||
   *
 | 
			
		||||
   * @param \Drupal\path_alias\AliasManagerInterface $alias_manager
 | 
			
		||||
   *   An alias manager for looking up the system path.
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct(AliasManagerInterface $alias_manager) {
 | 
			
		||||
    $this->aliasManager = $alias_manager;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function processInbound($path, Request $request) {
 | 
			
		||||
    $path = $this->aliasManager->getPathByAlias($path);
 | 
			
		||||
    return $path;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function processOutbound($path, &$options = [], ?Request $request = NULL, ?BubbleableMetadata $bubbleable_metadata = NULL) {
 | 
			
		||||
    if (empty($options['alias'])) {
 | 
			
		||||
      $langcode = isset($options['language']) ? $options['language']->getId() : NULL;
 | 
			
		||||
      $path = $this->aliasManager->getAliasByPath($path, $langcode);
 | 
			
		||||
      // Ensure the resulting path has at most one leading slash, to prevent it
 | 
			
		||||
      // becoming an external URL without a protocol like //example.com. This
 | 
			
		||||
      // is done in \Drupal\Core\Routing\UrlGenerator::generateFromRoute()
 | 
			
		||||
      // also, to protect against this problem in arbitrary path processors,
 | 
			
		||||
      // but it is duplicated here to protect any other URL generation code
 | 
			
		||||
      // that might call this method separately.
 | 
			
		||||
      if (str_starts_with($path, '//')) {
 | 
			
		||||
        $path = '/' . ltrim($path, '/');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return $path;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,14 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Tests\system\Functional\Module\GenericModuleTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generic module test for path_alias.
 | 
			
		||||
 *
 | 
			
		||||
 * @group path_alias
 | 
			
		||||
 */
 | 
			
		||||
class GenericTest extends GenericModuleTestBase {}
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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,43 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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}
 | 
			
		||||
   */
 | 
			
		||||
  protected 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,38 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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,121 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Functional\Rest;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Language\LanguageInterface;
 | 
			
		||||
use Drupal\path_alias\Entity\PathAlias;
 | 
			
		||||
use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Base class for path_alias EntityResource tests.
 | 
			
		||||
 */
 | 
			
		||||
abstract class PathAliasResourceTestBase extends EntityResourceTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['path', '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',
 | 
			
		||||
        ],
 | 
			
		||||
      ],
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,35 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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,45 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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}
 | 
			
		||||
   */
 | 
			
		||||
  protected 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,40 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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,40 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Functional\Update;
 | 
			
		||||
 | 
			
		||||
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the update path for the path_alias_revision table indices.
 | 
			
		||||
 *
 | 
			
		||||
 * @group path_alias
 | 
			
		||||
 */
 | 
			
		||||
class PathAliasRevisionIndexesUpdatePathTest extends UpdatePathTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setDatabaseDumpFiles(): void {
 | 
			
		||||
    $this->databaseDumpFiles = [
 | 
			
		||||
      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-10.3.0.bare.standard.php.gz',
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the update path for the path_alias_revision table indices.
 | 
			
		||||
   */
 | 
			
		||||
  public function testRunUpdates(): void {
 | 
			
		||||
    $schema = \Drupal::database()->schema();
 | 
			
		||||
 | 
			
		||||
    $this->assertFalse($schema->indexExists('path_alias_revision', 'path_alias_revision__alias_langcode_id_status'));
 | 
			
		||||
    $this->assertFalse($schema->indexExists('path_alias_revision', 'path_alias_revision__path_langcode_id_status'));
 | 
			
		||||
 | 
			
		||||
    $this->runUpdates();
 | 
			
		||||
 | 
			
		||||
    $this->assertTrue($schema->indexExists('path_alias_revision', 'path_alias_revision__alias_langcode_id_status'));
 | 
			
		||||
    $this->assertTrue($schema->indexExists('path_alias_revision', 'path_alias_revision__path_langcode_id_status'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,107 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Functional;
 | 
			
		||||
 | 
			
		||||
use Drupal\Core\Database\Database;
 | 
			
		||||
use Drupal\Core\Url;
 | 
			
		||||
use Drupal\Tests\BrowserTestBase;
 | 
			
		||||
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests altering the inbound path and the outbound path.
 | 
			
		||||
 *
 | 
			
		||||
 * @group path_alias
 | 
			
		||||
 */
 | 
			
		||||
class UrlAlterFunctionalTest extends BrowserTestBase {
 | 
			
		||||
 | 
			
		||||
  use PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['path', 'url_alter_test'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected $defaultTheme = 'stark';
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that URL altering works and that it occurs in the correct order.
 | 
			
		||||
   */
 | 
			
		||||
  public function testUrlAlter(): void {
 | 
			
		||||
    // 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'], "it's+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->drupalGet('admin/config/search/path/add');
 | 
			
		||||
    $this->submitForm($edit, 'Save');
 | 
			
		||||
    $this->assertSession()->pageTextContains('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 outbound query string altering.
 | 
			
		||||
    $url = Url::fromRoute('user.login');
 | 
			
		||||
    $this->assertSame(\Drupal::request()->getBaseUrl() . '/user/login?foo=bar', $url->toString());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Assert that an outbound path is altered to an expected value.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $original
 | 
			
		||||
   *   A string with the original path that is run through generateFrommPath().
 | 
			
		||||
   * @param string $final
 | 
			
		||||
   *   A string with the expected result after generateFrommPath().
 | 
			
		||||
   *
 | 
			
		||||
   * @internal
 | 
			
		||||
   */
 | 
			
		||||
  protected function assertUrlOutboundAlter(string $original, string $final): void {
 | 
			
		||||
    // Test outbound altering.
 | 
			
		||||
    $result = $this->container->get('path_processor_manager')->processOutbound($original);
 | 
			
		||||
    $this->assertSame($final, $result, "Altered outbound URL $original, expected $final, and got $result.");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Assert that an inbound path is altered to an expected value.
 | 
			
		||||
   *
 | 
			
		||||
   * @param string $original
 | 
			
		||||
   *   The original path before it has been altered by inbound URL processing.
 | 
			
		||||
   * @param string $final
 | 
			
		||||
   *   A string with the expected result.
 | 
			
		||||
   *
 | 
			
		||||
   * @internal
 | 
			
		||||
   */
 | 
			
		||||
  protected function assertUrlInboundAlter(string $original, string $final): void {
 | 
			
		||||
    // Test inbound altering.
 | 
			
		||||
    $result = $this->container->get('path_alias.manager')->getPathByAlias($original);
 | 
			
		||||
    $this->assertSame($final, $result, "Altered inbound URL $original, expected $final, and got $result.");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										472
									
								
								web/core/modules/path_alias/tests/src/Kernel/AliasTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										472
									
								
								web/core/modules/path_alias/tests/src/Kernel/AliasTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,472 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\Component\Datetime\TimeInterface;
 | 
			
		||||
use Drupal\Core\Cache\MemoryCounterBackend;
 | 
			
		||||
use Drupal\Core\Language\LanguageInterface;
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
use Drupal\path_alias\AliasManager;
 | 
			
		||||
use Drupal\path_alias\AliasPrefixList;
 | 
			
		||||
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(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    // The alias prefix list 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 ::preloadPathAlias
 | 
			
		||||
   */
 | 
			
		||||
  public function testPreloadPathAlias(): void {
 | 
			
		||||
    $path_alias_repository = $this->container->get('path_alias.repository');
 | 
			
		||||
 | 
			
		||||
    // Every interesting language combination:
 | 
			
		||||
    // Just unspecified.
 | 
			
		||||
    $this->createPathAlias('/und/src', '/und/alias', LanguageInterface::LANGCODE_NOT_SPECIFIED);
 | 
			
		||||
    // Just a single language.
 | 
			
		||||
    $this->createPathAlias('/en/src', '/en/alias', 'en');
 | 
			
		||||
    // A single language, plus unspecified.
 | 
			
		||||
    $this->createPathAlias('/en-und/src', '/en-und/und', LanguageInterface::LANGCODE_NOT_SPECIFIED);
 | 
			
		||||
    $this->createPathAlias('/en-und/src', '/en-und/en', 'en');
 | 
			
		||||
    // Multiple languages.
 | 
			
		||||
    $this->createPathAlias('/en-xx-lolspeak/src', '/en-xx-lolspeak/en', 'en');
 | 
			
		||||
    $this->createPathAlias('/en-xx-lolspeak/src', '/en-xx-lolspeak/xx-lolspeak', 'xx-lolspeak');
 | 
			
		||||
    // A duplicate alias for the same path. This is later, so should be
 | 
			
		||||
    // preferred.
 | 
			
		||||
    $this->createPathAlias('/en-xx-lolspeak/src', '/en-xx-lolspeak/en-dup', 'en');
 | 
			
		||||
    // Multiple languages, plus unspecified.
 | 
			
		||||
    $this->createPathAlias('/en-xx-lolspeak-und/src', '/en-xx-lolspeak-und/und', LanguageInterface::LANGCODE_NOT_SPECIFIED);
 | 
			
		||||
    $this->createPathAlias('/en-xx-lolspeak-und/src', '/en-xx-lolspeak-und/en', 'en');
 | 
			
		||||
    $this->createPathAlias('/en-xx-lolspeak-und/src', '/en-xx-lolspeak-und/xx-lolspeak', 'xx-lolspeak');
 | 
			
		||||
 | 
			
		||||
    // Queries for unspecified language aliases.
 | 
			
		||||
    // Ask for an empty array, get all results.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-und/src' => '/en-und/und',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias([], LanguageInterface::LANGCODE_NOT_SPECIFIED)
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for nonexistent source.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/nonexistent'], LanguageInterface::LANGCODE_NOT_SPECIFIED));
 | 
			
		||||
    // Ask for each saved source, individually.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/und/src' => '/und/alias'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/und/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-und/src' => '/en-und/und'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-und/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak-und/src'], LanguageInterface::LANGCODE_NOT_SPECIFIED)
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for multiple sources, all that are known.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-und/src' => '/en-und/und',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(
 | 
			
		||||
        [
 | 
			
		||||
          '/nonexistent',
 | 
			
		||||
          '/und/src',
 | 
			
		||||
          '/en/src',
 | 
			
		||||
          '/en-und/src',
 | 
			
		||||
          '/en-xx-lolspeak/src',
 | 
			
		||||
          '/en-xx-lolspeak-und/src',
 | 
			
		||||
        ],
 | 
			
		||||
        LanguageInterface::LANGCODE_NOT_SPECIFIED
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for multiple sources, just a subset.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/und',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(
 | 
			
		||||
        [
 | 
			
		||||
          '/und/src',
 | 
			
		||||
          '/en-xx-lolspeak/src',
 | 
			
		||||
          '/en-xx-lolspeak-und/src',
 | 
			
		||||
        ],
 | 
			
		||||
        LanguageInterface::LANGCODE_NOT_SPECIFIED
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Queries for English aliases.
 | 
			
		||||
    // Ask for an empty array, get all results.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en/src' => '/en/alias',
 | 
			
		||||
        '/en-und/src' => '/en-und/en',
 | 
			
		||||
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias([], 'en')
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for nonexistent source.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/nonexistent'], 'en'));
 | 
			
		||||
    // Ask for each saved source, individually.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/und/src' => '/und/alias'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/und/src'], 'en')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en/src' => '/en/alias'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en/src'], 'en')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-und/src' => '/en-und/en'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-und/src'], 'en')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak/src'], 'en')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak-und/src'], 'en')
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for multiple sources, all that are known.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en/src' => '/en/alias',
 | 
			
		||||
        '/en-und/src' => '/en-und/en',
 | 
			
		||||
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(
 | 
			
		||||
        [
 | 
			
		||||
          '/nonexistent',
 | 
			
		||||
          '/und/src',
 | 
			
		||||
          '/en/src',
 | 
			
		||||
          '/en-und/src',
 | 
			
		||||
          '/en-xx-lolspeak/src',
 | 
			
		||||
          '/en-xx-lolspeak-und/src',
 | 
			
		||||
        ],
 | 
			
		||||
        'en'
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for multiple sources, just a subset.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/en-dup',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/en',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(
 | 
			
		||||
        [
 | 
			
		||||
          '/und/src',
 | 
			
		||||
          '/en-xx-lolspeak/src',
 | 
			
		||||
          '/en-xx-lolspeak-und/src',
 | 
			
		||||
        ],
 | 
			
		||||
        'en'
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // Queries for xx-lolspeak aliases.
 | 
			
		||||
    // Ask for an empty array, get all results.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-und/src' => '/en-und/und',
 | 
			
		||||
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias([], 'xx-lolspeak')
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for nonexistent source.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/nonexistent'], 'xx-lolspeak'));
 | 
			
		||||
    // Ask for each saved source, individually.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/und/src' => '/und/alias'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/und/src'], 'xx-lolspeak')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en/src'], 'xx-lolspeak')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-und/src' => '/en-und/und'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-und/src'], 'xx-lolspeak')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak/src'], 'xx-lolspeak')
 | 
			
		||||
    );
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      ['/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak'],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(['/en-xx-lolspeak-und/src'], 'xx-lolspeak')
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for multiple sources, all that are known.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-und/src' => '/en-und/und',
 | 
			
		||||
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(
 | 
			
		||||
        [
 | 
			
		||||
          '/nonexistent',
 | 
			
		||||
          '/und/src',
 | 
			
		||||
          '/en/src',
 | 
			
		||||
          '/en-und/src',
 | 
			
		||||
          '/en-xx-lolspeak/src',
 | 
			
		||||
          '/en-xx-lolspeak-und/src',
 | 
			
		||||
        ],
 | 
			
		||||
        'xx-lolspeak'
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
    // Ask for multiple sources, just a subset.
 | 
			
		||||
    $this->assertEquals(
 | 
			
		||||
      [
 | 
			
		||||
        '/und/src' => '/und/alias',
 | 
			
		||||
        '/en-xx-lolspeak/src' => '/en-xx-lolspeak/xx-lolspeak',
 | 
			
		||||
        '/en-xx-lolspeak-und/src' => '/en-xx-lolspeak-und/xx-lolspeak',
 | 
			
		||||
      ],
 | 
			
		||||
      $path_alias_repository->preloadPathAlias(
 | 
			
		||||
        [
 | 
			
		||||
          '/und/src',
 | 
			
		||||
          '/en-xx-lolspeak/src',
 | 
			
		||||
          '/en-xx-lolspeak-und/src',
 | 
			
		||||
        ],
 | 
			
		||||
        'xx-lolspeak'
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * @covers ::lookupBySystemPath
 | 
			
		||||
   */
 | 
			
		||||
  public function testLookupBySystemPath(): void {
 | 
			
		||||
    $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(): void {
 | 
			
		||||
    $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(): void {
 | 
			
		||||
    // 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 prefix.
 | 
			
		||||
   */
 | 
			
		||||
  public function testPrefixList(): void {
 | 
			
		||||
    $memoryCounterBackend = new MemoryCounterBackend(\Drupal::service(TimeInterface::class));
 | 
			
		||||
 | 
			
		||||
    // Create AliasManager and Path object.
 | 
			
		||||
    $prefix_list = new AliasPrefixList('path_alias_prefix_list', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
 | 
			
		||||
    $aliasManager = new AliasManager($this->container->get('path_alias.repository'), $prefix_list, $this->container->get('language_manager'), $memoryCounterBackend, $this->container->get(TimeInterface::class));
 | 
			
		||||
 | 
			
		||||
    // No alias for user and admin yet, so should be NULL.
 | 
			
		||||
    $this->assertNull($prefix_list->get('user'));
 | 
			
		||||
    $this->assertNull($prefix_list->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($prefix_list->get($this->randomMachineName()));
 | 
			
		||||
 | 
			
		||||
    // Add an alias for user/1, user should get cached now.
 | 
			
		||||
    $this->createPathAlias('/user/1', '/' . $this->randomMachineName());
 | 
			
		||||
    $aliasManager->cacheClear();
 | 
			
		||||
    $this->assertTrue($prefix_list->get('user'));
 | 
			
		||||
    $this->assertNull($prefix_list->get('admin'));
 | 
			
		||||
    $this->assertNull($prefix_list->get($this->randomMachineName()));
 | 
			
		||||
 | 
			
		||||
    // Add an alias for admin, both should get cached now.
 | 
			
		||||
    $this->createPathAlias('/admin/something', '/' . $this->randomMachineName());
 | 
			
		||||
    $aliasManager->cacheClear();
 | 
			
		||||
    $this->assertTrue($prefix_list->get('user'));
 | 
			
		||||
    $this->assertTrue($prefix_list->get('admin'));
 | 
			
		||||
    $this->assertNull($prefix_list->get($this->randomMachineName()));
 | 
			
		||||
 | 
			
		||||
    // Remove the user alias again, prefix list 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($prefix_list->get('user'));
 | 
			
		||||
    $this->assertTrue($prefix_list->get('admin'));
 | 
			
		||||
    $this->assertNull($prefix_list->get($this->randomMachineName()));
 | 
			
		||||
 | 
			
		||||
    // Destruct the prefix list so that the caches are written.
 | 
			
		||||
    $prefix_list->destruct();
 | 
			
		||||
    $this->assertEquals(1, $memoryCounterBackend->getCounter('set', 'path_alias_prefix_list'));
 | 
			
		||||
    $memoryCounterBackend->resetCounter();
 | 
			
		||||
 | 
			
		||||
    // Re-initialize the prefix list using the same cache backend, should load
 | 
			
		||||
    // from cache.
 | 
			
		||||
    $prefix_list = new AliasPrefixList('path_alias_prefix_list', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
 | 
			
		||||
    $this->assertNull($prefix_list->get('user'));
 | 
			
		||||
    $this->assertTrue($prefix_list->get('admin'));
 | 
			
		||||
    $this->assertNull($prefix_list->get($this->randomMachineName()));
 | 
			
		||||
    $this->assertEquals(1, $memoryCounterBackend->getCounter('get', 'path_alias_prefix_list'));
 | 
			
		||||
    $this->assertEquals(0, $memoryCounterBackend->getCounter('set', 'path_alias_prefix_list'));
 | 
			
		||||
 | 
			
		||||
    // Destruct the prefix list, should not attempt to write the cache again.
 | 
			
		||||
    $prefix_list->destruct();
 | 
			
		||||
    $this->assertEquals(1, $memoryCounterBackend->getCounter('get', 'path_alias_prefix_list'));
 | 
			
		||||
    $this->assertEquals(0, $memoryCounterBackend->getCounter('set', 'path_alias_prefix_list'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests situation where the prefix list  cache is deleted mid-request.
 | 
			
		||||
   */
 | 
			
		||||
  public function testPrefixListCacheDeletionMidRequest() {
 | 
			
		||||
    $memoryCounterBackend = new MemoryCounterBackend(\Drupal::service(TimeInterface::class));
 | 
			
		||||
 | 
			
		||||
    // Create AliasManager and Path object.
 | 
			
		||||
    $prefix_list = new AliasPrefixList('path_alias_prefix_list', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
 | 
			
		||||
 | 
			
		||||
    // Prefix list cache should not exist at all yet.
 | 
			
		||||
    $this->assertFalse($memoryCounterBackend->get('path_alias_prefix_list'));
 | 
			
		||||
 | 
			
		||||
    // 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 prefix list. It will query the DB and figure out
 | 
			
		||||
    // that it indeed has an alias, and add it to the internal prefix list and
 | 
			
		||||
    // flag it to be persisted to cache.
 | 
			
		||||
    $this->assertTrue($prefix_list->get('admin'));
 | 
			
		||||
 | 
			
		||||
    // Destruct the prefix list so it persists its cache.
 | 
			
		||||
    $prefix_list->destruct();
 | 
			
		||||
    $this->assertEquals(1, $memoryCounterBackend->getCounter('set', 'path_alias_prefix_list'));
 | 
			
		||||
    // 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_prefix_list')->data);
 | 
			
		||||
    $memoryCounterBackend->resetCounter();
 | 
			
		||||
 | 
			
		||||
    // Re-initialize the prefix list and lookup an alias for the 'user' path.
 | 
			
		||||
    // Prefix list 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.
 | 
			
		||||
    $prefix_list = new AliasPrefixList('path_alias_prefix_list', $memoryCounterBackend, $this->container->get('lock'), $this->container->get('state'), $this->container->get('path_alias.repository'));
 | 
			
		||||
    $this->assertTrue($prefix_list->get('user'));
 | 
			
		||||
 | 
			
		||||
    // Delete the prefix list cache. This could happen from an outside process,
 | 
			
		||||
    // like a code deployment that performs a cache rebuild.
 | 
			
		||||
    $memoryCounterBackend->delete('path_alias_prefix_list');
 | 
			
		||||
 | 
			
		||||
    // Destruct prefix list so it attempts to save the prefix list 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.
 | 
			
		||||
    $prefix_list->destruct();
 | 
			
		||||
    $this->assertEquals(0, $memoryCounterBackend->getCounter('set', 'path_alias_prefix_list'));
 | 
			
		||||
    $this->assertFalse($memoryCounterBackend->get('path_alias_prefix_list'));
 | 
			
		||||
    $memoryCounterBackend->resetCounter();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\entity_test\Entity\EntityTest;
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
use Drupal\Tests\Traits\Core\PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests path alias on entities.
 | 
			
		||||
 *
 | 
			
		||||
 * @group path_alias
 | 
			
		||||
 */
 | 
			
		||||
class EntityAliasTest extends KernelTestBase {
 | 
			
		||||
 | 
			
		||||
  use PathAliasTestTrait;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = [
 | 
			
		||||
    'path_alias',
 | 
			
		||||
    'entity_test',
 | 
			
		||||
    'user',
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    $this->installEntitySchema('entity_test');
 | 
			
		||||
    $this->installEntitySchema('path_alias');
 | 
			
		||||
    $this->installEntitySchema('user');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests transform.
 | 
			
		||||
   */
 | 
			
		||||
  public function testEntityAlias(): void {
 | 
			
		||||
    EntityTest::create(['id' => 1])->save();
 | 
			
		||||
    $this->createPathAlias('/entity_test/1', '/entity-alias');
 | 
			
		||||
    $entity = EntityTest::load(1);
 | 
			
		||||
    $this->assertSame('/entity-alias', $entity->toUrl()->toString());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,44 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Kernel;
 | 
			
		||||
 | 
			
		||||
use Drupal\KernelTests\KernelTestBase;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests the path_alias storage schema.
 | 
			
		||||
 *
 | 
			
		||||
 * @coversDefaultClass \Drupal\path_alias\PathAliasStorageSchema
 | 
			
		||||
 *
 | 
			
		||||
 * @group path_alias
 | 
			
		||||
 */
 | 
			
		||||
class PathAliasStorageSchemaTest extends KernelTestBase {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['path_alias'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
    $this->installEntitySchema('path_alias');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that the path_alias__status index is removed.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getEntitySchema
 | 
			
		||||
   */
 | 
			
		||||
  public function testPathAliasStatusIndexRemoved(): void {
 | 
			
		||||
    $schema = \Drupal::database()->schema();
 | 
			
		||||
    $table_name = 'path_alias';
 | 
			
		||||
    $this->assertTrue($schema->indexExists($table_name, 'path_alias__alias_langcode_id_status'));
 | 
			
		||||
    $this->assertTrue($schema->indexExists($table_name, 'path_alias__path_langcode_id_status'));
 | 
			
		||||
    $this->assertFalse($schema->indexExists($table_name, 'path_alias__status'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,73 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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}
 | 
			
		||||
   */
 | 
			
		||||
  protected static $modules = ['path_alias'];
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->installEntitySchema('path_alias');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests that the PathAlias entity clears caches correctly.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::postSave
 | 
			
		||||
   * @covers ::postDelete
 | 
			
		||||
   */
 | 
			
		||||
  public function testPathHooks(): void {
 | 
			
		||||
    $path_alias = PathAlias::create([
 | 
			
		||||
      'path' => '/' . $this->randomMachineName(),
 | 
			
		||||
      'alias' => '/' . $this->randomMachineName(),
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    // Check \Drupal\path_alias\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\path_alias\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\path_alias\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();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										565
									
								
								web/core/modules/path_alias/tests/src/Unit/AliasManagerTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										565
									
								
								web/core/modules/path_alias/tests/src/Unit/AliasManagerTest.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,565 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Drupal\Tests\path_alias\Unit;
 | 
			
		||||
 | 
			
		||||
use Drupal\Component\Datetime\Time;
 | 
			
		||||
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 repository.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\path_alias\AliasRepositoryInterface|\PHPUnit\Framework\MockObject\MockObject
 | 
			
		||||
   */
 | 
			
		||||
  protected $aliasRepository;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Alias prefix list.
 | 
			
		||||
   *
 | 
			
		||||
   * @var \Drupal\path_alias\AliasPrefixListInterface|\PHPUnit\Framework\MockObject\MockObject
 | 
			
		||||
   */
 | 
			
		||||
  protected $aliasPrefixList;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 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(): void {
 | 
			
		||||
    parent::setUp();
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository = $this->createMock(AliasRepositoryInterface::class);
 | 
			
		||||
    $this->aliasPrefixList = $this->createMock('Drupal\path_alias\AliasPrefixListInterface');
 | 
			
		||||
    $this->languageManager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
 | 
			
		||||
    $this->cache = $this->createMock('Drupal\Core\Cache\CacheBackendInterface');
 | 
			
		||||
 | 
			
		||||
    $this->aliasManager = new AliasManager($this->aliasRepository, $this->aliasPrefixList, $this->languageManager, $this->cache, new Time());
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the getPathByAlias method for an alias that have no matching path.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getPathByAlias
 | 
			
		||||
   */
 | 
			
		||||
  public function testGetPathByAliasNoMatch(): void {
 | 
			
		||||
    $alias = '/' . $this->randomMachineName();
 | 
			
		||||
 | 
			
		||||
    $language = new Language(['id' => 'en']);
 | 
			
		||||
 | 
			
		||||
    $this->languageManager->expects($this->any())
 | 
			
		||||
      ->method('getCurrentLanguage')
 | 
			
		||||
      ->with(LanguageInterface::TYPE_URL)
 | 
			
		||||
      ->willReturn($language);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupByAlias')
 | 
			
		||||
      ->with($alias, $language->getId())
 | 
			
		||||
      ->willReturn(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 testGetPathByAliasMatch(): void {
 | 
			
		||||
    $alias = $this->randomMachineName();
 | 
			
		||||
    $path = $this->randomMachineName();
 | 
			
		||||
 | 
			
		||||
    $language = $this->setUpCurrentLanguage();
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupByAlias')
 | 
			
		||||
      ->with($alias, $language->getId())
 | 
			
		||||
      ->willReturn(['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(): void {
 | 
			
		||||
    $alias = $this->randomMachineName();
 | 
			
		||||
    $path = $this->randomMachineName();
 | 
			
		||||
 | 
			
		||||
    $this->languageManager->expects($this->never())
 | 
			
		||||
      ->method('getCurrentLanguage');
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupByAlias')
 | 
			
		||||
      ->with($alias, 'de')
 | 
			
		||||
      ->willReturn(['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 prefix list.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getAliasByPath
 | 
			
		||||
   */
 | 
			
		||||
  public function testGetAliasByPathPrefixList() {
 | 
			
		||||
    $path_part1 = $this->randomMachineName();
 | 
			
		||||
    $path_part2 = $this->randomMachineName();
 | 
			
		||||
    $path = '/' . $path_part1 . '/' . $path_part2;
 | 
			
		||||
 | 
			
		||||
    $this->setUpCurrentLanguage();
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(FALSE);
 | 
			
		||||
 | 
			
		||||
    // The prefix list 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(): void {
 | 
			
		||||
    $path_part1 = $this->randomMachineName();
 | 
			
		||||
    $path_part2 = $this->randomMachineName();
 | 
			
		||||
    $path = '/' . $path_part1 . '/' . $path_part2;
 | 
			
		||||
 | 
			
		||||
    $language = $this->setUpCurrentLanguage();
 | 
			
		||||
 | 
			
		||||
    $this->aliasManager->setCacheKey($this->path);
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(TRUE);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupBySystemPath')
 | 
			
		||||
      ->with($path, $language->getId())
 | 
			
		||||
      ->willReturn(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 exception.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getAliasByPath
 | 
			
		||||
   */
 | 
			
		||||
  public function testGetAliasByPathException(): void {
 | 
			
		||||
    $this->expectException(\InvalidArgumentException::class);
 | 
			
		||||
    $this->aliasManager->getAliasByPath('no-leading-slash-here');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Tests the getAliasByPath method for a path that has a matching alias.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getAliasByPath
 | 
			
		||||
   * @covers ::writeCache
 | 
			
		||||
   */
 | 
			
		||||
  public function testGetAliasByPathMatch(): void {
 | 
			
		||||
    $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->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(TRUE);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupBySystemPath')
 | 
			
		||||
      ->with($path, $language->getId())
 | 
			
		||||
      ->willReturn(['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(): void {
 | 
			
		||||
    $path_part1 = $this->randomMachineName();
 | 
			
		||||
    $path_part2 = $this->randomMachineName();
 | 
			
		||||
    $path = '/' . $path_part1 . '/' . $path_part2;
 | 
			
		||||
    $alias = $this->randomMachineName();
 | 
			
		||||
 | 
			
		||||
    $language = $this->setUpCurrentLanguage();
 | 
			
		||||
 | 
			
		||||
    // Use a set of cached paths where the tested path is in any position, not
 | 
			
		||||
    // only in the first one.
 | 
			
		||||
    $cached_paths = [
 | 
			
		||||
      $language->getId() => [
 | 
			
		||||
        '/another/path',
 | 
			
		||||
        $path,
 | 
			
		||||
      ],
 | 
			
		||||
    ];
 | 
			
		||||
    $this->cache->expects($this->once())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($this->cacheKey)
 | 
			
		||||
      ->willReturn((object) ['data' => $cached_paths]);
 | 
			
		||||
 | 
			
		||||
    // Simulate a request so that the preloaded paths are fetched.
 | 
			
		||||
    $this->aliasManager->setCacheKey($this->path);
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(TRUE);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('preloadPathAlias')
 | 
			
		||||
      ->with($cached_paths[$language->getId()], $language->getId())
 | 
			
		||||
      ->willReturn([$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(): void {
 | 
			
		||||
    $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)
 | 
			
		||||
      ->willReturn((object) ['data' => $cached_paths]);
 | 
			
		||||
 | 
			
		||||
    // Simulate a request so that the preloaded paths are fetched.
 | 
			
		||||
    $this->aliasManager->setCacheKey($this->path);
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(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())
 | 
			
		||||
      ->willReturn(['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(): void {
 | 
			
		||||
    $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)
 | 
			
		||||
      ->willReturn((object) ['data' => $cached_paths]);
 | 
			
		||||
 | 
			
		||||
    // Simulate a request so that the preloaded paths are fetched.
 | 
			
		||||
    $this->aliasManager->setCacheKey($this->path);
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(TRUE);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('preloadPathAlias')
 | 
			
		||||
      ->with($cached_paths[$language->getId()], $language->getId())
 | 
			
		||||
      ->willReturn([$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 un-preloaded path without alias.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getAliasByPath
 | 
			
		||||
   * @covers ::writeCache
 | 
			
		||||
   */
 | 
			
		||||
  public function testGetAliasByPathUncachedMissNoAlias(): void {
 | 
			
		||||
    $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)
 | 
			
		||||
      ->willReturn((object) ['data' => $cached_paths]);
 | 
			
		||||
 | 
			
		||||
    // Simulate a request so that the preloaded paths are fetched.
 | 
			
		||||
    $this->aliasManager->setCacheKey($this->path);
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(TRUE);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('preloadPathAlias')
 | 
			
		||||
      ->with($cached_paths[$language->getId()], $language->getId())
 | 
			
		||||
      ->willReturn([$cached_path => $cached_alias]);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupBySystemPath')
 | 
			
		||||
      ->with($path, $language->getId())
 | 
			
		||||
      ->willReturn(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(): void {
 | 
			
		||||
    $path = '/path';
 | 
			
		||||
    $alias = '/alias';
 | 
			
		||||
    $language = $this->setUpCurrentLanguage();
 | 
			
		||||
    $this->aliasRepository->expects($this->exactly(2))
 | 
			
		||||
      ->method('lookupBySystemPath')
 | 
			
		||||
      ->with($path, $language->getId())
 | 
			
		||||
      ->willReturn(['alias' => $alias]);
 | 
			
		||||
    $this->aliasPrefixList->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->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 un-preloaded path with alias.
 | 
			
		||||
   *
 | 
			
		||||
   * @covers ::getAliasByPath
 | 
			
		||||
   * @covers ::writeCache
 | 
			
		||||
   */
 | 
			
		||||
  public function testGetAliasByPathUncachedMissWithAlias(): void {
 | 
			
		||||
    $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)
 | 
			
		||||
      ->willReturn((object) ['data' => $cached_paths]);
 | 
			
		||||
 | 
			
		||||
    // Simulate a request so that the preloaded paths are fetched.
 | 
			
		||||
    $this->aliasManager->setCacheKey($this->path);
 | 
			
		||||
 | 
			
		||||
    $this->aliasPrefixList->expects($this->any())
 | 
			
		||||
      ->method('get')
 | 
			
		||||
      ->with($path_part1)
 | 
			
		||||
      ->willReturn(TRUE);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('preloadPathAlias')
 | 
			
		||||
      ->with($cached_paths[$language->getId()], $language->getId())
 | 
			
		||||
      ->willReturn([$cached_path => $cached_alias]);
 | 
			
		||||
 | 
			
		||||
    $this->aliasRepository->expects($this->once())
 | 
			
		||||
      ->method('lookupBySystemPath')
 | 
			
		||||
      ->with($path, $language->getId())
 | 
			
		||||
      ->willReturn(['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)
 | 
			
		||||
      ->willReturn($language);
 | 
			
		||||
 | 
			
		||||
    return $language;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,97 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function setUp(): void {
 | 
			
		||||
    parent::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(): void {
 | 
			
		||||
    $this->aliasManager->expects($this->exactly(2))
 | 
			
		||||
      ->method('getPathByAlias')
 | 
			
		||||
      ->willReturnMap([
 | 
			
		||||
        ['url-alias', NULL, 'internal-url'],
 | 
			
		||||
        ['url', NULL, 'url'],
 | 
			
		||||
      ]);
 | 
			
		||||
 | 
			
		||||
    $request = Request::create('/url-alias');
 | 
			
		||||
    $this->assertEquals('internal-url', $this->pathProcessor->processInbound('url-alias', $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): void {
 | 
			
		||||
    $this->aliasManager->expects($this->any())
 | 
			
		||||
      ->method('getAliasByPath')
 | 
			
		||||
      ->willReturnMap([
 | 
			
		||||
        ['internal-url', NULL, 'url-alias'],
 | 
			
		||||
        ['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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Provides data for testing outbound processing.
 | 
			
		||||
   *
 | 
			
		||||
   * @return array
 | 
			
		||||
   *   The data provider for testProcessOutbound.
 | 
			
		||||
   */
 | 
			
		||||
  public static function providerTestProcessOutbound() {
 | 
			
		||||
    return [
 | 
			
		||||
      ['internal-url', [], 'url-alias'],
 | 
			
		||||
      ['internal-url', ['alias' => TRUE], 'internal-url'],
 | 
			
		||||
      ['url', [], 'url'],
 | 
			
		||||
    ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user