fixed_path_alias-8.x-1.0-beta2/src/FixedPathAliasManager.php
src/FixedPathAliasManager.php
<?php
namespace Drupal\fixed_path_alias;
use Drupal\Core\CacheDecorator\CacheDecoratorInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\path_alias\AliasManagerInterface;
use Drupal\path_alias\AliasRepositoryInterface;
use Psr\Log\LoggerInterface;
/**
* Fixed path alias manager decorator. Wraps the alias manager.
*/
class FixedPathAliasManager implements AliasManagerInterface, CacheDecoratorInterface {
use StringTranslationTrait;
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* The wrapped alias manager.
*
* @var \Drupal\path_alias\AliasManagerInterface
*/
protected $aliasManager;
/**
* The alias storage service.
*
* @var \Drupal\path_alias\AliasRepositoryInterface
*/
protected $aliasRepository;
/**
* The language manager.
*
* @var \Drupal\Core\Language\LanguageManagerInterface
*/
protected $languageManager;
/**
* The fixed aliases config.
*
* @var \Drupal\Core\Config\Config
*/
protected $config;
/**
* The channel logger.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* 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 = [];
/**
* Constructs an FixedPathAliasManager.
*
* @param \Drupal\path_alias\AliasManagerInterface $alias_manager
* The alias manager that this class decorates.
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
* The entity type manager.
* @param \Drupal\path_alias\AliasRepositoryInterface $alias_repository
* The alias storage service.
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
* The language manager.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param \Psr\Log\LoggerInterface $logger
* The logger channel.
*/
public function __construct(AliasManagerInterface $alias_manager, EntityTypeManagerInterface $entity_type_manager, AliasRepositoryInterface $alias_repository, LanguageManagerInterface $language_manager, ConfigFactoryInterface $config_factory, LoggerInterface $logger) {
$this->aliasManager = $alias_manager;
$this->entityTypeManager = $entity_type_manager;
$this->aliasRepository = $alias_repository;
$this->languageManager = $language_manager;
$this->config = $config_factory->get('fixed_path_alias.aliases');
$this->logger = $logger;
}
/**
* {@inheritdoc}
*/
public function getPathByAlias($alias, $langcode = NULL) {
$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;
}
// Search the path in the wrapped alias manager.
$path = $this->aliasManager->getPathByAlias($alias, $langcode);
// If not found, try to look up within the fixed path aliases.
if ($path !== $alias
|| $path = $this->lookupFixedPath($alias, $langcode, TRUE)) {
return $path;
}
// Not found, cache in no path aliases.
$this->noPath[$langcode][$alias] = TRUE;
return $alias;
}
/**
* {@inheritdoc}
*/
public function getAliasByPath($path, $langcode = NULL) {
$langcode = $langcode ?: $this->languageManager->getCurrentLanguage(LanguageInterface::TYPE_URL)->getId();
// If we already know that there are no aliases for this path simply return.
if (!empty($this->noAlias[$langcode][$path])) {
return $path;
}
$alias = $this->aliasManager->getAliasByPath($path, $langcode);
// Alias not found by the wrapped alias manager, look up in fixed aliases.
if ($alias !== $path
|| $alias = $this->lookupFixedAlias($path, $langcode, TRUE)) {
return $alias;
}
// Not found, cache in no alias paths.
$this->noAlias[$langcode][$path] = TRUE;
return $path;
}
/**
* Resolves a source URL from a given path within the fixed path aliases.
*
* @param string $alias
* The path alias to look up.
* @param string $langcode
* The language.
* @param bool $restore
* (optional) Restore the regular path alias from the fixed one if found.
*
* @return string|false
* The source URL for the given alias, FALSE if not found.
*/
protected function lookupFixedPath($alias, $langcode, $restore = FALSE) {
$fixed_aliases = $this->config->get('aliases') ?: [];
// Find a match in the fixed aliases for the given alias.
foreach ($fixed_aliases as $fixed_alias) {
if ($alias == $fixed_alias['alias']
&& ($fixed_alias['langcode'] == $langcode || $fixed_alias['langcode'] == LanguageInterface::LANGCODE_NOT_SPECIFIED)) {
// Restore the path alias.
if ($restore) {
$this->restoreAlias($fixed_alias);
}
return $fixed_alias['source'];
}
}
return FALSE;
}
/**
* Resolves an alias from a given path within the fixed path aliases.
*
* @param string $path
* The path to look up.
* @param string $langcode
* The language.
* @param bool $restore
* (optional) Restore the regular path alias from the fixed one if found.
*
* @return string|false
* The alias for the given path, FALSE if not found.
*/
protected function lookupFixedAlias($path, $langcode, $restore = FALSE) {
$fixed_aliases = $this->config->get('aliases') ?: [];
// Find a match in the fixed aliases for the given path.
foreach ($fixed_aliases as $fixed_alias) {
if ($path == $fixed_alias['source']
&& ($fixed_alias['langcode'] == $langcode || $fixed_alias['langcode'] == LanguageInterface::LANGCODE_NOT_SPECIFIED)) {
// Restore the path alias.
if ($restore) {
$this->restoreAlias($fixed_alias);
}
return $fixed_alias['alias'];
}
}
return FALSE;
}
/**
* Restores an alias into database from a fixed alias config entry.
*
* @param array $fixed_alias
* A keyed array with the fixed alias config entry.
*/
protected function restoreAlias(array $fixed_alias) {
$new_alias = $this->getPathAliasEntityStorage()->create([
'path' => $fixed_alias['source'],
'alias' => $fixed_alias['alias'],
'langcode' => $fixed_alias['langcode'],
]);
if ($new_alias->save()) {
// Log the event.
$edit_link = $new_alias->toLink($this->t('Edit'), 'edit-form')->toString();
$this->logger->notice('Path alias %alias restored from config.', [
'%alias' => $fixed_alias['alias'],
'link' => $edit_link,
]);
}
}
/**
* {@inheritdoc}
*/
public function cacheClear($source = NULL) {
$this->aliasManager->cacheClear($source);
$this->noPath = [];
$this->noAlias = [];
}
/**
* {@inheritdoc}
*/
public function setCacheKey($key) {
if ($this->aliasManager instanceof CacheDecoratorInterface) {
$this->aliasManager->setCacheKey($key);
}
}
/**
* {@inheritdoc}
*/
public function writeCache() {
if ($this->aliasManager instanceof CacheDecoratorInterface) {
$this->aliasManager->writeCache();
}
}
/**
* Returns the path alias entity storage handler.
*
* We can not store it in the constructor because that leads to a circular
* dependency in the service container.
*
* @return \Drupal\Core\Entity\EntityStorageInterface
* The path alias entity storage.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/
protected function getPathAliasEntityStorage() {
return $this->entityTypeManager->getStorage('path_alias');
}
}
