Pathauto and dependencies
This commit is contained in:
parent
4b1a293d57
commit
24ffcb956b
257 changed files with 29510 additions and 0 deletions
351
web/modules/contrib/pathauto/src/AliasCleaner.php
Normal file
351
web/modules/contrib/pathauto/src/AliasCleaner.php
Normal file
|
@ -0,0 +1,351 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Component\Render\PlainTextOutput;
|
||||
use Drupal\Component\Transliteration\TransliterationInterface;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides an alias cleaner.
|
||||
*/
|
||||
class AliasCleaner implements AliasCleanerInterface {
|
||||
|
||||
/**
|
||||
* The config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The alias storage helper.
|
||||
*
|
||||
* @var AliasStorageHelperInterface
|
||||
*/
|
||||
protected $aliasStorageHelper;
|
||||
|
||||
/**
|
||||
* Language manager.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* Cache backend.
|
||||
*
|
||||
* @var \Drupal\Core\Cache\CacheBackendInterface
|
||||
*/
|
||||
protected $cacheBackend;
|
||||
|
||||
/**
|
||||
* Calculated settings cache.
|
||||
*
|
||||
* @todo Split this up into separate properties.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cleanStringCache = array();
|
||||
|
||||
/**
|
||||
* Transliteration service.
|
||||
*
|
||||
* @var \Drupal\Component\Transliteration\TransliterationInterface
|
||||
*/
|
||||
protected $transliteration;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Creates a new AliasCleaner.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\pathauto\AliasStorageHelperInterface $alias_storage_helper
|
||||
* The alias storage helper.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* The cache backend.
|
||||
* @param \Drupal\Component\Transliteration\TransliterationInterface $transliteration
|
||||
* The transliteration service.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, AliasStorageHelperInterface $alias_storage_helper, LanguageManagerInterface $language_manager, CacheBackendInterface $cache_backend, TransliterationInterface $transliteration, ModuleHandlerInterface $module_handler) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->aliasStorageHelper = $alias_storage_helper;
|
||||
$this->languageManager = $language_manager;
|
||||
$this->cacheBackend = $cache_backend;
|
||||
$this->transliteration = $transliteration;
|
||||
$this->moduleHandler = $module_handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cleanAlias($alias) {
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
$alias_max_length = min($config->get('max_length'), $this->aliasStorageHelper->getAliasSchemaMaxLength());
|
||||
|
||||
$output = $alias;
|
||||
|
||||
// Trim duplicate, leading, and trailing separators. Do this before cleaning
|
||||
// backslashes since a pattern like "[token1]/[token2]-[token3]/[token4]"
|
||||
// could end up like "value1/-/value2" and if backslashes were cleaned first
|
||||
// this would result in a duplicate blackslash.
|
||||
$output = $this->getCleanSeparators($output);
|
||||
|
||||
// Trim duplicate, leading, and trailing backslashes.
|
||||
$output = $this->getCleanSeparators($output, '/');
|
||||
|
||||
// Shorten to a logical place based on word boundaries.
|
||||
$output = Unicode::truncate($output, $alias_max_length, TRUE);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCleanSeparators($string, $separator = NULL) {
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
|
||||
if (!isset($separator)) {
|
||||
$separator = $config->get('separator');
|
||||
}
|
||||
|
||||
$output = $string;
|
||||
|
||||
if (strlen($separator)) {
|
||||
// Trim any leading or trailing separators.
|
||||
$output = trim($output, $separator);
|
||||
|
||||
// Escape the separator for use in regular expressions.
|
||||
$seppattern = preg_quote($separator, '/');
|
||||
|
||||
// Replace multiple separators with a single one.
|
||||
$output = preg_replace("/$seppattern+/", $separator, $output);
|
||||
|
||||
// Replace trailing separators around slashes.
|
||||
if ($separator !== '/') {
|
||||
$output = preg_replace("/\/+$seppattern\/+|$seppattern\/+|\/+$seppattern/", "/", $output);
|
||||
}
|
||||
else {
|
||||
// If the separator is a slash, we need to re-add the leading slash
|
||||
// dropped by the trim function.
|
||||
$output = '/' . $output;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cleanString($string, array $options = array()) {
|
||||
if (empty($this->cleanStringCache)) {
|
||||
// Generate and cache variables used in this method.
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
$this->cleanStringCache = array(
|
||||
'separator' => $config->get('separator'),
|
||||
'strings' => array(),
|
||||
'transliterate' => $config->get('transliterate'),
|
||||
'punctuation' => array(),
|
||||
'reduce_ascii' => (bool) $config->get('reduce_ascii'),
|
||||
'ignore_words_regex' => FALSE,
|
||||
'lowercase' => (bool) $config->get('case'),
|
||||
'maxlength' => min($config->get('max_component_length'), $this->aliasStorageHelper->getAliasSchemaMaxLength()),
|
||||
);
|
||||
|
||||
// Generate and cache the punctuation replacements for strtr().
|
||||
$punctuation = $this->getPunctuationCharacters();
|
||||
foreach ($punctuation as $name => $details) {
|
||||
$action = $config->get('punctuation.' . $name);
|
||||
switch ($action) {
|
||||
case PathautoGeneratorInterface::PUNCTUATION_REMOVE:
|
||||
$this->cleanStringCache['punctuation'][$details['value']] = '';
|
||||
break;
|
||||
|
||||
case PathautoGeneratorInterface::PUNCTUATION_REPLACE:
|
||||
$this->cleanStringCache['punctuation'][$details['value']] = $this->cleanStringCache['separator'];
|
||||
break;
|
||||
|
||||
case PathautoGeneratorInterface::PUNCTUATION_DO_NOTHING:
|
||||
// Literally do nothing.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate and cache the ignored words regular expression.
|
||||
$ignore_words = $config->get('ignore_words');
|
||||
$ignore_words_regex = preg_replace(array('/^[,\s]+|[,\s]+$/', '/[,\s]+/'), array('', '\b|\b'), $ignore_words);
|
||||
if ($ignore_words_regex) {
|
||||
$this->cleanStringCache['ignore_words_regex'] = '\b' . $ignore_words_regex . '\b';
|
||||
if (function_exists('mb_eregi_replace')) {
|
||||
mb_regex_encoding('UTF-8');
|
||||
$this->cleanStringCache['ignore_words_callback'] = 'mb_eregi_replace';
|
||||
}
|
||||
else {
|
||||
$this->cleanStringCache['ignore_words_callback'] = 'preg_replace';
|
||||
$this->cleanStringCache['ignore_words_regex'] = '/' . $this->cleanStringCache['ignore_words_regex'] . '/i';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty strings do not need any processing.
|
||||
if ($string === '' || $string === NULL) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$langcode = NULL;
|
||||
if (!empty($options['language'])) {
|
||||
$langcode = $options['language']->getId();
|
||||
}
|
||||
elseif (!empty($options['langcode'])) {
|
||||
$langcode = $options['langcode'];
|
||||
}
|
||||
|
||||
// Check if the string has already been processed, and if so return the
|
||||
// cached result.
|
||||
if (isset($this->cleanStringCache['strings'][$langcode][(string) $string])) {
|
||||
return $this->cleanStringCache['strings'][$langcode][(string) $string];
|
||||
}
|
||||
|
||||
// Remove all HTML tags from the string.
|
||||
$output = Html::decodeEntities($string);
|
||||
$output = PlainTextOutput::renderFromHtml($output);
|
||||
|
||||
// Optionally transliterate.
|
||||
if ($this->cleanStringCache['transliterate']) {
|
||||
// If the reduce strings to letters and numbers is enabled, don't bother
|
||||
// replacing unknown characters with a question mark. Use an empty string
|
||||
// instead.
|
||||
$output = $this->transliteration->transliterate($output, $langcode, $this->cleanStringCache['reduce_ascii'] ? '' : '?');
|
||||
}
|
||||
|
||||
// Replace or drop punctuation based on user settings.
|
||||
$output = strtr($output, $this->cleanStringCache['punctuation']);
|
||||
|
||||
// Reduce strings to letters and numbers.
|
||||
if ($this->cleanStringCache['reduce_ascii']) {
|
||||
$output = preg_replace('/[^a-zA-Z0-9\/]+/', $this->cleanStringCache['separator'], $output);
|
||||
}
|
||||
|
||||
// Get rid of words that are on the ignore list.
|
||||
if ($this->cleanStringCache['ignore_words_regex']) {
|
||||
$words_removed = $this->cleanStringCache['ignore_words_callback']($this->cleanStringCache['ignore_words_regex'], '', $output);
|
||||
if (Unicode::strlen(trim($words_removed)) > 0) {
|
||||
$output = $words_removed;
|
||||
}
|
||||
}
|
||||
|
||||
// Always replace whitespace with the separator.
|
||||
$output = preg_replace('/\s+/', $this->cleanStringCache['separator'], $output);
|
||||
|
||||
// Trim duplicates and remove trailing and leading separators.
|
||||
$output = $this->getCleanSeparators($this->getCleanSeparators($output, $this->cleanStringCache['separator']));
|
||||
|
||||
// Optionally convert to lower case.
|
||||
if ($this->cleanStringCache['lowercase']) {
|
||||
$output = Unicode::strtolower($output);
|
||||
}
|
||||
|
||||
// Shorten to a logical place based on word boundaries.
|
||||
$output = Unicode::truncate($output, $this->cleanStringCache['maxlength'], TRUE);
|
||||
|
||||
// Cache this result in the static array.
|
||||
$this->cleanStringCache['strings'][$langcode][(string) $string] = $output;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPunctuationCharacters() {
|
||||
if (empty($this->punctuationCharacters)) {
|
||||
$langcode = $this->languageManager->getCurrentLanguage()->getId();
|
||||
|
||||
$cid = 'pathauto:punctuation:' . $langcode;
|
||||
if ($cache = $this->cacheBackend->get($cid)) {
|
||||
$this->punctuationCharacters = $cache->data;
|
||||
}
|
||||
else {
|
||||
$punctuation = array();
|
||||
$punctuation['double_quotes'] = array('value' => '"', 'name' => t('Double quotation marks'));
|
||||
$punctuation['quotes'] = array('value' => '\'', 'name' => t("Single quotation marks (apostrophe)"));
|
||||
$punctuation['backtick'] = array('value' => '`', 'name' => t('Back tick'));
|
||||
$punctuation['comma'] = array('value' => ',', 'name' => t('Comma'));
|
||||
$punctuation['period'] = array('value' => '.', 'name' => t('Period'));
|
||||
$punctuation['hyphen'] = array('value' => '-', 'name' => t('Hyphen'));
|
||||
$punctuation['underscore'] = array('value' => '_', 'name' => t('Underscore'));
|
||||
$punctuation['colon'] = array('value' => ':', 'name' => t('Colon'));
|
||||
$punctuation['semicolon'] = array('value' => ';', 'name' => t('Semicolon'));
|
||||
$punctuation['pipe'] = array('value' => '|', 'name' => t('Vertical bar (pipe)'));
|
||||
$punctuation['left_curly'] = array('value' => '{', 'name' => t('Left curly bracket'));
|
||||
$punctuation['left_square'] = array('value' => '[', 'name' => t('Left square bracket'));
|
||||
$punctuation['right_curly'] = array('value' => '}', 'name' => t('Right curly bracket'));
|
||||
$punctuation['right_square'] = array('value' => ']', 'name' => t('Right square bracket'));
|
||||
$punctuation['plus'] = array('value' => '+', 'name' => t('Plus sign'));
|
||||
$punctuation['equal'] = array('value' => '=', 'name' => t('Equal sign'));
|
||||
$punctuation['asterisk'] = array('value' => '*', 'name' => t('Asterisk'));
|
||||
$punctuation['ampersand'] = array('value' => '&', 'name' => t('Ampersand'));
|
||||
$punctuation['percent'] = array('value' => '%', 'name' => t('Percent sign'));
|
||||
$punctuation['caret'] = array('value' => '^', 'name' => t('Caret'));
|
||||
$punctuation['dollar'] = array('value' => '$', 'name' => t('Dollar sign'));
|
||||
$punctuation['hash'] = array('value' => '#', 'name' => t('Number sign (pound sign, hash)'));
|
||||
$punctuation['at'] = array('value' => '@', 'name' => t('At sign'));
|
||||
$punctuation['exclamation'] = array('value' => '!', 'name' => t('Exclamation mark'));
|
||||
$punctuation['tilde'] = array('value' => '~', 'name' => t('Tilde'));
|
||||
$punctuation['left_parenthesis'] = array('value' => '(', 'name' => t('Left parenthesis'));
|
||||
$punctuation['right_parenthesis'] = array('value' => ')', 'name' => t('Right parenthesis'));
|
||||
$punctuation['question_mark'] = array('value' => '?', 'name' => t('Question mark'));
|
||||
$punctuation['less_than'] = array('value' => '<', 'name' => t('Less-than sign'));
|
||||
$punctuation['greater_than'] = array('value' => '>', 'name' => t('Greater-than sign'));
|
||||
$punctuation['slash'] = array('value' => '/', 'name' => t('Slash'));
|
||||
$punctuation['back_slash'] = array('value' => '\\', 'name' => t('Backslash'));
|
||||
|
||||
// Allow modules to alter the punctuation list and cache the result.
|
||||
$this->moduleHandler->alter('pathauto_punctuation_chars', $punctuation);
|
||||
$this->cacheBackend->set($cid, $punctuation);
|
||||
$this->punctuationCharacters = $punctuation;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->punctuationCharacters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cleanTokenValues(&$replacements, $data = array(), $options = array()) {
|
||||
foreach ($replacements as $token => $value) {
|
||||
// Only clean non-path tokens.
|
||||
if (!preg_match('/(path|alias|url|url-brief)\]$/', $token)) {
|
||||
$replacements[$token] = $this->cleanString($value, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetCaches() {
|
||||
$this->cleanStringCache = array();
|
||||
}
|
||||
|
||||
}
|
103
web/modules/contrib/pathauto/src/AliasCleanerInterface.php
Normal file
103
web/modules/contrib/pathauto/src/AliasCleanerInterface.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
/**
|
||||
* @todo add class comment.
|
||||
*/
|
||||
interface AliasCleanerInterface {
|
||||
|
||||
/**
|
||||
* Clean up an URL alias.
|
||||
*
|
||||
* Performs the following alterations:
|
||||
* - Trim duplicate, leading, and trailing back-slashes.
|
||||
* - Trim duplicate, leading, and trailing separators.
|
||||
* - Shorten to a desired length and logical position based on word boundaries.
|
||||
*
|
||||
* @param string $alias
|
||||
* A string with the URL alias to clean up.
|
||||
*
|
||||
* @return string
|
||||
* The cleaned URL alias.
|
||||
*/
|
||||
public function cleanAlias($alias);
|
||||
|
||||
/**
|
||||
* Trims duplicate, leading, and trailing separators from a string.
|
||||
*
|
||||
* @param string $string
|
||||
* The string to clean path separators from.
|
||||
* @param string $separator
|
||||
* The path separator to use when cleaning.
|
||||
*
|
||||
* @return string
|
||||
* The cleaned version of the string.
|
||||
*
|
||||
* @see pathauto_cleanstring()
|
||||
* @see pathauto_clean_alias()
|
||||
*/
|
||||
public function getCleanSeparators($string, $separator = NULL);
|
||||
|
||||
/**
|
||||
* Clean up a string segment to be used in an URL alias.
|
||||
*
|
||||
* Performs the following possible alterations:
|
||||
* - Remove all HTML tags.
|
||||
* - Process the string through the transliteration module.
|
||||
* - Replace or remove punctuation with the separator character.
|
||||
* - Remove back-slashes.
|
||||
* - Replace non-ascii and non-numeric characters with the separator.
|
||||
* - Remove common words.
|
||||
* - Replace whitespace with the separator character.
|
||||
* - Trim duplicate, leading, and trailing separators.
|
||||
* - Convert to lower-case.
|
||||
* - Shorten to a desired length and logical position based on word boundaries.
|
||||
*
|
||||
* This function should *not* be called on URL alias or path strings
|
||||
* because it is assumed that they are already clean.
|
||||
*
|
||||
* @param string $string
|
||||
* A string to clean.
|
||||
* @param array $options
|
||||
* (optional) A keyed array of settings and flags to control the Pathauto
|
||||
* clean string replacement process. Supported options are:
|
||||
* - langcode: A language code to be used when translating strings.
|
||||
*
|
||||
* @return string
|
||||
* The cleaned string.
|
||||
*/
|
||||
public function cleanString($string, array $options = array());
|
||||
|
||||
/**
|
||||
* Return an array of arrays for punctuation values.
|
||||
*
|
||||
* Returns an array of arrays for punctuation values keyed by a name, including
|
||||
* the value and a textual description.
|
||||
* Can and should be expanded to include "all" non text punctuation values.
|
||||
*
|
||||
* @return array
|
||||
* An array of arrays for punctuation values keyed by a name, including the
|
||||
* value and a textual description.
|
||||
*/
|
||||
public function getPunctuationCharacters();
|
||||
|
||||
/**
|
||||
* Clean tokens so they are URL friendly.
|
||||
*
|
||||
* @param array $replacements
|
||||
* An array of token replacements
|
||||
* that need to be "cleaned" for use in the URL.
|
||||
* @param array $data
|
||||
* An array of objects used to generate the replacements.
|
||||
* @param array $options
|
||||
* An array of options used to generate the replacements.
|
||||
*/
|
||||
public function cleanTokenValues(&$replacements, $data = array(), $options = array());
|
||||
|
||||
/**
|
||||
* Resets internal caches.
|
||||
*/
|
||||
public function resetCaches();
|
||||
|
||||
}
|
255
web/modules/contrib/pathauto/src/AliasStorageHelper.php
Normal file
255
web/modules/contrib/pathauto/src/AliasStorageHelper.php
Normal file
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Path\AliasStorageInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
|
||||
/**
|
||||
* Provides helper methods for accessing alias storage.
|
||||
*/
|
||||
class AliasStorageHelper implements AliasStorageHelperInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Alias schema max length.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $aliasSchemaMaxLength = 255;
|
||||
|
||||
/**
|
||||
* Config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The alias storage.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasStorageInterface
|
||||
*/
|
||||
protected $aliasStorage;
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* The messenger.
|
||||
*
|
||||
* @var \Drupal\pathauto\MessengerInterface
|
||||
*/
|
||||
protected $messenger;
|
||||
|
||||
/**
|
||||
* The config factory.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\Core\Path\AliasStorageInterface $alias_storage
|
||||
* The alias storage.
|
||||
* @param \Drupal\Core\Database\Connection $database
|
||||
* The database connection.
|
||||
* @param MessengerInterface $messenger
|
||||
* The messenger.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, AliasStorageInterface $alias_storage, Connection $database, MessengerInterface $messenger, TranslationInterface $string_translation) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->aliasStorage = $alias_storage;
|
||||
$this->database = $database;
|
||||
$this->messenger = $messenger;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAliasSchemaMaxLength() {
|
||||
return $this->aliasSchemaMaxLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $path, $existing_alias = NULL, $op = NULL) {
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
|
||||
// Alert users if they are trying to create an alias that is the same as the
|
||||
// internal path.
|
||||
if ($path['source'] == $path['alias']) {
|
||||
$this->messenger->addMessage($this->t('Ignoring alias %alias because it is the same as the internal path.', array('%alias' => $path['alias'])));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Skip replacing the current alias with an identical alias.
|
||||
if (empty($existing_alias) || $existing_alias['alias'] != $path['alias']) {
|
||||
$path += array(
|
||||
'pathauto' => TRUE,
|
||||
'original' => $existing_alias,
|
||||
'pid' => NULL,
|
||||
);
|
||||
|
||||
// If there is already an alias, respect some update actions.
|
||||
if (!empty($existing_alias)) {
|
||||
switch ($config->get('update_action')) {
|
||||
case PathautoGeneratorInterface::UPDATE_ACTION_NO_NEW:
|
||||
// Do not create the alias.
|
||||
return NULL;
|
||||
|
||||
case PathautoGeneratorInterface::UPDATE_ACTION_LEAVE:
|
||||
// Create a new alias instead of overwriting the existing by leaving
|
||||
// $path['pid'] empty.
|
||||
break;
|
||||
|
||||
case PathautoGeneratorInterface::UPDATE_ACTION_DELETE:
|
||||
// The delete actions should overwrite the existing alias.
|
||||
$path['pid'] = $existing_alias['pid'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the path array.
|
||||
$this->aliasStorage->save($path['source'], $path['alias'], $path['language'], $path['pid']);
|
||||
|
||||
if (!empty($existing_alias['pid'])) {
|
||||
$this->messenger->addMessage($this->t(
|
||||
'Created new alias %alias for %source, replacing %old_alias.',
|
||||
array(
|
||||
'%alias' => $path['alias'],
|
||||
'%source' => $path['source'],
|
||||
'%old_alias' => $existing_alias['alias'],
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$this->messenger->addMessage($this->t('Created new alias %alias for %source.', array(
|
||||
'%alias' => $path['alias'],
|
||||
'%source' => $path['source'],
|
||||
)));
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadBySource($source, $language = LanguageInterface::LANGCODE_NOT_SPECIFIED) {
|
||||
$alias = $this->aliasStorage->load([
|
||||
'source' => $source,
|
||||
'langcode' => $language,
|
||||
]);
|
||||
// If no alias was fetched and if a language was specified, fallbacks to
|
||||
// undefined language.
|
||||
if (!$alias && ($language !== LanguageInterface::LANGCODE_NOT_SPECIFIED)) {
|
||||
$alias = $this->aliasStorage->load([
|
||||
'source' => $source,
|
||||
'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED,
|
||||
]);
|
||||
}
|
||||
return $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteBySourcePrefix($source) {
|
||||
$pids = $this->loadBySourcePrefix($source);
|
||||
if ($pids) {
|
||||
$this->deleteMultiple($pids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteAll() {
|
||||
$this->database->truncate('url_alias')->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deleteEntityPathAll(EntityInterface $entity, $default_uri = NULL) {
|
||||
$this->deleteBySourcePrefix('/' . $entity->toUrl('canonical')->getInternalPath());
|
||||
if (isset($default_uri) && $entity->toUrl('canonical')->toString() != $default_uri) {
|
||||
$this->deleteBySourcePrefix($default_uri);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function loadBySourcePrefix($source) {
|
||||
$select = $this->database->select('url_alias', 'u')
|
||||
->fields('u', array('pid'));
|
||||
|
||||
$or_group = $select->orConditionGroup()
|
||||
->condition('source', $source)
|
||||
->condition('source', rtrim($source, '/') . '/%', 'LIKE');
|
||||
|
||||
return $select
|
||||
->condition($or_group)
|
||||
->execute()
|
||||
->fetchCol();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countBySourcePrefix($source) {
|
||||
$select = $this->database->select('url_alias', 'u')
|
||||
->fields('u', array('pid'));
|
||||
|
||||
$or_group = $select->orConditionGroup()
|
||||
->condition('source', $source)
|
||||
->condition('source', rtrim($source, '/') . '/%', 'LIKE');
|
||||
|
||||
return $select
|
||||
->condition($or_group)
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function countAll() {
|
||||
return $this->database->select('url_alias')
|
||||
->countQuery()
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple URL aliases.
|
||||
*
|
||||
* Intent of this is to abstract a potential path_delete_multiple() function
|
||||
* for Drupal 7 or 8.
|
||||
*
|
||||
* @param int[] $pids
|
||||
* An array of path IDs to delete.
|
||||
*/
|
||||
public function deleteMultiple($pids) {
|
||||
foreach ($pids as $pid) {
|
||||
$this->aliasStorage->delete(array('pid' => $pid));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
117
web/modules/contrib/pathauto/src/AliasStorageHelperInterface.php
Normal file
117
web/modules/contrib/pathauto/src/AliasStorageHelperInterface.php
Normal file
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
|
||||
/**
|
||||
* Provides helper methods for accessing alias storage.
|
||||
*/
|
||||
interface AliasStorageHelperInterface {
|
||||
|
||||
/**
|
||||
* Fetch the maximum length of the {url_alias}.alias field from the schema.
|
||||
*
|
||||
* @return int
|
||||
* An integer of the maximum URL alias length allowed by the database.
|
||||
*/
|
||||
public function getAliasSchemaMaxLength();
|
||||
|
||||
/**
|
||||
* Private function for Pathauto to create an alias.
|
||||
*
|
||||
* @param array $path
|
||||
* An associative array containing the following keys:
|
||||
* - source: The internal system path.
|
||||
* - alias: The URL alias.
|
||||
* - pid: (optional) Unique path alias identifier.
|
||||
* - language: (optional) The language of the alias.
|
||||
* @param array|bool|null $existing_alias
|
||||
* (optional) An associative array of the existing path alias.
|
||||
* @param string $op
|
||||
* An optional string with the operation being performed.
|
||||
*
|
||||
* @return array|bool
|
||||
* The saved path or NULL if the path was not saved.
|
||||
*/
|
||||
public function save(array $path, $existing_alias = NULL, $op = NULL);
|
||||
|
||||
/**
|
||||
* Fetches an existing URL alias given a path and optional language.
|
||||
*
|
||||
* @param string $source
|
||||
* An internal Drupal path.
|
||||
* @param string $language
|
||||
* An optional language code to look up the path in.
|
||||
*
|
||||
* @return bool|array
|
||||
* FALSE if no alias was found or an associative array containing the
|
||||
* following keys:
|
||||
* - source (string): The internal system path with a starting slash.
|
||||
* - alias (string): The URL alias with a starting slash.
|
||||
* - pid (int): Unique path alias identifier.
|
||||
* - langcode (string): The language code of the alias.
|
||||
*/
|
||||
public function loadBySource($source, $language = LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
|
||||
/**
|
||||
* Delete all aliases by source url.
|
||||
*
|
||||
* @param string $source
|
||||
* An internal Drupal path.
|
||||
*
|
||||
* @return bool
|
||||
* The URL alias source.
|
||||
*/
|
||||
public function deleteBySourcePrefix($source);
|
||||
|
||||
/**
|
||||
* Delete all aliases (truncate the url_alias table).
|
||||
*/
|
||||
public function deleteAll();
|
||||
|
||||
/**
|
||||
* Delete an entity URL alias and any of its sub-paths.
|
||||
*
|
||||
* This function also checks to see if the default entity URI is different
|
||||
* from the current entity URI and will delete any of the default aliases.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* An entity object.
|
||||
* @param string $default_uri
|
||||
* The optional default uri path for the entity.
|
||||
*/
|
||||
public function deleteEntityPathAll(EntityInterface $entity, $default_uri = NULL);
|
||||
|
||||
/**
|
||||
* Fetches an existing URL alias given a path prefix.
|
||||
*
|
||||
* @param string $source
|
||||
* An internal Drupal path prefix.
|
||||
*
|
||||
* @return integer[]
|
||||
* An array of PIDs.
|
||||
*/
|
||||
public function loadBySourcePrefix($source);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the count of url aliases for the source.
|
||||
*
|
||||
* @param $source
|
||||
* An internal Drupal path prefix.
|
||||
*
|
||||
* @return int
|
||||
* Number of url aliases for the source.
|
||||
*/
|
||||
public function countBySourcePrefix($source);
|
||||
|
||||
/**
|
||||
* Returns the total count of the url aliases.
|
||||
*
|
||||
* @return int
|
||||
* Total number of aliases.
|
||||
*/
|
||||
public function countAll();
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
/**
|
||||
* Alias types that support batch updates and deletions.
|
||||
*/
|
||||
interface AliasTypeBatchUpdateInterface extends AliasTypeInterface {
|
||||
|
||||
/**
|
||||
* Gets called to batch update all entries.
|
||||
*
|
||||
* @param string $action
|
||||
* One of:
|
||||
* - 'create' to generate a URL alias for paths having none.
|
||||
* - 'update' to recreate the URL alias for paths already having one, useful if the pattern changed.
|
||||
* - 'all' to do both actions above at the same time.
|
||||
* @param array $context
|
||||
* Batch context.
|
||||
*/
|
||||
public function batchUpdate($action, &$context);
|
||||
|
||||
/**
|
||||
* Gets called to batch delete all aliases created by pathauto.
|
||||
*
|
||||
* @param array $context
|
||||
* Batch context.
|
||||
*/
|
||||
public function batchDelete(&$context);
|
||||
|
||||
}
|
48
web/modules/contrib/pathauto/src/AliasTypeInterface.php
Normal file
48
web/modules/contrib/pathauto/src/AliasTypeInterface.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Component\Plugin\DerivativeInspectionInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for pathauto alias types.
|
||||
*/
|
||||
interface AliasTypeInterface extends ContextAwarePluginInterface, DerivativeInspectionInterface {
|
||||
|
||||
/**
|
||||
* Get the label.
|
||||
*
|
||||
* @return string
|
||||
* The label.
|
||||
*/
|
||||
public function getLabel();
|
||||
|
||||
/**
|
||||
* Get the token types.
|
||||
*
|
||||
* @return string[]
|
||||
* The token types.
|
||||
*/
|
||||
public function getTokenTypes();
|
||||
|
||||
/**
|
||||
* Returns the source prefix; used for bulk delete.
|
||||
*
|
||||
* @return string
|
||||
* The source path prefix.
|
||||
*/
|
||||
public function getSourcePrefix();
|
||||
|
||||
/**
|
||||
* Determines if this plugin type can apply a given object.
|
||||
*
|
||||
* @param object $object
|
||||
* The object used to determine if this plugin can apply.
|
||||
*
|
||||
* @return bool
|
||||
* Whether this plugin applies to the given object.
|
||||
*/
|
||||
public function applies($object);
|
||||
|
||||
}
|
71
web/modules/contrib/pathauto/src/AliasTypeManager.php
Normal file
71
web/modules/contrib/pathauto/src/AliasTypeManager.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Cache\CacheBackendInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Plugin\DefaultPluginManager;
|
||||
use Drupal\Component\Plugin\FallbackPluginManagerInterface;
|
||||
|
||||
/**
|
||||
* Manages pathauto alias type plugins.
|
||||
*/
|
||||
class AliasTypeManager extends DefaultPluginManager implements FallbackPluginManagerInterface {
|
||||
|
||||
/**
|
||||
* Constructs a new AliasType manager instance.
|
||||
*
|
||||
* @param \Traversable $namespaces
|
||||
* An object that implements \Traversable which contains the root paths
|
||||
* keyed by the corresponding namespace to look for plugin implementations.
|
||||
* @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
|
||||
* Cache backend instance to use.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler to invoke the alter hook with.
|
||||
*/
|
||||
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
|
||||
parent::__construct('Plugin/pathauto/AliasType', $namespaces, $module_handler, 'Drupal\pathauto\AliasTypeInterface', 'Drupal\pathauto\Annotation\AliasType');
|
||||
$this->alterInfo('pathauto_alias_types');
|
||||
$this->setCacheBackend($cache_backend, 'pathauto_alias_types');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns plugin definitions that support a given token type.
|
||||
*
|
||||
* @param string $type
|
||||
* The type of token plugin must support to be useful.
|
||||
*
|
||||
* @return array
|
||||
* Plugin definitions.
|
||||
*/
|
||||
public function getPluginDefinitionByType($type) {
|
||||
$definitions = array_filter($this->getDefinitions(), function ($definition) use ($type) {
|
||||
if (!empty($definition['types']) && in_array($type, $definition['types'])) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
});
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFallbackPluginId($plugin_id, array $configuration = array()) {
|
||||
return 'broken';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the definition of all visible plugins for this type.
|
||||
*
|
||||
* @return array
|
||||
* An array of plugin definitions (empty array if no definitions were
|
||||
* found). Keys are plugin IDs.
|
||||
*/
|
||||
public function getVisibleDefinitions() {
|
||||
$definitions = $this->getDefinitions();
|
||||
unset($definitions['broken']);
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
}
|
167
web/modules/contrib/pathauto/src/AliasUniquifier.php
Normal file
167
web/modules/contrib/pathauto/src/AliasUniquifier.php
Normal file
|
@ -0,0 +1,167 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Routing\RouteProviderInterface;
|
||||
|
||||
/**
|
||||
* Provides a utility for creating a unique path alias.
|
||||
*/
|
||||
class AliasUniquifier implements AliasUniquifierInterface {
|
||||
|
||||
/**
|
||||
* Config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The alias storage helper.
|
||||
*
|
||||
* @var \Drupal\pathauto\AliasStorageHelperInterface
|
||||
*/
|
||||
protected $aliasStorageHelper;
|
||||
|
||||
/**
|
||||
* The module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The route provider service.
|
||||
*
|
||||
* @var \Drupal\Core\Routing\RouteProviderInterface.
|
||||
*/
|
||||
protected $routeProvider;
|
||||
|
||||
/**
|
||||
* The alias manager.
|
||||
*
|
||||
* @var \Drupal\Core\Path\AliasManagerInterface
|
||||
*/
|
||||
protected $aliasManager;
|
||||
|
||||
/**
|
||||
* Creates a new AliasUniquifier.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\pathauto\AliasStorageHelperInterface $alias_storage_helper
|
||||
* The alias storage helper.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
|
||||
* The route provider service.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, AliasStorageHelperInterface $alias_storage_helper, ModuleHandlerInterface $module_handler, RouteProviderInterface $route_provider, AliasManagerInterface $alias_manager) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->aliasStorageHelper = $alias_storage_helper;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->routeProvider = $route_provider;
|
||||
$this->aliasManager = $alias_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function uniquify(&$alias, $source, $langcode) {
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
|
||||
if (!$this->isReserved($alias, $source, $langcode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the alias already exists, generate a new, hopefully unique, variant.
|
||||
$maxlength = min($config->get('max_length'), $this->aliasStorageHelper->getAliasSchemaMaxlength());
|
||||
$separator = $config->get('separator');
|
||||
$original_alias = $alias;
|
||||
|
||||
$i = 0;
|
||||
do {
|
||||
// Append an incrementing numeric suffix until we find a unique alias.
|
||||
$unique_suffix = $separator . $i;
|
||||
$alias = Unicode::truncate($original_alias, $maxlength - Unicode::strlen($unique_suffix), TRUE) . $unique_suffix;
|
||||
$i++;
|
||||
} while ($this->isReserved($alias, $source, $langcode));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isReserved($alias, $source, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED) {
|
||||
// Check if this alias already exists.
|
||||
if ($existing_source = $this->aliasManager->getPathByAlias($alias, $langcode)) {
|
||||
if ($existing_source != $alias) {
|
||||
// If it is an alias for the provided source, it is allowed to keep using
|
||||
// it. If not, then it is reserved.
|
||||
return $existing_source != $source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Then check if there is a route with the same path.
|
||||
if ($this->isRoute($alias)) {
|
||||
return TRUE;
|
||||
}
|
||||
// Finally check if any other modules have reserved the alias.
|
||||
$args = array(
|
||||
$alias,
|
||||
$source,
|
||||
$langcode,
|
||||
);
|
||||
$implementations = $this->moduleHandler->getImplementations('pathauto_is_alias_reserved');
|
||||
foreach ($implementations as $module) {
|
||||
|
||||
$result = $this->moduleHandler->invoke($module, 'pathauto_is_alias_reserved', $args);
|
||||
|
||||
if (!empty($result)) {
|
||||
// As soon as the first module says that an alias is in fact reserved,
|
||||
// then there is no point in checking the rest of the modules.
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the given path is a valid route.
|
||||
*
|
||||
* @param string $path
|
||||
* A string containing a relative path.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the path already exists.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function isRoute($path) {
|
||||
if (is_file(DRUPAL_ROOT . '/' . $path) || is_dir(DRUPAL_ROOT . '/' . $path)) {
|
||||
// Do not allow existing files or directories to get assigned an automatic
|
||||
// alias. Note that we do not need to use is_link() to check for symbolic
|
||||
// links since this returns TRUE for either is_file() or is_dir() already.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
$routes = $this->routeProvider->getRoutesByPattern($path);
|
||||
|
||||
// Only return true for an exact match, ignore placeholders.
|
||||
foreach ($routes as $route) {
|
||||
if ($route->getPath() == $path) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for alias uniquifiers.
|
||||
*/
|
||||
interface AliasUniquifierInterface {
|
||||
|
||||
/**
|
||||
* Check to ensure a path alias is unique and add suffix variants if necessary.
|
||||
*
|
||||
* Given an alias 'content/test' if a path alias with the exact alias already
|
||||
* exists, the function will change the alias to 'content/test-0' and will
|
||||
* increase the number suffix until it finds a unique alias.
|
||||
*
|
||||
* @param string $alias
|
||||
* A string with the alias. Can be altered by reference.
|
||||
* @param string $source
|
||||
* A string with the path source.
|
||||
* @param string $langcode
|
||||
* A string with a language code.
|
||||
*/
|
||||
public function uniquify(&$alias, $source, $langcode);
|
||||
|
||||
/**
|
||||
* Checks if an alias is reserved.
|
||||
*
|
||||
* @param string $alias
|
||||
* The alias.
|
||||
* @param string $source
|
||||
* The source.
|
||||
* @param string $langcode
|
||||
* (optional) The language code.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if the alias is reserved.
|
||||
*/
|
||||
public function isReserved($alias, $source, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
|
||||
}
|
37
web/modules/contrib/pathauto/src/Annotation/AliasType.php
Normal file
37
web/modules/contrib/pathauto/src/Annotation/AliasType.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Annotation;
|
||||
|
||||
use Drupal\Component\Annotation\Plugin;
|
||||
|
||||
/**
|
||||
* Defines an AliasType annotation.
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
class AliasType extends Plugin {
|
||||
|
||||
/**
|
||||
* The plugin ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* The human-readable name of the action plugin.
|
||||
*
|
||||
* @ingroup plugin_translatable
|
||||
*
|
||||
* @var \Drupal\Core\Annotation\Translation
|
||||
*/
|
||||
public $label;
|
||||
|
||||
/**
|
||||
* The token types.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
public $types = array();
|
||||
|
||||
}
|
370
web/modules/contrib/pathauto/src/Entity/PathautoPattern.php
Normal file
370
web/modules/contrib/pathauto/src/Entity/PathautoPattern.php
Normal file
|
@ -0,0 +1,370 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Entity;
|
||||
|
||||
use Drupal\Component\Plugin\Exception\ContextException;
|
||||
use Drupal\Core\Condition\ConditionPluginCollection;
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
|
||||
use Drupal\pathauto\PathautoPatternInterface;
|
||||
|
||||
/**
|
||||
* Defines the Pathauto pattern entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "pathauto_pattern",
|
||||
* label = @Translation("Pathauto pattern"),
|
||||
* handlers = {
|
||||
* "list_builder" = "Drupal\pathauto\PathautoPatternListBuilder",
|
||||
* "form" = {
|
||||
* "default" = "Drupal\pathauto\Form\PatternEditForm",
|
||||
* "delete" = "Drupal\Core\Entity\EntityDeleteForm",
|
||||
* "enable" = "Drupal\pathauto\Form\PatternEnableForm",
|
||||
* "disable" = "Drupal\pathauto\Form\PatternDisableForm"
|
||||
* },
|
||||
* "route_provider" = {
|
||||
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
|
||||
* },
|
||||
* },
|
||||
* config_prefix = "pattern",
|
||||
* admin_permission = "administer pathauto",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label",
|
||||
* "uuid" = "uuid",
|
||||
* "weight" = "weight",
|
||||
* "status" = "status"
|
||||
* },
|
||||
* config_export = {
|
||||
* "id",
|
||||
* "label",
|
||||
* "type",
|
||||
* "pattern",
|
||||
* "selection_criteria",
|
||||
* "selection_logic",
|
||||
* "weight",
|
||||
* "relationships"
|
||||
* },
|
||||
* lookup_keys = {
|
||||
* "type",
|
||||
* "status",
|
||||
* },
|
||||
* links = {
|
||||
* "collection" = "/admin/config/search/path/patterns",
|
||||
* "edit-form" = "/admin/config/search/path/patterns/{pathauto_pattern}",
|
||||
* "delete-form" = "/admin/config/search/path/patterns/{pathauto_pattern}/delete",
|
||||
* "enable" = "/admin/config/search/path/patterns/{pathauto_pattern}/enable",
|
||||
* "disable" = "/admin/config/search/path/patterns/{pathauto_pattern}/disable"
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class PathautoPattern extends ConfigEntityBase implements PathautoPatternInterface {
|
||||
|
||||
/**
|
||||
* The Pathauto pattern ID.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The Pathauto pattern label.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The pattern type.
|
||||
*
|
||||
* A string denoting the type of pathauto pattern this is. For a node path
|
||||
* this would be 'node', for users it would be 'user', and so on. This allows
|
||||
* for arbitrary non-entity patterns to be possible if applicable.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Plugin\DefaultSingleLazyPluginCollection
|
||||
*/
|
||||
protected $aliasTypeCollection;
|
||||
|
||||
/**
|
||||
* A tokenized string for alias generation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $pattern;
|
||||
|
||||
/**
|
||||
* The plugin configuration for the selection criteria condition plugins.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $selection_criteria = [];
|
||||
|
||||
/**
|
||||
* The selection logic for this pattern entity (either 'and' or 'or').
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selection_logic = 'and';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $weight = 0;
|
||||
|
||||
/**
|
||||
* @var array[]
|
||||
* Keys are context tokens, and values are arrays with the following keys:
|
||||
* - label (string|null, optional): The human-readable label of this
|
||||
* relationship.
|
||||
*/
|
||||
protected $relationships = [];
|
||||
|
||||
/**
|
||||
* The plugin collection that holds the selection criteria condition plugins.
|
||||
*
|
||||
* @var \Drupal\Component\Plugin\LazyPluginCollection
|
||||
*/
|
||||
protected $selectionConditionCollection;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* Not using core's default logic around ConditionPluginCollection since it
|
||||
* incorrectly assumes no condition will ever be applied twice.
|
||||
*/
|
||||
public function preSave(EntityStorageInterface $storage) {
|
||||
parent::preSave($storage);
|
||||
$criteria = [];
|
||||
foreach ($this->getSelectionConditions() as $id => $condition) {
|
||||
$criteria[$id] = $condition->getConfiguration();
|
||||
}
|
||||
$this->selection_criteria = $criteria;
|
||||
|
||||
// Invalidate the static caches.
|
||||
\Drupal::service('pathauto.generator')->resetCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function postDelete(EntityStorageInterface $storage, array $entities) {
|
||||
parent::postDelete($storage, $entities);
|
||||
// Invalidate the static caches.
|
||||
\Drupal::service('pathauto.generator')->resetCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
parent::calculateDependencies();
|
||||
|
||||
$this->calculatePluginDependencies($this->getAliasType());
|
||||
|
||||
foreach ($this->getSelectionConditions() as $instance) {
|
||||
$this->calculatePluginDependencies($instance);
|
||||
}
|
||||
|
||||
return $this->getDependencies();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPattern() {
|
||||
return $this->pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setPattern($pattern) {
|
||||
$this->pattern = $pattern;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getType() {
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAliasType() {
|
||||
if (!$this->aliasTypeCollection) {
|
||||
$this->aliasTypeCollection = new DefaultSingleLazyPluginCollection(\Drupal::service('plugin.manager.alias_type'), $this->getType(), ['default' => $this->getPattern()]);
|
||||
}
|
||||
return $this->aliasTypeCollection->get($this->getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getWeight() {
|
||||
return $this->weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setWeight($weight) {
|
||||
$this->weight = $weight;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getContexts() {
|
||||
$contexts = $this->getAliasType()->getContexts();
|
||||
foreach ($this->getRelationships() as $token => $definition) {
|
||||
/** @var \Drupal\ctools\TypedDataResolver $resolver */
|
||||
$resolver = \Drupal::service('ctools.typed_data.resolver');
|
||||
$context = $resolver->convertTokenToContext($token, $contexts);
|
||||
$context_definition = $context->getContextDefinition();
|
||||
if (!empty($definition['label'])) {
|
||||
$context_definition->setLabel($definition['label']);
|
||||
}
|
||||
$contexts[$token] = $context;
|
||||
}
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasRelationship($token) {
|
||||
return isset($this->relationships[$token]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addRelationship($token, $label = NULL) {
|
||||
if (!$this->hasRelationship($token)) {
|
||||
$this->relationships[$token] = [
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function replaceRelationship($token, $label) {
|
||||
if ($this->hasRelationship($token)) {
|
||||
$this->relationships[$token] = [
|
||||
'label' => $label,
|
||||
];
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeRelationship($token) {
|
||||
unset($this->relationships[$token]);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRelationships() {
|
||||
return $this->relationships;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSelectionConditions() {
|
||||
if (!$this->selectionConditionCollection) {
|
||||
$this->selectionConditionCollection = new ConditionPluginCollection(\Drupal::service('plugin.manager.condition'), $this->get('selection_criteria'));
|
||||
}
|
||||
return $this->selectionConditionCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addSelectionCondition(array $configuration) {
|
||||
$configuration['uuid'] = $this->uuidGenerator()->generate();
|
||||
$this->getSelectionConditions()->addInstanceId($configuration['uuid'], $configuration);
|
||||
return $configuration['uuid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSelectionCondition($condition_id) {
|
||||
return $this->getSelectionConditions()->get($condition_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeSelectionCondition($condition_id) {
|
||||
$this->getSelectionConditions()->removeInstanceId($condition_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSelectionLogic() {
|
||||
return $this->selection_logic;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies($object) {
|
||||
if ($this->getAliasType()->applies($object)) {
|
||||
$definitions = $this->getAliasType()->getContextDefinitions();
|
||||
if (count($definitions) > 1) {
|
||||
throw new \Exception("Alias types do not support more than one context.");
|
||||
}
|
||||
$keys = array_keys($definitions);
|
||||
// Set the context object on our Alias plugin before retrieving contexts.
|
||||
$this->getAliasType()->setContextValue($keys[0], $object);
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextInterface[] $base_contexts */
|
||||
$contexts = $this->getContexts();
|
||||
/** @var \Drupal\Core\Plugin\Context\ContextHandler $context_handler */
|
||||
$context_handler = \Drupal::service('context.handler');
|
||||
$conditions = $this->getSelectionConditions();
|
||||
foreach ($conditions as $condition) {
|
||||
if ($condition instanceof ContextAwarePluginInterface) {
|
||||
try {
|
||||
$context_handler->applyContextMapping($condition, $contexts);
|
||||
}
|
||||
catch (ContextException $e) {
|
||||
watchdog_exception('pathauto', $e);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
$result = $condition->execute();
|
||||
if ($this->getSelectionLogic() == 'and' && !$result) {
|
||||
return FALSE;
|
||||
}
|
||||
elseif ($this->getSelectionLogic() == 'or' && $result) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\EventSubscriber;
|
||||
|
||||
use Drupal\Core\Config\ConfigCrudEvent;
|
||||
use Drupal\Core\Config\ConfigEvents;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\pathauto\AliasTypeManager;
|
||||
|
||||
/**
|
||||
* A subscriber to clear fielddefinition cache when saving pathauto settings.
|
||||
*/
|
||||
class PathautoSettingsCacheTag implements EventSubscriberInterface {
|
||||
|
||||
protected $entityFieldManager;
|
||||
protected $aliasTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a PathautoSettingsCacheTag object.
|
||||
*/
|
||||
public function __construct(EntityFieldManagerInterface $entity_field_manager, AliasTypeManager $alias_type_manager) {
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
$this->aliasTypeManager = $alias_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the 'rendered' cache tag whenever the settings are modified.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigCrudEvent $event
|
||||
* The Event to process.
|
||||
*/
|
||||
public function onSave(ConfigCrudEvent $event) {
|
||||
if ($event->getConfig()->getName() === 'pathauto.settings') {
|
||||
$config = $event->getConfig();
|
||||
$original_entity_types = $config->getOriginal('enabled_entity_types');
|
||||
|
||||
// Clear cached field definitions if the values are changed.
|
||||
if ($original_entity_types != $config->get('enabled_entity_types')) {
|
||||
$this->entityFieldManager->clearCachedFieldDefinitions();
|
||||
$this->aliasTypeManager->clearCachedDefinitions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents() {
|
||||
$events[ConfigEvents::SAVE][] = ['onSave'];
|
||||
return $events;
|
||||
}
|
||||
|
||||
}
|
185
web/modules/contrib/pathauto/src/Form/PathautoAdminDelete.php
Normal file
185
web/modules/contrib/pathauto/src/Form/PathautoAdminDelete.php
Normal file
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\pathauto\AliasTypeManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Alias mass delete form.
|
||||
*/
|
||||
class PathautoAdminDelete extends FormBase {
|
||||
|
||||
/**
|
||||
* The alias type manager.
|
||||
*
|
||||
* @var \Drupal\pathauto\AliasTypeManager
|
||||
*/
|
||||
protected $aliasTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a PathautoAdminDelete object.
|
||||
*
|
||||
* @param \Drupal\pathauto\AliasTypeManager $alias_type_manager
|
||||
* The alias type manager.
|
||||
*/
|
||||
public function __construct(AliasTypeManager $alias_type_manager) {
|
||||
$this->aliasTypeManager = $alias_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.alias_type')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'pathauto_admin_delete';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$form['delete'] = [
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Choose aliases to delete'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
// First we do the "all" case.
|
||||
$storage_helper = \Drupal::service('pathauto.alias_storage_helper');
|
||||
$total_count = $storage_helper->countAll();
|
||||
$form['delete']['all_aliases'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('All aliases'),
|
||||
'#default_value' => FALSE,
|
||||
'#description' => $this->t('Delete all aliases. Number of aliases which will be deleted: %count.', ['%count' => $total_count]),
|
||||
];
|
||||
|
||||
// Next, iterate over all visible alias types.
|
||||
$definitions = $this->aliasTypeManager->getVisibleDefinitions();
|
||||
|
||||
foreach ($definitions as $id => $definition) {
|
||||
/** @var \Drupal\pathauto\AliasTypeInterface $alias_type */
|
||||
$alias_type = $this->aliasTypeManager->createInstance($id);
|
||||
$count = $storage_helper->countBySourcePrefix($alias_type->getSourcePrefix());
|
||||
$form['delete']['plugins'][$id] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => (string) $definition['label'],
|
||||
'#default_value' => FALSE,
|
||||
'#description' => $this->t('Delete aliases for all @label. Number of aliases which will be deleted: %count.', ['@label' => (string) $definition['label'], '%count' => $count]),
|
||||
];
|
||||
}
|
||||
|
||||
$form['options'] = [
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Delete options'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
// Provide checkbox for not deleting custom aliases.
|
||||
$form['options']['keep_custom_aliases'] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Only delete automatically generated aliases'),
|
||||
'#default_value' => TRUE,
|
||||
'#description' => $this->t('When checked, aliases which have been manually set are not affected by this mass-deletion.'),
|
||||
];
|
||||
|
||||
// Warn them and give a button that shows we mean business.
|
||||
$form['warning'] = ['#value' => '<p>' . $this->t('<strong>Note:</strong> there is no confirmation. Be sure of your action before clicking the "Delete aliases now!" button.<br />You may want to make a backup of the database and/or the url_alias table prior to using this feature.') . '</p>'];
|
||||
$form['buttons']['submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Delete aliases now!'),
|
||||
];
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$delete_all = $form_state->getValue(['delete', 'all_aliases']);
|
||||
// Keeping custom aliases forces us to go the slow way to correctly check
|
||||
// the automatic/manual flag.
|
||||
if ($form_state->getValue(['options', 'keep_custom_aliases'])) {
|
||||
$batch = [
|
||||
'title' => $this->t('Bulk deleting URL aliases'),
|
||||
'operations' => [['Drupal\pathauto\Form\PathautoAdminDelete::batchStart', [$delete_all]]],
|
||||
'finished' => 'Drupal\pathauto\Form\PathautoAdminDelete::batchFinished',
|
||||
];
|
||||
|
||||
if ($delete_all) {
|
||||
foreach (array_keys($form_state->getValue(['delete', 'plugins'])) as $id) {
|
||||
$batch['operations'][] = ['Drupal\pathauto\Form\PathautoAdminDelete::batchProcess', [$id]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach (array_keys(array_filter($form_state->getValue(['delete', 'plugins']))) as $id) {
|
||||
$batch['operations'][] = ['Drupal\pathauto\Form\PathautoAdminDelete::batchProcess', [$id]];
|
||||
}
|
||||
}
|
||||
|
||||
batch_set($batch);
|
||||
}
|
||||
else if ($delete_all) {
|
||||
\Drupal::service('pathauto.alias_storage_helper')->deleteAll();
|
||||
drupal_set_message($this->t('All of your path aliases have been deleted.'));
|
||||
}
|
||||
else {
|
||||
$storage_helper = \Drupal::service('pathauto.alias_storage_helper');
|
||||
foreach (array_keys(array_filter($form_state->getValue(['delete', 'plugins']))) as $id) {
|
||||
$alias_type = $this->aliasTypeManager->createInstance($id);
|
||||
$storage_helper->deleteBySourcePrefix((string) $alias_type->getSourcePrefix());
|
||||
drupal_set_message($this->t('All of your %label path aliases have been deleted.', ['%label' => $alias_type->getLabel()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch callback; record if aliases of all types must be deleted.
|
||||
*/
|
||||
public static function batchStart($delete_all, &$context) {
|
||||
$context['results']['delete_all'] = $delete_all;
|
||||
$context['results']['deletions'] = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Common batch processing callback for all operations.
|
||||
*/
|
||||
public static function batchProcess($id, &$context) {
|
||||
/** @var \Drupal\pathauto\AliasTypeBatchUpdateInterface $alias_type */
|
||||
$alias_type = \Drupal::service('plugin.manager.alias_type')->createInstance($id);
|
||||
$alias_type->batchDelete($context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch finished callback.
|
||||
*/
|
||||
public static function batchFinished($success, $results, $operations) {
|
||||
if ($success) {
|
||||
if ($results['delete_all']) {
|
||||
drupal_set_message(t('All of your automatically generated path aliases have been deleted.'));
|
||||
}
|
||||
else if (isset($results['deletions'])) {
|
||||
foreach (array_values($results['deletions']) as $label) {
|
||||
drupal_set_message(t('All of your automatically generated %label path aliases have been deleted.', ['%label' => $label]));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$error_operation = reset($operations);
|
||||
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
164
web/modules/contrib/pathauto/src/Form/PathautoBulkUpdateForm.php
Normal file
164
web/modules/contrib/pathauto/src/Form/PathautoBulkUpdateForm.php
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Form;
|
||||
|
||||
use Drupal\Core\Form\FormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\pathauto\AliasTypeBatchUpdateInterface;
|
||||
use Drupal\pathauto\AliasTypeManager;
|
||||
use Drupal\pathauto\PathautoGeneratorInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure file system settings for this site.
|
||||
*/
|
||||
class PathautoBulkUpdateForm extends FormBase {
|
||||
|
||||
/**
|
||||
* The alias type manager.
|
||||
*
|
||||
* @var \Drupal\pathauto\AliasTypeManager
|
||||
*/
|
||||
protected $aliasTypeManager;
|
||||
|
||||
/**
|
||||
* Constructs a PathautoBulkUpdateForm object.
|
||||
*
|
||||
* @param \Drupal\pathauto\AliasTypeManager $alias_type_manager
|
||||
* The alias type manager.
|
||||
*/
|
||||
public function __construct(AliasTypeManager $alias_type_manager) {
|
||||
$this->aliasTypeManager = $alias_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.alias_type')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'pathauto_bulk_update_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
|
||||
$form = array();
|
||||
|
||||
$form['#update_callbacks'] = array();
|
||||
|
||||
$form['update'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => $this->t('Select the types of paths for which to generate URL aliases'),
|
||||
'#options' => array(),
|
||||
'#default_value' => array(),
|
||||
);
|
||||
|
||||
$definitions = $this->aliasTypeManager->getVisibleDefinitions();
|
||||
|
||||
foreach ($definitions as $id => $definition) {
|
||||
$alias_type = $this->aliasTypeManager->createInstance($id);
|
||||
if ($alias_type instanceof AliasTypeBatchUpdateInterface) {
|
||||
$form['update']['#options'][$id] = $alias_type->getLabel();
|
||||
}
|
||||
}
|
||||
|
||||
$form['action'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Select which URL aliases to generate'),
|
||||
'#options' => ['create' => $this->t('Generate a URL alias for un-aliased paths only')],
|
||||
'#default_value' => 'create',
|
||||
);
|
||||
|
||||
$config = $this->config('pathauto.settings');
|
||||
|
||||
if ($config->get('update_action') == PathautoGeneratorInterface::UPDATE_ACTION_NO_NEW) {
|
||||
// Existing aliases should not be updated.
|
||||
$form['warning'] = array(
|
||||
'#markup' => $this->t('<a href=":url">Pathauto settings</a> are set to ignore paths which already have a URL alias. You can only create URL aliases for paths having none.', [':url' => Url::fromRoute('pathauto.settings.form')->toString()]),
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form['action']['#options']['update'] = $this->t('Update the URL alias for paths having an old URL alias');
|
||||
$form['action']['#options']['all'] = $this->t('Regenerate URL aliases for all paths');
|
||||
}
|
||||
|
||||
$form['actions']['#type'] = 'actions';
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => $this->t('Update'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$batch = array(
|
||||
'title' => $this->t('Bulk updating URL aliases'),
|
||||
'operations' => array(
|
||||
array('Drupal\pathauto\Form\PathautoBulkUpdateForm::batchStart', array()),
|
||||
),
|
||||
'finished' => 'Drupal\pathauto\Form\PathautoBulkUpdateForm::batchFinished',
|
||||
);
|
||||
|
||||
$action = $form_state->getValue('action');
|
||||
|
||||
foreach ($form_state->getValue('update') as $id) {
|
||||
if (!empty($id)) {
|
||||
$batch['operations'][] = array('Drupal\pathauto\Form\PathautoBulkUpdateForm::batchProcess', [$id, $action]);
|
||||
}
|
||||
}
|
||||
|
||||
batch_set($batch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch callback; initialize the number of updated aliases.
|
||||
*/
|
||||
public static function batchStart(&$context) {
|
||||
$context['results']['updates'] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Common batch processing callback for all operations.
|
||||
*
|
||||
* Required to load our include the proper batch file.
|
||||
*/
|
||||
public static function batchProcess($id, $action, &$context) {
|
||||
/** @var \Drupal\pathauto\AliasTypeBatchUpdateInterface $alias_type */
|
||||
$alias_type = \Drupal::service('plugin.manager.alias_type')->createInstance($id);
|
||||
$alias_type->batchUpdate($action, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch finished callback.
|
||||
*/
|
||||
public static function batchFinished($success, $results, $operations) {
|
||||
if ($success) {
|
||||
if ($results['updates']) {
|
||||
drupal_set_message(\Drupal::translation()->formatPlural($results['updates'], 'Generated 1 URL alias.', 'Generated @count URL aliases.'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('No new URL aliases to generate.'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$error_operation = reset($operations);
|
||||
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array('@operation' => $error_operation[0], '@args' => print_r($error_operation[0], TRUE))));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
266
web/modules/contrib/pathauto/src/Form/PathautoSettingsForm.php
Normal file
266
web/modules/contrib/pathauto/src/Form/PathautoSettingsForm.php
Normal file
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Form;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Form\ConfigFormBase;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\pathauto\AliasTypeManager;
|
||||
use Drupal\pathauto\PathautoGeneratorInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Configure file system settings for this site.
|
||||
*/
|
||||
class PathautoSettingsForm extends ConfigFormBase {
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\pathauto\AliasTypeManager
|
||||
*/
|
||||
protected $aliasTypeManager;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, AliasTypeManager $alias_type_manager) {
|
||||
parent::__construct($config_factory);
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
$this->aliasTypeManager = $alias_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('config.factory'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('plugin.manager.alias_type')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'pathauto_settings_form';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEditableConfigNames() {
|
||||
return ['pathauto.settings'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
$config = $this->config('pathauto.settings');
|
||||
|
||||
$form['enabled_entity_types'] = [
|
||||
'#type' => 'details',
|
||||
'#open' => TRUE,
|
||||
'#title' => $this->t('Enabled entity types'),
|
||||
'#description' => $this->t('Enable to add a path field and allow to define alias patterns for the given type. Disabled types already define a path field themselves or currently have a pattern.'),
|
||||
'#tree' => TRUE,
|
||||
];
|
||||
|
||||
// Get all applicable entity types.
|
||||
foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
// Disable a checkbox if it already exists and if the entity type has
|
||||
// patterns currently defined or if it isn't defined by us.
|
||||
$patterns_count = \Drupal::entityQuery('pathauto_pattern')
|
||||
->condition('type', 'canonical_entities:' . $entity_type_id)
|
||||
->count()
|
||||
->execute();
|
||||
|
||||
if (is_subclass_of($entity_type->getClass(), FieldableEntityInterface::class) && $entity_type->hasLinkTemplate('canonical')) {
|
||||
$field_definitions = $this->entityFieldManager->getBaseFieldDefinitions($entity_type_id);
|
||||
$form['enabled_entity_types'][$entity_type_id] = [
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $entity_type->getLabel(),
|
||||
'#default_value' => isset($field_definitions['path']) || in_array($entity_type_id, $config->get('enabled_entity_types')),
|
||||
'#disabled' => isset($field_definitions['path']) && ($field_definitions['path']->getProvider() != 'pathauto' || $patterns_count),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$form['verbose'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Verbose'),
|
||||
'#default_value' => $config->get('verbose'),
|
||||
'#description' => $this->t('Display alias changes (except during bulk updates).'),
|
||||
);
|
||||
|
||||
$form['separator'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Separator'),
|
||||
'#size' => 1,
|
||||
'#maxlength' => 1,
|
||||
'#default_value' => $config->get('separator'),
|
||||
'#description' => $this->t('Character used to separate words in titles. This will replace any spaces and punctuation characters. Using a space or + character can cause unexpected results.'),
|
||||
);
|
||||
|
||||
$form['case'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Character case'),
|
||||
'#default_value' => $config->get('case'),
|
||||
'#description' => $this->t('Convert token values to lowercase.'),
|
||||
);
|
||||
|
||||
$max_length = \Drupal::service('pathauto.alias_storage_helper')->getAliasSchemaMaxlength();
|
||||
|
||||
$help_link = '';
|
||||
if (\Drupal::moduleHandler()->moduleExists('help')) {
|
||||
$help_link = ' ' . $this->t('See <a href=":pathauto-help">Pathauto help</a> for details.', [':pathauto-help' => Url::fromRoute('help.page', ['name' => 'pathauto'])->toString()]);
|
||||
}
|
||||
|
||||
$form['max_length'] = array(
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Maximum alias length'),
|
||||
'#size' => 3,
|
||||
'#maxlength' => 3,
|
||||
'#default_value' => $config->get('max_length'),
|
||||
'#min' => 1,
|
||||
'#max' => $max_length,
|
||||
'#description' => $this->t('Maximum length of aliases to generate. 100 is the recommended length. @max is the maximum possible length.', array('@max' => $max_length)) . $help_link,
|
||||
);
|
||||
|
||||
$form['max_component_length'] = array(
|
||||
'#type' => 'number',
|
||||
'#title' => $this->t('Maximum component length'),
|
||||
'#size' => 3,
|
||||
'#maxlength' => 3,
|
||||
'#default_value' => $config->get('max_component_length'),
|
||||
'#min' => 1,
|
||||
'#max' => $max_length,
|
||||
'#description' => $this->t('Maximum text length of any component in the alias (e.g., [title]). 100 is the recommended length. @max is the maximum possible length.', ['@max' => $max_length]) . $help_link,
|
||||
);
|
||||
|
||||
$description = $this->t('What should Pathauto do when updating an existing content item which already has an alias?');
|
||||
if (\Drupal::moduleHandler()->moduleExists('redirect')) {
|
||||
$description .= ' ' . $this->t('The <a href=":url">Redirect module settings</a> affect whether a redirect is created when an alias is deleted.', array(':url' => Url::fromRoute('redirect.settings')->toString()));
|
||||
}
|
||||
else {
|
||||
$description .= ' ' . $this->t('Considering installing the <a href=":url">Redirect module</a> to get redirects when your aliases change.', array(':url' => 'http://drupal.org/project/redirect'));
|
||||
}
|
||||
|
||||
$form['update_action'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => $this->t('Update action'),
|
||||
'#default_value' => $config->get('update_action'),
|
||||
'#options' => array(
|
||||
PathautoGeneratorInterface::UPDATE_ACTION_NO_NEW => $this->t('Do nothing. Leave the old alias intact.'),
|
||||
PathautoGeneratorInterface::UPDATE_ACTION_LEAVE => $this->t('Create a new alias. Leave the existing alias functioning.'),
|
||||
PathautoGeneratorInterface::UPDATE_ACTION_DELETE => $this->t('Create a new alias. Delete the old alias.'),
|
||||
),
|
||||
'#description' => $description,
|
||||
);
|
||||
|
||||
$form['transliterate'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Transliterate prior to creating alias'),
|
||||
'#default_value' => $config->get('transliterate'),
|
||||
'#description' => $this->t('When a pattern includes certain characters (such as those with accents) should Pathauto attempt to transliterate them into the US-ASCII alphabet?'),
|
||||
);
|
||||
|
||||
$form['reduce_ascii'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Reduce strings to letters and numbers'),
|
||||
'#default_value' => $config->get('reduce_ascii'),
|
||||
'#description' => $this->t('Filters the new alias to only letters and numbers found in the ASCII-96 set.'),
|
||||
);
|
||||
|
||||
$form['ignore_words'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => $this->t('Strings to Remove'),
|
||||
'#default_value' => $config->get('ignore_words'),
|
||||
'#description' => $this->t('Words to strip out of the URL alias, separated by commas. Do not use this to remove punctuation.'),
|
||||
'#wysiwyg' => FALSE,
|
||||
);
|
||||
|
||||
$form['punctuation'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('Punctuation'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
'#tree' => TRUE,
|
||||
);
|
||||
|
||||
$punctuation = \Drupal::service('pathauto.alias_cleaner')->getPunctuationCharacters();
|
||||
|
||||
foreach ($punctuation as $name => $details) {
|
||||
// Use the value from config if it exists.
|
||||
if ($config->get('punctuation.' . $name) !== NULL) {
|
||||
$details['default'] = $config->get('punctuation.' . $name);
|
||||
}
|
||||
else {
|
||||
// Otherwise use the correct default.
|
||||
$details['default'] = $details['value'] == $config->get('separator') ? PathautoGeneratorInterface::PUNCTUATION_REPLACE : PathautoGeneratorInterface::PUNCTUATION_REMOVE;
|
||||
}
|
||||
$form['punctuation'][$name] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $details['name'] . ' (<code>' . Html::escape($details['value']) . '</code>)',
|
||||
'#default_value' => $details['default'],
|
||||
'#options' => array(
|
||||
PathautoGeneratorInterface::PUNCTUATION_REMOVE => $this->t('Remove'),
|
||||
PathautoGeneratorInterface::PUNCTUATION_REPLACE => $this->t('Replace by separator'),
|
||||
PathautoGeneratorInterface::PUNCTUATION_DO_NOTHING => $this->t('No action (do not replace)'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
|
||||
$config = $this->config('pathauto.settings');
|
||||
|
||||
$form_state->cleanValues();
|
||||
|
||||
$original_entity_types = $config->get('enabled_entity_types');
|
||||
foreach ($form_state->getValues() as $key => $value) {
|
||||
if ($key == 'enabled_entity_types') {
|
||||
$enabled_entity_types = [];
|
||||
foreach ($value as $entity_type_id => $enabled) {
|
||||
$field_definitions = $this->entityFieldManager->getBaseFieldDefinitions($entity_type_id);
|
||||
// Verify that the entity type is enabled and that it is not defined
|
||||
// or defined by us before adding it to the configuration, so that
|
||||
// we do not store an entity type that cannot be enabled or disabled.
|
||||
if ($enabled && (!isset($field_definitions['path']) || ($field_definitions['path']->getProvider() === 'pathauto'))) {
|
||||
$enabled_entity_types[] = $entity_type_id;
|
||||
}
|
||||
}
|
||||
$value = $enabled_entity_types;
|
||||
}
|
||||
$config->set($key, $value);
|
||||
}
|
||||
$config->save();
|
||||
|
||||
parent::submitForm($form, $form_state);
|
||||
}
|
||||
|
||||
}
|
52
web/modules/contrib/pathauto/src/Form/PatternDisableForm.php
Normal file
52
web/modules/contrib/pathauto/src/Form/PatternDisableForm.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Provides the pathauto pattern disable disable form.
|
||||
*/
|
||||
class PatternDisableForm extends EntityConfirmFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to disable the pattern %label?', array('%label' => $this->entity->label()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('entity.pathauto_pattern.collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Disable');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return $this->t('Disabled patterns are ignored when generating aliases.');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->entity->disable()->save();
|
||||
drupal_set_message($this->t('Disabled pattern %label.', array('%label' => $this->entity->label())));
|
||||
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
}
|
285
web/modules/contrib/pathauto/src/Form/PatternEditForm.php
Normal file
285
web/modules/contrib/pathauto/src/Form/PatternEditForm.php
Normal file
|
@ -0,0 +1,285 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\pathauto\AliasTypeManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Edit form for pathauto patterns.
|
||||
*/
|
||||
class PatternEditForm extends EntityForm {
|
||||
|
||||
/**
|
||||
* @var \Drupal\pathauto\AliasTypeManager
|
||||
*/
|
||||
protected $manager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\pathauto\PathautoPatternInterface
|
||||
*/
|
||||
protected $entity;
|
||||
|
||||
/**
|
||||
* The entity type bundle info service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
|
||||
*/
|
||||
protected $entityTypeBundleInfo;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('plugin.manager.alias_type'),
|
||||
$container->get('entity_type.bundle.info'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('language_manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* PatternEditForm constructor.
|
||||
*
|
||||
* @param \Drupal\pathauto\AliasTypeManager $manager
|
||||
* @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
*/
|
||||
function __construct(AliasTypeManager $manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityTypeManagerInterface $entity_type_manager, LanguageManagerInterface $language_manager) {
|
||||
$this->manager = $manager;
|
||||
$this->entityTypeBundleInfo = $entity_type_bundle_info;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->languageManager = $language_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildForm(array $form, FormStateInterface $form_state) {
|
||||
|
||||
$options = [];
|
||||
foreach ($this->manager->getVisibleDefinitions() as $plugin_id => $plugin_definition) {
|
||||
$options[$plugin_id] = $plugin_definition['label'];
|
||||
}
|
||||
$form['type'] = [
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Pattern type'),
|
||||
'#default_value' => $this->entity->getType(),
|
||||
'#options' => $options,
|
||||
'#required' => TRUE,
|
||||
'#limit_validation_errors' => array(array('type')),
|
||||
'#submit' => array('::submitSelectType'),
|
||||
'#executes_submit_callback' => TRUE,
|
||||
'#ajax' => array(
|
||||
'callback' => '::ajaxReplacePatternForm',
|
||||
'wrapper' => 'pathauto-pattern',
|
||||
'method' => 'replace',
|
||||
),
|
||||
];
|
||||
|
||||
$form['pattern_container'] = [
|
||||
'#type' => 'container',
|
||||
'#prefix' => '<div id="pathauto-pattern">',
|
||||
'#suffix' => '</div>',
|
||||
];
|
||||
|
||||
// if there is no type yet, stop here.
|
||||
if ($this->entity->getType()) {
|
||||
|
||||
$alias_type = $this->entity->getAliasType();
|
||||
|
||||
$form['pattern_container']['pattern'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'Path pattern',
|
||||
'#default_value' => $this->entity->getPattern(),
|
||||
'#size' => 65,
|
||||
'#maxlength' => 1280,
|
||||
'#element_validate' => array('token_element_validate', 'pathauto_pattern_validate'),
|
||||
'#after_build' => array('token_element_validate'),
|
||||
'#token_types' => $alias_type->getTokenTypes(),
|
||||
'#min_tokens' => 1,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
// Show the token help relevant to this pattern type.
|
||||
$form['pattern_container']['token_help'] = array(
|
||||
'#theme' => 'token_tree_link',
|
||||
'#token_types' => $alias_type->getTokenTypes(),
|
||||
);
|
||||
|
||||
// Expose bundle and language conditions.
|
||||
if ($alias_type->getDerivativeId() && $entity_type = $this->entityTypeManager->getDefinition($alias_type->getDerivativeId())) {
|
||||
|
||||
$default_bundles = [];
|
||||
$default_languages = [];
|
||||
foreach ($this->entity->getSelectionConditions() as $condition_id => $condition) {
|
||||
if (in_array($condition->getPluginId(), ['entity_bundle:' . $entity_type->id(), 'node_type'])) {
|
||||
$default_bundles = $condition->getConfiguration()['bundles'];
|
||||
}
|
||||
elseif ($condition->getPluginId() == 'language') {
|
||||
$default_languages = $condition->getConfiguration()['langcodes'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($entity_type->hasKey('bundle') && $bundles = $this->entityTypeBundleInfo->getBundleInfo($entity_type->id())) {
|
||||
$bundle_options = [];
|
||||
foreach ($bundles as $id => $info) {
|
||||
$bundle_options[$id] = $info['label'];
|
||||
}
|
||||
$form['pattern_container']['bundles'] = array(
|
||||
'#title' => $entity_type->getBundleLabel(),
|
||||
'#type' => 'checkboxes',
|
||||
'#options' => $bundle_options,
|
||||
'#default_value' => $default_bundles,
|
||||
'#description' => $this->t('Check to which types this pattern should be applied. Leave empty to allow any.'),
|
||||
);
|
||||
}
|
||||
|
||||
if ($this->languageManager->isMultilingual() && $entity_type->isTranslatable()) {
|
||||
$language_options = [];
|
||||
foreach ($this->languageManager->getLanguages() as $id => $language) {
|
||||
$language_options[$id] = $language->getName();
|
||||
}
|
||||
$form['pattern_container']['languages'] = array(
|
||||
'#title' => $this->t('Languages'),
|
||||
'#type' => 'checkboxes',
|
||||
'#options' => $language_options,
|
||||
'#default_value' => $default_languages,
|
||||
'#description' => $this->t('Check to which languages this pattern should be applied. Leave empty to allow any.'),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $this->entity->label(),
|
||||
'#required' => TRUE,
|
||||
'#description' => $this->t('A short name to help you identify this pattern in the patterns list.'),
|
||||
);
|
||||
|
||||
$form['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#title' => $this->t('ID'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $this->entity->id(),
|
||||
'#required' => TRUE,
|
||||
'#disabled' => !$this->entity->isNew(),
|
||||
'#machine_name' => array(
|
||||
'exists' => 'Drupal\pathauto\Entity\PathautoPattern::load',
|
||||
),
|
||||
);
|
||||
|
||||
$form['status'] = [
|
||||
'#title' => $this->t('Enabled'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $this->entity->status(),
|
||||
];
|
||||
|
||||
return parent::buildForm($form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function buildEntity(array $form, FormStateInterface $form_state) {
|
||||
/** @var \Drupal\pathauto\PathautoPatternInterface $entity */
|
||||
$entity = parent::buildEntity($form, $form_state);
|
||||
|
||||
// Will only be used for new patterns.
|
||||
$default_weight = 0;
|
||||
|
||||
$alias_type = $entity->getAliasType();
|
||||
if ($alias_type->getDerivativeId() && $this->entityTypeManager->hasDefinition($alias_type->getDerivativeId())) {
|
||||
$entity_type = $alias_type->getDerivativeId();
|
||||
// First, remove bundle and language conditions.
|
||||
foreach ($entity->getSelectionConditions() as $condition_id => $condition) {
|
||||
if (in_array($condition->getPluginId(), ['entity_bundle:' . $entity_type, 'node_type', 'language'])) {
|
||||
$entity->removeSelectionCondition($condition_id);
|
||||
}
|
||||
}
|
||||
|
||||
if ($bundles = array_filter((array) $form_state->getValue('bundles'))) {
|
||||
$default_weight -= 5;
|
||||
$plugin_id = $entity_type == 'node' ? 'node_type' : 'entity_bundle:' . $entity_type;
|
||||
$entity->addSelectionCondition(
|
||||
[
|
||||
'id' => $plugin_id,
|
||||
'bundles' => $bundles,
|
||||
'negate' => FALSE,
|
||||
'context_mapping' => [
|
||||
$entity_type => $entity_type,
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ($languages = array_filter((array) $form_state->getValue('languages'))) {
|
||||
$default_weight -= 5;
|
||||
$language_mapping = $entity_type . ':' . $this->entityTypeManager->getDefinition($entity_type)->getKey('langcode') . ':language';
|
||||
$entity->addSelectionCondition(
|
||||
[
|
||||
'id' => 'language',
|
||||
'langcodes' => array_combine($languages, $languages),
|
||||
'negate' => FALSE,
|
||||
'context_mapping' => [
|
||||
'language' => $language_mapping,
|
||||
]
|
||||
]
|
||||
);
|
||||
$entity->addRelationship($language_mapping, t('Language'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($entity->isNew()) {
|
||||
$entity->setWeight($default_weight);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
parent::save($form, $form_state);
|
||||
drupal_set_message($this->t('Pattern @label saved.', ['@label' => $this->entity->label()]));
|
||||
$form_state->setRedirectUrl($this->entity->toUrl('collection'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles switching the type selector.
|
||||
*/
|
||||
public function ajaxReplacePatternForm($form, FormStateInterface $form_state) {
|
||||
return $form['pattern_container'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles submit call when alias type is selected.
|
||||
*/
|
||||
public function submitSelectType(array $form, FormStateInterface $form_state) {
|
||||
$this->entity = $this->buildEntity($form, $form_state);
|
||||
$form_state->setRebuild();
|
||||
}
|
||||
|
||||
}
|
52
web/modules/contrib/pathauto/src/Form/PatternEnableForm.php
Normal file
52
web/modules/contrib/pathauto/src/Form/PatternEnableForm.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Form;
|
||||
|
||||
use Drupal\Core\Entity\EntityConfirmFormBase;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Provides the pathauto pattern disable disable form.
|
||||
*/
|
||||
class PatternEnableForm extends EntityConfirmFormBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQuestion() {
|
||||
return $this->t('Are you sure you want to enable the pattern %label?', array('%label' => $this->entity->label()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCancelUrl() {
|
||||
return new Url('entity.pathauto_pattern.collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConfirmText() {
|
||||
return $this->t('Enable');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDescription() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function submitForm(array &$form, FormStateInterface $form_state) {
|
||||
$this->entity->enable()->save();
|
||||
drupal_set_message($this->t('Enabled pattern %label.', array('%label' => $this->entity->label())));
|
||||
|
||||
$form_state->setRedirectUrl($this->getCancelUrl());
|
||||
}
|
||||
|
||||
}
|
20
web/modules/contrib/pathauto/src/MessengerInterface.php
Normal file
20
web/modules/contrib/pathauto/src/MessengerInterface.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
/**
|
||||
* Provides an interface for Messengers.
|
||||
*/
|
||||
interface MessengerInterface {
|
||||
|
||||
/**
|
||||
* Adds a message.
|
||||
*
|
||||
* @param string $message
|
||||
* The message to add.
|
||||
* @param string $op
|
||||
* (optional) The operation being performed.
|
||||
*/
|
||||
public function addMessage($message, $op = NULL);
|
||||
|
||||
}
|
365
web/modules/contrib/pathauto/src/PathautoGenerator.php
Normal file
365
web/modules/contrib/pathauto/src/PathautoGenerator.php
Normal file
|
@ -0,0 +1,365 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Entity\ContentEntityInterface;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Entity\RevisionableInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\Utility\Token;
|
||||
use Drupal\token\TokenEntityMapperInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
|
||||
/**
|
||||
* Provides methods for generating path aliases.
|
||||
*/
|
||||
class PathautoGenerator implements PathautoGeneratorInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* Config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* Module handler.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* Token service.
|
||||
*
|
||||
* @var \Drupal\Core\Utility\Token
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
/**
|
||||
* Calculated pattern for a specific entity.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $patterns = array();
|
||||
|
||||
/**
|
||||
* Available patterns per entity type ID.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $patternsByEntityType = array();
|
||||
|
||||
/**
|
||||
* The alias cleaner.
|
||||
*
|
||||
* @var \Drupal\pathauto\AliasCleanerInterface
|
||||
*/
|
||||
protected $aliasCleaner;
|
||||
|
||||
/**
|
||||
* The alias storage helper.
|
||||
*
|
||||
* @var \Drupal\pathauto\AliasStorageHelperInterface
|
||||
*/
|
||||
protected $aliasStorageHelper;
|
||||
|
||||
/**
|
||||
* The alias uniquifier.
|
||||
*
|
||||
* @var \Drupal\pathauto\AliasUniquifierInterface
|
||||
*/
|
||||
protected $aliasUniquifier;
|
||||
|
||||
/**
|
||||
* The messenger service.
|
||||
*
|
||||
* @var \Drupal\pathauto\MessengerInterface
|
||||
*/
|
||||
protected $messenger;
|
||||
|
||||
/**
|
||||
* @var \Drupal\token\TokenEntityMapperInterface
|
||||
*/
|
||||
protected $tokenEntityMapper;
|
||||
|
||||
/**
|
||||
* @var Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* Creates a new Pathauto manager.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler.
|
||||
* @param \Drupal\Core\Utility\Token $token
|
||||
* The token utility.
|
||||
* @param \Drupal\pathauto\AliasCleanerInterface $alias_cleaner
|
||||
* The alias cleaner.
|
||||
* @param \Drupal\pathauto\AliasStorageHelperInterface $alias_storage_helper
|
||||
* The alias storage helper.
|
||||
* @param AliasUniquifierInterface $alias_uniquifier
|
||||
* The alias uniquifier.
|
||||
* @param MessengerInterface $messenger
|
||||
* The messenger service.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
* @param Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, ModuleHandlerInterface $module_handler, Token $token, AliasCleanerInterface $alias_cleaner, AliasStorageHelperInterface $alias_storage_helper, AliasUniquifierInterface $alias_uniquifier, MessengerInterface $messenger, TranslationInterface $string_translation, TokenEntityMapperInterface $token_entity_mappper, EntityTypeManagerInterface $entity_type_manager) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->token = $token;
|
||||
$this->aliasCleaner = $alias_cleaner;
|
||||
$this->aliasStorageHelper = $alias_storage_helper;
|
||||
$this->aliasUniquifier = $alias_uniquifier;
|
||||
$this->messenger = $messenger;
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->tokenEntityMapper = $token_entity_mappper;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createEntityAlias(EntityInterface $entity, $op) {
|
||||
// Retrieve and apply the pattern for this content type.
|
||||
$pattern = $this->getPatternByEntity($entity);
|
||||
if (empty($pattern)) {
|
||||
// No pattern? Do nothing (otherwise we may blow away existing aliases...)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$source = '/' . $entity->toUrl()->getInternalPath();
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
$langcode = $entity->language()->getId();
|
||||
|
||||
// Core does not handle aliases with language Not Applicable.
|
||||
if ($langcode == LanguageInterface::LANGCODE_NOT_APPLICABLE) {
|
||||
$langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
// Build token data.
|
||||
$data = [
|
||||
$this->tokenEntityMapper->getTokenTypeForEntityType($entity->getEntityTypeId()) => $entity,
|
||||
];
|
||||
|
||||
// Allow other modules to alter the pattern.
|
||||
$context = array(
|
||||
'module' => $entity->getEntityType()->getProvider(),
|
||||
'op' => $op,
|
||||
'source' => $source,
|
||||
'data' => $data,
|
||||
'bundle' => $entity->bundle(),
|
||||
'language' => &$langcode,
|
||||
);
|
||||
// @todo Is still hook still useful?
|
||||
$this->moduleHandler->alter('pathauto_pattern', $pattern, $context);
|
||||
|
||||
// Special handling when updating an item which is already aliased.
|
||||
$existing_alias = NULL;
|
||||
if ($op == 'update' || $op == 'bulkupdate') {
|
||||
if ($existing_alias = $this->aliasStorageHelper->loadBySource($source, $langcode)) {
|
||||
switch ($config->get('update_action')) {
|
||||
case PathautoGeneratorInterface::UPDATE_ACTION_NO_NEW:
|
||||
// If an alias already exists,
|
||||
// and the update action is set to do nothing,
|
||||
// then gosh-darn it, do nothing.
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replace any tokens in the pattern.
|
||||
// Uses callback option to clean replacements. No sanitization.
|
||||
// Pass empty BubbleableMetadata object to explicitly ignore cacheablity,
|
||||
// as the result is never rendered.
|
||||
$alias = $this->token->replace($pattern->getPattern(), $data, array(
|
||||
'clear' => TRUE,
|
||||
'callback' => array($this->aliasCleaner, 'cleanTokenValues'),
|
||||
'langcode' => $langcode,
|
||||
'pathauto' => TRUE,
|
||||
), new BubbleableMetadata());
|
||||
|
||||
// Check if the token replacement has not actually replaced any values. If
|
||||
// that is the case, then stop because we should not generate an alias.
|
||||
// @see token_scan()
|
||||
$pattern_tokens_removed = preg_replace('/\[[^\s\]:]*:[^\s\]]*\]/', '', $pattern->getPattern());
|
||||
if ($alias === $pattern_tokens_removed) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$alias = $this->aliasCleaner->cleanAlias($alias);
|
||||
|
||||
// Allow other modules to alter the alias.
|
||||
$context['source'] = &$source;
|
||||
$context['pattern'] = $pattern;
|
||||
$this->moduleHandler->alter('pathauto_alias', $alias, $context);
|
||||
|
||||
// If we have arrived at an empty string, discontinue.
|
||||
if (!Unicode::strlen($alias)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If the alias already exists, generate a new, hopefully unique, variant.
|
||||
$original_alias = $alias;
|
||||
$this->aliasUniquifier->uniquify($alias, $source, $langcode);
|
||||
if ($original_alias != $alias) {
|
||||
// Alert the user why this happened.
|
||||
$this->messenger->addMessage($this->t('The automatically generated alias %original_alias conflicted with an existing alias. Alias changed to %alias.', array(
|
||||
'%original_alias' => $original_alias,
|
||||
'%alias' => $alias,
|
||||
)), $op);
|
||||
}
|
||||
|
||||
// Return the generated alias if requested.
|
||||
if ($op == 'return') {
|
||||
return $alias;
|
||||
}
|
||||
|
||||
// Build the new path alias array and send it off to be created.
|
||||
$path = array(
|
||||
'source' => $source,
|
||||
'alias' => $alias,
|
||||
'language' => $langcode,
|
||||
);
|
||||
|
||||
return $this->aliasStorageHelper->save($path, $existing_alias, $op);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads pathauto patterns for a given entity type ID
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* An entity type ID.
|
||||
*
|
||||
* @return \Drupal\pathauto\PathautoPatternInterface[]
|
||||
* A list of patterns, sorted by weight.
|
||||
*/
|
||||
protected function getPatternByEntityType($entity_type_id) {
|
||||
if (!isset($this->patternsByEntityType[$entity_type_id])) {
|
||||
$ids = \Drupal::entityQuery('pathauto_pattern')
|
||||
->condition('type', array_keys(\Drupal::service('plugin.manager.alias_type')
|
||||
->getPluginDefinitionByType($this->tokenEntityMapper->getTokenTypeForEntityType($entity_type_id))))
|
||||
->condition('status', 1)
|
||||
->sort('weight')
|
||||
->execute();
|
||||
|
||||
$this->patternsByEntityType[$entity_type_id] = \Drupal::entityTypeManager()
|
||||
->getStorage('pathauto_pattern')
|
||||
->loadMultiple($ids);
|
||||
}
|
||||
|
||||
return $this->patternsByEntityType[$entity_type_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPatternByEntity(EntityInterface $entity) {
|
||||
$langcode = $entity->language()->getId();
|
||||
if (!isset($this->patterns[$entity->getEntityTypeId()][$entity->id()][$langcode])) {
|
||||
foreach ($this->getPatternByEntityType($entity->getEntityTypeId()) as $pattern) {
|
||||
if ($pattern->applies($entity)) {
|
||||
$this->patterns[$entity->getEntityTypeId()][$entity->id()][$langcode] = $pattern;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If still not set.
|
||||
if (!isset($this->patterns[$entity->getEntityTypeId()][$entity->id()][$langcode])) {
|
||||
$this->patterns[$entity->getEntityTypeId()][$entity->id()][$langcode] = NULL;
|
||||
}
|
||||
}
|
||||
return $this->patterns[$entity->getEntityTypeId()][$entity->id()][$langcode];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetCaches() {
|
||||
$this->patterns = [];
|
||||
$this->patternsByEntityType = [];
|
||||
$this->aliasCleaner->resetCaches();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function updateEntityAlias(EntityInterface $entity, $op, array $options = array()) {
|
||||
// Skip if the entity does not have the path field.
|
||||
if (!($entity instanceof ContentEntityInterface) || !$entity->hasField('path')) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Skip if pathauto processing is disabled.
|
||||
if ($entity->path->pathauto != PathautoState::CREATE && empty($options['force'])) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Only act if this is the default revision.
|
||||
if ($entity instanceof RevisionableInterface && !$entity->isDefaultRevision()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$options += array('language' => $entity->language()->getId());
|
||||
$type = $entity->getEntityTypeId();
|
||||
|
||||
// Skip processing if the entity has no pattern.
|
||||
if (!$this->getPatternByEntity($entity)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Deal with taxonomy specific logic.
|
||||
// @todo Update and test forum related code.
|
||||
if ($type == 'taxonomy_term') {
|
||||
|
||||
$config_forum = $this->configFactory->get('forum.settings');
|
||||
if ($entity->getVocabularyId() == $config_forum->get('vocabulary')) {
|
||||
$type = 'forum';
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$result = $this->createEntityAlias($entity, $op);
|
||||
}
|
||||
catch (\InvalidArgumentException $e) {
|
||||
drupal_set_message($e->getMessage(), 'error');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// @todo Move this to a method on the pattern plugin.
|
||||
if ($type == 'taxonomy_term') {
|
||||
foreach ($this->loadTermChildren($entity->id()) as $subterm) {
|
||||
$this->updateEntityAlias($subterm, $op, $options);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all children of a term ID.
|
||||
*
|
||||
* @param int $tid
|
||||
* Term ID to retrieve parents for.
|
||||
*
|
||||
* @return \Drupal\taxonomy\TermInterface[]
|
||||
* An array of term objects that are the children of the term $tid.
|
||||
*/
|
||||
protected function loadTermChildren($tid) {
|
||||
return $this->entityTypeManager->getStorage('taxonomy_term')->loadChildren($tid);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* Provides and interface for PathautoGenerator.
|
||||
*/
|
||||
interface PathautoGeneratorInterface {
|
||||
|
||||
/**
|
||||
* "Do nothing. Leave the old alias intact."
|
||||
*/
|
||||
const UPDATE_ACTION_NO_NEW = 0;
|
||||
|
||||
/**
|
||||
* "Create a new alias. Leave the existing alias functioning."
|
||||
*/
|
||||
const UPDATE_ACTION_LEAVE = 1;
|
||||
|
||||
/**
|
||||
* "Create a new alias. Delete the old alias."
|
||||
*/
|
||||
const UPDATE_ACTION_DELETE = 2;
|
||||
|
||||
/**
|
||||
* Remove the punctuation from the alias.
|
||||
*/
|
||||
const PUNCTUATION_REMOVE = 0;
|
||||
|
||||
/**
|
||||
* Replace the punctuation with the separator in the alias.
|
||||
*/
|
||||
const PUNCTUATION_REPLACE = 1;
|
||||
|
||||
/**
|
||||
* Leave the punctuation as it is in the alias.
|
||||
*/
|
||||
const PUNCTUATION_DO_NOTHING = 2;
|
||||
|
||||
/**
|
||||
* Resets internal caches.
|
||||
*/
|
||||
public function resetCaches();
|
||||
|
||||
/**
|
||||
* Load an alias pattern entity by entity, bundle, and language.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* An entity.
|
||||
* @return \Drupal\pathauto\PathautoPatternInterface|null
|
||||
*/
|
||||
public function getPatternByEntity(EntityInterface $entity);
|
||||
|
||||
/**
|
||||
* Apply patterns to create an alias.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity.
|
||||
* @param string $op
|
||||
* Operation being performed on the content being aliased
|
||||
* ('insert', 'update', 'return', or 'bulkupdate').
|
||||
*
|
||||
* @return array|string
|
||||
* The alias that was created.
|
||||
*
|
||||
* @see _pathauto_set_alias()
|
||||
*/
|
||||
public function createEntityAlias(EntityInterface $entity, $op);
|
||||
|
||||
/**
|
||||
* Creates or updates an alias for the given entity.
|
||||
*
|
||||
* @param EntityInterface $entity
|
||||
* Entity for which to update the alias.
|
||||
* @param string $op
|
||||
* The operation performed (insert, update)
|
||||
* @param array $options
|
||||
* - force: will force updating the path
|
||||
* - language: the language for which to create the alias
|
||||
*
|
||||
* @return array|null
|
||||
* - An array with alias data in case the alias has been created or updated.
|
||||
* - NULL if no operation performed.
|
||||
*/
|
||||
public function updateEntityAlias(EntityInterface $entity, $op, array $options = array());
|
||||
|
||||
}
|
58
web/modules/contrib/pathauto/src/PathautoItem.php
Normal file
58
web/modules/contrib/pathauto/src/PathautoItem.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Field\FieldStorageDefinitionInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\path\Plugin\Field\FieldType\PathItem;
|
||||
|
||||
/**
|
||||
* Extends the default PathItem implementation to generate aliases.
|
||||
*/
|
||||
class PathautoItem extends PathItem {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
|
||||
$properties = parent::propertyDefinitions($field_definition);
|
||||
$properties['pathauto'] = DataDefinition::create('integer')
|
||||
->setLabel(t('Pathauto state'))
|
||||
->setDescription(t('Whether an automated alias should be created or not.'))
|
||||
->setComputed(TRUE)
|
||||
->setClass('\Drupal\pathauto\PathautoState');
|
||||
return $properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave($update) {
|
||||
// Only allow the parent implementation to act if pathauto will not create
|
||||
// an alias.
|
||||
if ($this->pathauto == PathautoState::SKIP) {
|
||||
parent::postSave($update);
|
||||
}
|
||||
$this->get('pathauto')->persist();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isEmpty() {
|
||||
// Make sure that the pathauto state flag does not get lost if just that is
|
||||
// changed.
|
||||
return !$this->alias && !$this->get('pathauto')->hasValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applyDefaultValue($notify = TRUE) {
|
||||
parent::applyDefaultValue($notify);
|
||||
// Created fields default creating a new alias.
|
||||
$this->setValue(array('pathauto' => PathautoState::CREATE), $notify);
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
181
web/modules/contrib/pathauto/src/PathautoPatternInterface.php
Normal file
181
web/modules/contrib/pathauto/src/PathautoPatternInterface.php
Normal file
|
@ -0,0 +1,181 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface for defining Pathauto pattern entities.
|
||||
*/
|
||||
interface PathautoPatternInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Get the tokenized pattern used during alias generation.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPattern();
|
||||
|
||||
/**
|
||||
* Set the tokenized pattern to use during alias generation.
|
||||
*
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPattern($pattern);
|
||||
|
||||
/**
|
||||
* Gets the type of this pattern.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType();
|
||||
|
||||
/**
|
||||
* @return \Drupal\pathauto\AliasTypeInterface
|
||||
*/
|
||||
public function getAliasType();
|
||||
|
||||
/**
|
||||
* Gets the weight of this pattern (compared to other patterns of this type).
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getWeight();
|
||||
|
||||
/**
|
||||
* Sets the weight of this pattern (compared to other patterns of this type).
|
||||
*
|
||||
* @param int $weight
|
||||
* The weight of the variant.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setWeight($weight);
|
||||
|
||||
/**
|
||||
* Returns the contexts of this pattern.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextInterface[]
|
||||
*/
|
||||
public function getContexts();
|
||||
|
||||
/**
|
||||
* Returns whether a relationship exists.
|
||||
*
|
||||
* @param string $token
|
||||
* Relationship identifier.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the relationship exists, FALSE otherwise.
|
||||
*/
|
||||
public function hasRelationship($token);
|
||||
|
||||
/**
|
||||
* Adds a relationship.
|
||||
*
|
||||
* The relationship will not be changed if it already exists.
|
||||
*
|
||||
* @param string $token
|
||||
* Relationship identifier.
|
||||
* @param string|null $label
|
||||
* (optional) A label, will use the label of the referenced context if not
|
||||
* provided.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addRelationship($token, $label = NULL);
|
||||
|
||||
/**
|
||||
* Replaces a relationship.
|
||||
*
|
||||
* Only already existing relationships are updated.
|
||||
*
|
||||
* @param string $token
|
||||
* Relationship identifier.
|
||||
* @param string|null $label
|
||||
* (optional) A label, will use the label of the referenced context if not
|
||||
* provided.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function replaceRelationship($token, $label);
|
||||
|
||||
/**
|
||||
* Removes a relationship.
|
||||
*
|
||||
* @param string $token
|
||||
* Relationship identifier.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeRelationship($token);
|
||||
|
||||
/**
|
||||
* Returns a list of relationships.
|
||||
*
|
||||
* @return array[]
|
||||
* Keys are context tokens, and values are arrays with the following keys:
|
||||
* - label (string|null, optional): The human-readable label of this
|
||||
* relationship.
|
||||
*/
|
||||
public function getRelationships();
|
||||
|
||||
/**
|
||||
* Gets the selection condition collection.
|
||||
*
|
||||
* @return \Drupal\Core\Condition\ConditionInterface[]|\Drupal\Core\Condition\ConditionPluginCollection
|
||||
*/
|
||||
public function getSelectionConditions();
|
||||
|
||||
/**
|
||||
* Adds selection criteria.
|
||||
*
|
||||
* @param array $configuration
|
||||
* Configuration of the selection criteria.
|
||||
*
|
||||
* @return string
|
||||
* The condition id of the new criteria.
|
||||
*/
|
||||
public function addSelectionCondition(array $configuration);
|
||||
|
||||
/**
|
||||
* Gets selection criteria by condition id.
|
||||
*
|
||||
* @param string $condition_id
|
||||
* The id of the condition.
|
||||
*
|
||||
* @return \Drupal\Core\Condition\ConditionInterface
|
||||
*/
|
||||
public function getSelectionCondition($condition_id);
|
||||
|
||||
/**
|
||||
* Removes selection criteria by condition id.
|
||||
*
|
||||
* @param string $condition_id
|
||||
* The id of the condition.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeSelectionCondition($condition_id);
|
||||
|
||||
/**
|
||||
* Gets the selection logic used by the criteria (ie. "and" or "or").
|
||||
*
|
||||
* @return string
|
||||
* Either "and" or "or"; represents how the selection criteria are combined.
|
||||
*/
|
||||
public function getSelectionLogic();
|
||||
|
||||
/**
|
||||
* Determines if this pattern can apply a given object.
|
||||
*
|
||||
* @param $object
|
||||
* The object used to determine if this plugin can apply.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function applies($object);
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Config\Entity\DraggableListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* Provides a listing of Pathauto pattern entities.
|
||||
*/
|
||||
class PathautoPatternListBuilder extends DraggableListBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected $limit = FALSE;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormId() {
|
||||
return 'pathauto_pattern_list';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['label'] = $this->t('Label');
|
||||
$header['pattern'] = $this->t('Pattern');
|
||||
$header['type'] = $this->t('Pattern type');
|
||||
$header['conditions'] = $this->t('Conditions');
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
/* @var \Drupal\pathauto\PathautoPatternInterface $entity */
|
||||
$row['label'] = $entity->label();
|
||||
$row['patern']['#markup'] = $entity->getPattern();
|
||||
$row['type']['#markup'] = $entity->getAliasType()->getLabel();
|
||||
$row['conditions']['#theme'] = 'item_list';
|
||||
foreach ($entity->getSelectionConditions() as $condition) {
|
||||
$row['conditions']['#items'][] = $condition->summary();
|
||||
}
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
}
|
97
web/modules/contrib/pathauto/src/PathautoState.php
Normal file
97
web/modules/contrib/pathauto/src/PathautoState.php
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\TypedData\TypedData;
|
||||
|
||||
/**
|
||||
* A property that stores in keyvalue whether an entity should receive an alias.
|
||||
*/
|
||||
class PathautoState extends TypedData {
|
||||
|
||||
/**
|
||||
* An automatic alias should not be created.
|
||||
*/
|
||||
const SKIP = 0;
|
||||
|
||||
/**
|
||||
* An automatic alias should be created.
|
||||
*/
|
||||
const CREATE = 1;
|
||||
|
||||
/**
|
||||
* Pathauto state.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Field\FieldItemInterface
|
||||
*/
|
||||
protected $parent;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue() {
|
||||
if ($this->value === NULL) {
|
||||
// If no value has been set or loaded yet, try to load a value if this
|
||||
// entity has already been saved.
|
||||
$this->value = \Drupal::keyValue($this->getCollection())
|
||||
->get($this->parent->getEntity()->id());
|
||||
// If it was not yet saved or no value was found, then set the flag to
|
||||
// create the alias if there is a matching pattern.
|
||||
if ($this->value === NULL) {
|
||||
$entity = $this->parent->getEntity();
|
||||
$pattern = \Drupal::service('pathauto.generator')->getPatternByEntity($entity);
|
||||
$this->value = !empty($pattern) ? static::CREATE : static::SKIP;
|
||||
}
|
||||
}
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setValue($value, $notify = TRUE) {
|
||||
$this->value = $value;
|
||||
// Notify the parent of any changes.
|
||||
if ($notify && isset($this->parent)) {
|
||||
$this->parent->onChange($this->name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if a value was set.
|
||||
*/
|
||||
public function hasValue() {
|
||||
return $this->value !== NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the state.
|
||||
*/
|
||||
public function persist() {
|
||||
\Drupal::keyValue($this->getCollection())->set(
|
||||
$this->parent->getEntity()
|
||||
->id(), $this->value
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the stored state.
|
||||
*/
|
||||
public function purge() {
|
||||
\Drupal::keyValue($this->getCollection())
|
||||
->delete($this->parent->getEntity()->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key value collection that should be used for the given entity.
|
||||
* @return string
|
||||
*/
|
||||
protected function getCollection() {
|
||||
return 'pathauto_state.' . $this->parent->getEntity()->getEntityTypeId();
|
||||
}
|
||||
|
||||
}
|
71
web/modules/contrib/pathauto/src/PathautoWidget.php
Normal file
71
web/modules/contrib/pathauto/src/PathautoWidget.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\path\Plugin\Field\FieldWidget\PathWidget;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Url;
|
||||
|
||||
/**
|
||||
* Extends the core path widget.
|
||||
*/
|
||||
class PathautoWidget extends PathWidget {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
|
||||
$element = parent::formElement($items, $delta, $element, $form, $form_state);
|
||||
$entity = $items->getEntity();
|
||||
|
||||
// Taxonomy terms do not have an actual fieldset for path settings.
|
||||
// Merge in the defaults.
|
||||
// @todo Impossible to do this in widget, use another solution
|
||||
/*
|
||||
$form['path'] += array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => $this->t('URL path settings'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => empty($form['path']['alias']),
|
||||
'#group' => 'additional_settings',
|
||||
'#attributes' => array(
|
||||
'class' => array('path-form'),
|
||||
),
|
||||
'#access' => \Drupal::currentUser()->hasPermission('create url aliases') || \Drupal::currentUser()->hasPermission('administer url aliases'),
|
||||
'#weight' => 30,
|
||||
'#tree' => TRUE,
|
||||
'#element_validate' => array('path_form_element_validate'),
|
||||
);*/
|
||||
|
||||
$pattern = \Drupal::service('pathauto.generator')->getPatternByEntity($entity);
|
||||
if (empty($pattern)) {
|
||||
return $element;
|
||||
}
|
||||
|
||||
if (\Drupal::currentUser()->hasPermission('administer pathauto')) {
|
||||
$description = $this->t('Uncheck this to create a custom alias below. <a href="@admin_link">Configure URL alias patterns.</a>', ['@admin_link' => Url::fromRoute('entity.pathauto_pattern.collection')->toString()]);
|
||||
}
|
||||
else {
|
||||
$description = $this->t('Uncheck this to create a custom alias below.');
|
||||
}
|
||||
|
||||
$element['pathauto'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => $this->t('Generate automatic URL alias'),
|
||||
'#default_value' => $entity->path->pathauto,
|
||||
'#description' => $description,
|
||||
'#weight' => -1,
|
||||
);
|
||||
|
||||
// Add JavaScript that will disable the path textfield when the automatic
|
||||
// alias checkbox is checked.
|
||||
$element['alias']['#states']['disabled']['input[name="path[' . $delta . '][pathauto]"]'] = array('checked' => TRUE);
|
||||
|
||||
// Override path.module's vertical tabs summary.
|
||||
$element['alias']['#attached']['library'] = ['pathauto/widget'];
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Plugin\Action;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Action\ActionBase;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\pathauto\PathautoState;
|
||||
|
||||
/**
|
||||
* Pathauto entity update action.
|
||||
*
|
||||
* @Action(
|
||||
* id = "pathauto_update_alias",
|
||||
* label = @Translation("Update URL alias of an entity"),
|
||||
* )
|
||||
*/
|
||||
class UpdateAction extends ActionBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute($entity = NULL) {
|
||||
$entity->path->pathauto = PathautoState::CREATE;
|
||||
\Drupal::service('pathauto.generator')->updateEntityAlias($entity, 'bulkupdate', array('message' => TRUE));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) {
|
||||
$result = AccessResult::allowedIfHasPermission($account, 'create url aliases');
|
||||
return $return_as_object ? $result : $result->isAllowed();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Plugin\Deriver;
|
||||
|
||||
use Drupal\Component\Plugin\Derivative\DeriverBase;
|
||||
use Drupal\Core\Entity\EntityFieldManagerInterface;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\token\TokenEntityMapperInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Deriver that exposes content entities as alias type plugins.
|
||||
*/
|
||||
class EntityAliasTypeDeriver extends DeriverBase implements ContainerDeriverInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Entity\EntityFieldManagerInterface
|
||||
*/
|
||||
protected $entityFieldManager;
|
||||
|
||||
/**
|
||||
* @var \Drupal\token\TokenEntityMapperInterface
|
||||
*/
|
||||
protected $tokenEntityMapper;
|
||||
|
||||
/**
|
||||
* Constructs new EntityAliasTypeDeriver.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity type manager.
|
||||
* @param \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager
|
||||
* The entity field manager.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* The string translation service.
|
||||
* @apram \Drupal\Token\TokenEntityMapperInterface $token_entity_mapper
|
||||
* The token entity mapper.
|
||||
*/
|
||||
public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFieldManagerInterface $entity_field_manager, TranslationInterface $string_translation, TokenEntityMapperInterface $token_entity_mapper) {
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->entityFieldManager = $entity_field_manager;
|
||||
$this->stringTranslation = $string_translation;
|
||||
$this->tokenEntityMapper = $token_entity_mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, $base_plugin_id) {
|
||||
return new static(
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('entity_field.manager'),
|
||||
$container->get('string_translation'),
|
||||
$container->get('token.entity_mapper')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDerivativeDefinitions($base_plugin_definition) {
|
||||
foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $entity_type) {
|
||||
// An entity type must have a canonical link template and support fields.
|
||||
if ($entity_type->hasLinkTemplate('canonical') && is_subclass_of($entity_type->getClass(), FieldableEntityInterface::class)) {
|
||||
$base_fields = $this->entityFieldManager->getBaseFieldDefinitions($entity_type_id);
|
||||
if (!isset($base_fields['path'])) {
|
||||
// The entity type does not have a path field and is therefore not
|
||||
// supported.
|
||||
continue;
|
||||
}
|
||||
$this->derivatives[$entity_type_id] = $base_plugin_definition;
|
||||
$this->derivatives[$entity_type_id]['label'] = $entity_type->getLabel();
|
||||
$this->derivatives[$entity_type_id]['types'] = [$this->tokenEntityMapper->getTokenTypeForEntityType($entity_type_id)];
|
||||
$this->derivatives[$entity_type_id]['provider'] = $entity_type->getProvider();
|
||||
$this->derivatives[$entity_type_id]['context'] = [
|
||||
$entity_type_id => new ContextDefinition("entity:$entity_type_id", $this->t('@label being aliased', ['@label' => $entity_type->getLabel()]))
|
||||
];
|
||||
}
|
||||
}
|
||||
return $this->derivatives;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Plugin\pathauto\AliasType;
|
||||
|
||||
/**
|
||||
* Defines a fallback plugin for missing block plugins.
|
||||
*
|
||||
* @AliasType(
|
||||
* id = "broken",
|
||||
* label = @Translation("Broken"),
|
||||
* admin_label = @Translation("Broken/Missing"),
|
||||
* category = @Translation("AliasType"),
|
||||
* )
|
||||
*/
|
||||
class Broken extends EntityAliasTypeBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLabel() {
|
||||
return $this->t('Broken type');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Plugin\pathauto\AliasType;
|
||||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Entity\FieldableEntityInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Plugin\Context\Context;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginBase;
|
||||
use Drupal\pathauto\AliasTypeBatchUpdateInterface;
|
||||
use Drupal\pathauto\AliasTypeInterface;
|
||||
use Drupal\pathauto\PathautoState;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* A pathauto alias type plugin for entities with canonical links.
|
||||
*
|
||||
* @AliasType(
|
||||
* id = "canonical_entities",
|
||||
* deriver = "\Drupal\pathauto\Plugin\Deriver\EntityAliasTypeDeriver"
|
||||
* )
|
||||
*/
|
||||
class EntityAliasTypeBase extends ContextAwarePluginBase implements AliasTypeInterface, AliasTypeBatchUpdateInterface, ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The module handler service.
|
||||
*
|
||||
* @var \Drupal\Core\Extension\ModuleHandlerInterface
|
||||
*/
|
||||
protected $moduleHandler;
|
||||
|
||||
/**
|
||||
* The language manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Language\LanguageManagerInterface
|
||||
*/
|
||||
protected $languageManager;
|
||||
|
||||
/**
|
||||
* The entity manager service.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
||||
*/
|
||||
protected $entityTypeManager;
|
||||
|
||||
/**
|
||||
* The key/value manager service.
|
||||
*
|
||||
* @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface
|
||||
*/
|
||||
protected $keyValue;
|
||||
|
||||
/**
|
||||
* The database connection.
|
||||
*
|
||||
* @var \Drupal\Core\Database\Connection
|
||||
*/
|
||||
protected $database;
|
||||
|
||||
/**
|
||||
* The path prefix for this entity type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix;
|
||||
|
||||
/**
|
||||
* Constructs a EntityAliasTypeBase instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value
|
||||
* The key/value manager service.
|
||||
* @param \Drupal\Core\Database\Connection $database
|
||||
* The database connection.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, EntityTypeManagerInterface $entity_type_manager, KeyValueFactoryInterface $key_value, Connection $database) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition);
|
||||
$this->moduleHandler = $module_handler;
|
||||
$this->languageManager = $language_manager;
|
||||
$this->entityTypeManager = $entity_type_manager;
|
||||
$this->keyValue = $key_value;
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('module_handler'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('keyvalue'),
|
||||
$container->get('database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getLabel() {
|
||||
$definition = $this->getPluginDefinition();
|
||||
// Cast the admin label to a string since it is an object.
|
||||
// @see \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
return (string) $definition['label'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTokenTypes() {
|
||||
$definition = $this->getPluginDefinition();
|
||||
return $definition['types'];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function batchUpdate($action, &$context) {
|
||||
if (!isset($context['sandbox']['current'])) {
|
||||
$context['sandbox']['count'] = 0;
|
||||
$context['sandbox']['current'] = 0;
|
||||
}
|
||||
|
||||
$entity_type = $this->entityTypeManager->getDefinition($this->getEntityTypeId());
|
||||
$id_key = $entity_type->getKey('id');
|
||||
|
||||
$query = $this->database->select($entity_type->get('base_table'), 'base_table');
|
||||
$query->leftJoin('url_alias', 'ua', "CONCAT('" . $this->getSourcePrefix() . "' , base_table.$id_key) = ua.source");
|
||||
$query->addField('base_table', $id_key, 'id');
|
||||
|
||||
switch ($action) {
|
||||
case 'create':
|
||||
$query->isNull('ua.source');
|
||||
break;
|
||||
case 'update':
|
||||
$query->isNotNull('ua.source');
|
||||
break;
|
||||
case 'all':
|
||||
// Nothing to do. We want all paths.
|
||||
break;
|
||||
default:
|
||||
// Unknown action. Abort!
|
||||
return;
|
||||
}
|
||||
$query->condition('base_table.' . $id_key, $context['sandbox']['current'], '>');
|
||||
$query->orderBy('base_table.' . $id_key);
|
||||
$query->addTag('pathauto_bulk_update');
|
||||
$query->addMetaData('entity', $this->getEntityTypeId());
|
||||
|
||||
// Get the total amount of items to process.
|
||||
if (!isset($context['sandbox']['total'])) {
|
||||
$context['sandbox']['total'] = $query->countQuery()->execute()->fetchField();
|
||||
|
||||
// If there are no entities to update, then stop immediately.
|
||||
if (!$context['sandbox']['total']) {
|
||||
$context['finished'] = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$query->range(0, 25);
|
||||
$ids = $query->execute()->fetchCol();
|
||||
|
||||
$updates = $this->bulkUpdate($ids);
|
||||
$context['sandbox']['count'] += count($ids);
|
||||
$context['sandbox']['current'] = max($ids);
|
||||
$context['results']['updates'] += $updates;
|
||||
$context['message'] = $this->t('Updated alias for %label @id.', array('%label' => $entity_type->getLabel(), '@id' => end($ids)));
|
||||
|
||||
if ($context['sandbox']['count'] != $context['sandbox']['total']) {
|
||||
$context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function batchDelete(&$context) {
|
||||
if (!isset($context['sandbox']['current'])) {
|
||||
$context['sandbox']['count'] = 0;
|
||||
$context['sandbox']['current'] = 0;
|
||||
}
|
||||
|
||||
$entity_type = $this->entityTypeManager->getDefinition($this->getEntityTypeId());
|
||||
$id_key = $entity_type->getKey('id');
|
||||
|
||||
$query = $this->database->select($entity_type->get('base_table'), 'base_table');
|
||||
$query->innerJoin('url_alias', 'ua', "CONCAT('" . $this->getSourcePrefix() . "' , base_table.$id_key) = ua.source");
|
||||
$query->addField('base_table', $id_key, 'id');
|
||||
$query->addField('ua', 'pid');
|
||||
$query->condition('ua.pid', $context['sandbox']['current'], '>');
|
||||
$query->orderBy('ua.pid');
|
||||
$query->addTag('pathauto_bulk_delete');
|
||||
$query->addMetaData('entity', $this->getEntityTypeId());
|
||||
|
||||
// Get the total amount of items to process.
|
||||
if (!isset($context['sandbox']['total'])) {
|
||||
$context['sandbox']['total'] = $query->countQuery()->execute()->fetchField();
|
||||
|
||||
// If there are no entities to delete, then stop immediately.
|
||||
if (!$context['sandbox']['total']) {
|
||||
$context['finished'] = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$query->range(0, 100);
|
||||
$pids_by_id = $query->execute()->fetchAllKeyed();
|
||||
|
||||
$this->bulkDelete($pids_by_id);
|
||||
$context['sandbox']['count'] += count($pids_by_id);
|
||||
$context['sandbox']['current'] = max($pids_by_id);
|
||||
$context['results']['deletions'][] = $this->getLabel();
|
||||
|
||||
if ($context['sandbox']['count'] != $context['sandbox']['total']) {
|
||||
$context['finished'] = $context['sandbox']['count'] / $context['sandbox']['total'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entity type ID.
|
||||
*
|
||||
* @return string
|
||||
* The entity type ID.
|
||||
*/
|
||||
protected function getEntityTypeId() {
|
||||
return $this->getDerivativeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the URL aliases for multiple entities.
|
||||
*
|
||||
* @param array $ids
|
||||
* An array of entity IDs.
|
||||
* @param array $options
|
||||
* An optional array of additional options.
|
||||
*
|
||||
* @return int
|
||||
* The number of updated URL aliases.
|
||||
*/
|
||||
protected function bulkUpdate(array $ids, array $options = array()) {
|
||||
$options += array('message' => FALSE);
|
||||
$updates = 0;
|
||||
|
||||
$entities = $this->entityTypeManager->getStorage($this->getEntityTypeId())->loadMultiple($ids);
|
||||
foreach ($entities as $entity) {
|
||||
// Update aliases for the entity's default language and its translations.
|
||||
foreach ($entity->getTranslationLanguages() as $langcode => $language) {
|
||||
$translated_entity = $entity->getTranslation($langcode);
|
||||
$result = \Drupal::service('pathauto.generator')->updateEntityAlias($translated_entity, 'bulkupdate', $options);
|
||||
if ($result) {
|
||||
$updates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($options['message'])) {
|
||||
drupal_set_message(\Drupal::translation()->formatPlural(count($ids), 'Updated 1 %label URL alias.', 'Updated @count %label URL aliases.'), array('%label' => $this->getLabel()));
|
||||
}
|
||||
|
||||
return $updates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the URL aliases for multiple entities.
|
||||
*
|
||||
* @param int[] $pids_by_id
|
||||
* A list of path IDs keyed by entity ID.
|
||||
*/
|
||||
protected function bulkDelete(array $pids_by_id) {
|
||||
$collection = 'pathauto_state.' . $this->getEntityTypeId();
|
||||
$states = $this->keyValue->get($collection)->getMultiple(array_keys($pids_by_id));
|
||||
|
||||
$pids = [];
|
||||
foreach ($pids_by_id as $id => $pid) {
|
||||
// Only delete aliases that were created by this module.
|
||||
if (isset($states[$id]) && $states[$id] == PathautoState::CREATE) {
|
||||
$pids[] = $pid;
|
||||
}
|
||||
}
|
||||
\Drupal::service('pathauto.alias_storage_helper')->deleteMultiple($pids);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
$dependencies = [];
|
||||
$dependencies['module'][] = $this->entityTypeManager->getDefinition($this->getEntityTypeId())->getProvider();
|
||||
return $dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies($object) {
|
||||
return $object instanceof FieldableEntityInterface && $object->getEntityTypeId() == $this->getEntityTypeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourcePrefix() {
|
||||
if (empty($this->prefix)) {
|
||||
$entity_type = $this->entityTypeManager->getDefinition($this->getEntityTypeId());
|
||||
$path = $entity_type->getLinkTemplate('canonical');
|
||||
$this->prefix = substr($path, 0, strpos($path, '{'));
|
||||
}
|
||||
return $this->prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setContextValue($name, $value) {
|
||||
// Overridden to avoid merging existing cacheability metadata, which is not
|
||||
// relevant for alias type plugins.
|
||||
$this->context[$name] = new Context($this->getContextDefinition($name), $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Plugin\pathauto\AliasType;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Entity\EntityTypeManagerInterface;
|
||||
use Drupal\Core\Extension\ModuleHandlerInterface;
|
||||
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
|
||||
use Drupal\Core\Language\LanguageManagerInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* A pathauto alias type plugin for forum terms.
|
||||
*
|
||||
* @AliasType(
|
||||
* id = "forum",
|
||||
* label = @Translation("Forum"),
|
||||
* types = {"term"},
|
||||
* provider = "forum",
|
||||
* context = {
|
||||
* "taxonomy_term" = @ContextDefinition("entity:taxonomy_term")
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class ForumAliasType extends EntityAliasTypeBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* The config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* Constructs a ForumAliasType instance.
|
||||
*
|
||||
* @param array $configuration
|
||||
* A configuration array containing information about the plugin instance.
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the plugin instance.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
|
||||
* The module handler service.
|
||||
* @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
|
||||
* The language manager service.
|
||||
* @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
||||
* The entity manager service.
|
||||
* @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value
|
||||
* The key/value manager service.
|
||||
* @param \Drupal\Core\Database\Connection $database
|
||||
* The database service.
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
*/
|
||||
public function __construct(array $configuration, $plugin_id, $plugin_definition, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, EntityTypeManagerInterface $entity_type_manager, KeyValueFactoryInterface $key_value, Connection $database, ConfigFactoryInterface $config_factory) {
|
||||
parent::__construct($configuration, $plugin_id, $plugin_definition, $module_handler, $language_manager, $entity_type_manager, $key_value, $database);
|
||||
$this->configFactory = $config_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
$plugin_definition,
|
||||
$container->get('module_handler'),
|
||||
$container->get('language_manager'),
|
||||
$container->get('entity_type.manager'),
|
||||
$container->get('keyvalue'),
|
||||
$container->get('database'),
|
||||
$container->get('config.factory')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getEntityTypeId() {
|
||||
return 'taxonomy_term';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSourcePrefix() {
|
||||
return '/forum/';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function applies($object) {
|
||||
if (parent::applies($object)) {
|
||||
/** @var \Drupal\taxonomy\TermInterface $object */
|
||||
$vid = $this->configFactory->get('forum.settings')->get('vocabulary');
|
||||
return $object->getVocabularyId() == $vid;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\pathauto\PathautoGeneratorInterface;
|
||||
use Drupal\pathauto\PathautoState;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Bulk update functionality tests.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoBulkUpdateTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'pathauto', 'forum');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* The created nodes.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
/**
|
||||
* The created patterns.
|
||||
*
|
||||
* @var \Drupal\pathauto\PathautoPatternInterface
|
||||
*/
|
||||
protected $patterns;
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Allow other modules to add additional permissions for the admin user.
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer forums',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->patterns = array();
|
||||
$this->patterns['node'] = $this->createPattern('node', '/content/[node:title]');
|
||||
$this->patterns['user'] = $this->createPattern('user', '/users/[user:name]');
|
||||
$this->patterns['forum'] = $this->createPattern('forum', '/forums/[term:name]');
|
||||
}
|
||||
|
||||
function testBulkUpdate() {
|
||||
// Create some nodes.
|
||||
$this->nodes = array();
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$node = $this->drupalCreateNode();
|
||||
$this->nodes[$node->id()] = $node;
|
||||
}
|
||||
|
||||
// Clear out all aliases.
|
||||
$this->deleteAllAliases();
|
||||
|
||||
// Bulk create aliases.
|
||||
$edit = array(
|
||||
'update[canonical_entities:node]' => TRUE,
|
||||
'update[canonical_entities:user]' => TRUE,
|
||||
'update[forum]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/update_bulk', $edit, t('Update'));
|
||||
|
||||
// This has generated 8 aliases: 5 nodes, 2 users and 1 forum.
|
||||
$this->assertText('Generated 8 URL aliases.');
|
||||
|
||||
// Check that aliases have actually been created.
|
||||
foreach ($this->nodes as $node) {
|
||||
$this->assertEntityAliasExists($node);
|
||||
}
|
||||
$this->assertEntityAliasExists($this->adminUser);
|
||||
// This is the default "General discussion" forum.
|
||||
$this->assertAliasExists(['source' => '/taxonomy/term/1']);
|
||||
|
||||
// Add a new node.
|
||||
$new_node = $this->drupalCreateNode(array('path' => array('alias' => '', 'pathauto' => PathautoState::SKIP)));
|
||||
|
||||
// Run the update again which should not run against any nodes.
|
||||
$this->drupalPostForm('admin/config/search/path/update_bulk', $edit, t('Update'));
|
||||
$this->assertText('No new URL aliases to generate.');
|
||||
$this->assertNoEntityAliasExists($new_node);
|
||||
|
||||
// Make sure existing aliases can be overriden.
|
||||
$this->drupalPostForm('admin/config/search/path/settings', ['update_action' => PathautoGeneratorInterface::UPDATE_ACTION_DELETE], t('Save configuration'));
|
||||
|
||||
// Patterns did not change, so no aliases should be regenerated.
|
||||
$edit['action'] = 'all';
|
||||
$this->drupalPostForm('admin/config/search/path/update_bulk', $edit, t('Update'));
|
||||
$this->assertText('No new URL aliases to generate.');
|
||||
|
||||
// Update the node pattern, and leave other patterns alone. Existing nodes should get a new alias,
|
||||
// except the node above whose alias is manually set. Other aliases must be left alone.
|
||||
$this->patterns['node']->delete();
|
||||
$this->patterns['node'] = $this->createPattern('node', '/archive/node-[node:nid]');
|
||||
|
||||
$this->drupalPostForm('admin/config/search/path/update_bulk', $edit, t('Update'));
|
||||
$this->assertText('Generated 5 URL aliases.');
|
||||
|
||||
// Prevent existing aliases to be overriden. The bulk generate page should only offer
|
||||
// to create an alias for paths which have none.
|
||||
$this->drupalPostForm('admin/config/search/path/settings', ['update_action' => PathautoGeneratorInterface::UPDATE_ACTION_NO_NEW], t('Save configuration'));
|
||||
|
||||
$this->drupalGet('admin/config/search/path/update_bulk');
|
||||
$this->assertFieldByName('action', 'create');
|
||||
$this->assertText('Pathauto settings are set to ignore paths which already have a URL alias.');
|
||||
$this->assertNoFieldByName('action', 'update');
|
||||
$this->assertNoFieldByName('action', 'all');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests alias generation for nodes that existed before installing Pathauto.
|
||||
*/
|
||||
function testBulkUpdateExistingContent() {
|
||||
// Create a node.
|
||||
$node = $this->drupalCreateNode();
|
||||
|
||||
// Delete its alias and Pathauto metadata.
|
||||
\Drupal::service('pathauto.alias_storage_helper')->deleteEntityPathAll($node);
|
||||
$node->path->first()->get('pathauto')->purge();
|
||||
\Drupal::entityTypeManager()->getStorage('node')->resetCache(array($node->id()));
|
||||
|
||||
// Execute bulk generation.
|
||||
// Bulk create aliases.
|
||||
$edit = array(
|
||||
'update[canonical_entities:node]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/update_bulk', $edit, t('Update'));
|
||||
|
||||
// Verify that the alias was created for the node.
|
||||
$this->assertText('Generated 1 URL alias.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\comment\Tests\CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Tests pathauto settings form.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoEnablingEntityTypesTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
use CommentTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'pathauto', 'comment');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'article'));
|
||||
$this->addDefaultCommentField('node', 'article');
|
||||
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer nodes',
|
||||
'post comments',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* A suite of tests to verify if the feature to enable and disable the
|
||||
* ability to define alias patterns for a given entity type works. Test with
|
||||
* the comment module, as it is not enabled by default.
|
||||
*/
|
||||
function testEnablingEntityTypes() {
|
||||
// Verify that the comment entity type is not available when trying to add
|
||||
// a new pattern, nor "broken".
|
||||
$this->drupalGet('/admin/config/search/path/patterns/add');
|
||||
$this->assertEqual(count($this->cssSelect('option[value = "canonical_entities:comment"]:contains(Comment)')), 0);
|
||||
$this->assertEqual(count($this->cssSelect('option:contains(Broken)')), 0);
|
||||
|
||||
// Enable the entity type and create a pattern for it.
|
||||
$this->drupalGet('/admin/config/search/path/settings');
|
||||
$edit = [
|
||||
'enabled_entity_types[comment]' => TRUE,
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Save configuration');
|
||||
$this->createPattern('comment', '/comment/[comment:body]');
|
||||
|
||||
// Create a node, a comment type and a comment entity.
|
||||
$node = $this->drupalCreateNode(['type' => 'article']);
|
||||
$this->drupalGet('/node/' . $node->id());
|
||||
$edit = [
|
||||
'comment_body[0][value]' => 'test-body',
|
||||
];
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
|
||||
// Verify that an alias has been generated and that the type can no longer
|
||||
// be disabled.
|
||||
$this->assertAliasExists(['alias' => '/comment/test-body']);
|
||||
$this->drupalGet('/admin/config/search/path/settings');
|
||||
$this->assertEqual(count($this->cssSelect('input[name = "enabled_entity_types[comment]"][disabled = "disabled"]')), 1);
|
||||
}
|
||||
|
||||
}
|
201
web/modules/contrib/pathauto/src/Tests/PathautoLocaleTest.php
Normal file
201
web/modules/contrib/pathauto/src/Tests/PathautoLocaleTest.php
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
use Drupal\pathauto\PathautoState;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Test pathauto functionality with localization and translation.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoLocaleTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'pathauto', 'locale', 'content_translation');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create Article node type.
|
||||
$this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that when an English node is updated, its old English alias is
|
||||
* updated and its newer French alias is left intact.
|
||||
*/
|
||||
function testLanguageAliases() {
|
||||
|
||||
$this->createPattern('node', '/content/[node:title]');
|
||||
|
||||
// Add predefined French language.
|
||||
ConfigurableLanguage::createFromLangcode('fr')->save();
|
||||
|
||||
$node = array(
|
||||
'title' => 'English node',
|
||||
'langcode' => 'en',
|
||||
'path' => array(array(
|
||||
'alias' => '/english-node',
|
||||
'pathauto' => FALSE,
|
||||
)),
|
||||
);
|
||||
$node = $this->drupalCreateNode($node);
|
||||
$english_alias = \Drupal::service('path.alias_storage')->load(array('alias' => '/english-node', 'langcode' => 'en'));
|
||||
$this->assertTrue($english_alias, 'Alias created with proper language.');
|
||||
|
||||
// Also save a French alias that should not be left alone, even though
|
||||
// it is the newer alias.
|
||||
$this->saveEntityAlias($node, '/french-node', 'fr');
|
||||
|
||||
// Add an alias with the soon-to-be generated alias, causing the upcoming
|
||||
// alias update to generate a unique alias with the '-0' suffix.
|
||||
$this->saveAlias('/node/invalid', '/content/english-node', Language::LANGCODE_NOT_SPECIFIED);
|
||||
|
||||
// Update the node, triggering a change in the English alias.
|
||||
$node->path->pathauto = PathautoState::CREATE;
|
||||
$node->save();
|
||||
|
||||
// Check that the new English alias replaced the old one.
|
||||
$this->assertEntityAlias($node, '/content/english-node-0', 'en');
|
||||
$this->assertEntityAlias($node, '/french-node', 'fr');
|
||||
$this->assertAliasExists(array('pid' => $english_alias['pid'], 'alias' => '/content/english-node-0'));
|
||||
|
||||
// Create a new node with the same title as before but without
|
||||
// specifying a language.
|
||||
$node = $this->drupalCreateNode(array('title' => 'English node', 'langcode' => LanguageInterface::LANGCODE_NOT_SPECIFIED));
|
||||
|
||||
// Check that the new node had a unique alias generated with the '-0'
|
||||
// suffix.
|
||||
$this->assertEntityAlias($node, '/content/english-node-0', LanguageInterface::LANGCODE_NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that patterns work on multilingual content.
|
||||
*/
|
||||
function testLanguagePatterns() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
|
||||
// Add French language.
|
||||
$edit = array(
|
||||
'predefined_langcode' => 'fr',
|
||||
);
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
|
||||
|
||||
$this->enableArticleTranslation();
|
||||
|
||||
// Create a pattern for English articles.
|
||||
$this->drupalGet('admin/config/search/path/patterns/add');
|
||||
$edit = array(
|
||||
'type' => 'canonical_entities:node',
|
||||
);
|
||||
$this->drupalPostAjaxForm(NULL, $edit, 'type');
|
||||
$edit += array(
|
||||
'pattern' => '/the-articles/[node:title]',
|
||||
'label' => 'English articles',
|
||||
'id' => 'english_articles',
|
||||
'bundles[article]' => TRUE,
|
||||
'languages[en]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Pattern English articles saved.');
|
||||
|
||||
// Create a pattern for French articles.
|
||||
$this->drupalGet('admin/config/search/path/patterns/add');
|
||||
$edit = array(
|
||||
'type' => 'canonical_entities:node',
|
||||
);
|
||||
$this->drupalPostAjaxForm(NULL, $edit, 'type');
|
||||
$edit += array(
|
||||
'pattern' => '/les-articles/[node:title]',
|
||||
'label' => 'French articles',
|
||||
'id' => 'french_articles',
|
||||
'bundles[article]' => TRUE,
|
||||
'languages[fr]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Pattern French articles saved.');
|
||||
|
||||
// Create a node and its translation. Assert aliases.
|
||||
$edit = array(
|
||||
'title[0][value]' => 'English node',
|
||||
'langcode[0][value]' => 'en',
|
||||
);
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
|
||||
$english_node = $this->drupalGetNodeByTitle('English node');
|
||||
$this->assertAlias('/node/' . $english_node->id(), '/the-articles/english-node', 'en');
|
||||
|
||||
$this->drupalGet('node/' . $english_node->id() . '/translations');
|
||||
$this->clickLink(t('Add'));
|
||||
$edit = array(
|
||||
'title[0][value]' => 'French node',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save and keep published (this translation)'));
|
||||
$this->rebuildContainer();
|
||||
$english_node = $this->drupalGetNodeByTitle('English node');
|
||||
$french_node = $english_node->getTranslation('fr');
|
||||
$this->assertAlias('/node/' . $french_node->id(), '/les-articles/french-node', 'fr');
|
||||
|
||||
// Bulk delete and Bulk generate patterns. Assert aliases.
|
||||
$this->deleteAllAliases();
|
||||
// Bulk create aliases.
|
||||
$edit = array(
|
||||
'update[canonical_entities:node]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/update_bulk', $edit, t('Update'));
|
||||
$this->assertText(t('Generated 2 URL aliases.'));
|
||||
$this->assertAlias('/node/' . $english_node->id(), '/the-articles/english-node', 'en');
|
||||
$this->assertAlias('/node/' . $french_node->id(), '/les-articles/french-node', 'fr');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the alias created for a node with language Not Applicable.
|
||||
*/
|
||||
public function testLanguageNotApplicable() {
|
||||
$this->drupalLogin($this->rootUser);
|
||||
$this->enableArticleTranslation();
|
||||
|
||||
// Create a pattern for nodes.
|
||||
$pattern = $this->createPattern('node', '/content/[node:title]', -1);
|
||||
$pattern->save();
|
||||
|
||||
// Create a node with language Not Applicable.
|
||||
$node = $this->createNode(['type' => 'article', 'title' => 'Test node', 'langcode' => LanguageInterface::LANGCODE_NOT_APPLICABLE]);
|
||||
|
||||
// Check that the generated alias has language Not Specified.
|
||||
$alias = \Drupal::service('pathauto.alias_storage_helper')->loadBySource('/node/' . $node->id());
|
||||
$this->assertEqual($alias['langcode'], LanguageInterface::LANGCODE_NOT_SPECIFIED, 'PathautoGenerator::createEntityAlias() adjusts the alias langcode from Not Applicable to Not Specified.');
|
||||
|
||||
// Check that the alias works.
|
||||
$this->drupalGet('content/test-node');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables content translation on articles.
|
||||
*/
|
||||
protected function enableArticleTranslation() {
|
||||
// Enable content translation on articles.
|
||||
$this->drupalGet('admin/config/regional/content-language');
|
||||
$edit = array(
|
||||
'entity_types[node]' => TRUE,
|
||||
'settings[node][article][translatable]' => TRUE,
|
||||
'settings[node][article][settings][language][language_alterable]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Save configuration'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\pathauto\PathautoState;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Mass delete functionality tests.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoMassDeleteTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'taxonomy', 'pathauto');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* The test nodes.
|
||||
*
|
||||
* @var \Drupal\node\NodeInterface
|
||||
*/
|
||||
protected $nodes;
|
||||
|
||||
/**
|
||||
* The test accounts.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $accounts;
|
||||
|
||||
/**
|
||||
* The test terms.
|
||||
*
|
||||
* @var \Drupal\taxonomy\TermInterface
|
||||
*/
|
||||
protected $terms;
|
||||
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->createPattern('node', '/content/[node:title]');
|
||||
$this->createPattern('user', '/users/[user:name]');
|
||||
$this->createPattern('taxonomy_term', '/[term:vocabulary]/[term:name]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the deletion of all the aliases.
|
||||
*/
|
||||
function testDeleteAll() {
|
||||
// 1. Test that deleting all the aliases, of any type, works.
|
||||
$this->generateAliases();
|
||||
$edit = array(
|
||||
'delete[all_aliases]' => TRUE,
|
||||
'options[keep_custom_aliases]' => FALSE,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/delete_bulk', $edit, t('Delete aliases now!'));
|
||||
$this->assertText(t('All of your path aliases have been deleted.'));
|
||||
$this->assertUrl('admin/config/search/path/delete_bulk');
|
||||
|
||||
// Make sure that all of them are actually deleted.
|
||||
$aliases = \Drupal::database()->select('url_alias', 'ua')->fields('ua', array())->execute()->fetchAll();
|
||||
$this->assertEqual($aliases, array(), "All the aliases have been deleted.");
|
||||
|
||||
// 2. Test deleting only specific (entity type) aliases.
|
||||
$manager = $this->container->get('plugin.manager.alias_type');
|
||||
$pathauto_plugins = array('canonical_entities:node' => 'nodes', 'canonical_entities:taxonomy_term' => 'terms', 'canonical_entities:user' => 'accounts');
|
||||
foreach ($pathauto_plugins as $pathauto_plugin => $attribute) {
|
||||
$this->generateAliases();
|
||||
$edit = array(
|
||||
'delete[plugins][' . $pathauto_plugin . ']' => TRUE,
|
||||
'options[keep_custom_aliases]' => FALSE,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/delete_bulk', $edit, t('Delete aliases now!'));
|
||||
$alias_type = $manager->createInstance($pathauto_plugin);
|
||||
$this->assertRaw(t('All of your %label path aliases have been deleted.', array('%label' => $alias_type->getLabel())));
|
||||
// Check that the aliases were actually deleted.
|
||||
foreach ($this->{$attribute} as $entity) {
|
||||
$this->assertNoEntityAlias($entity);
|
||||
}
|
||||
|
||||
// Check that the other aliases are not deleted.
|
||||
foreach ($pathauto_plugins as $_pathauto_plugin => $_attribute) {
|
||||
// Skip the aliases that should be deleted.
|
||||
if ($_pathauto_plugin == $pathauto_plugin) {
|
||||
continue;
|
||||
}
|
||||
foreach ($this->{$_attribute} as $entity) {
|
||||
$this->assertEntityAliasExists($entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Test deleting automatically generated aliases only.
|
||||
$this->generateAliases();
|
||||
$edit = array(
|
||||
'delete[all_aliases]' => TRUE,
|
||||
'options[keep_custom_aliases]' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/config/search/path/delete_bulk', $edit, t('Delete aliases now!'));
|
||||
$this->assertText(t('All of your automatically generated path aliases have been deleted.'));
|
||||
$this->assertUrl('admin/config/search/path/delete_bulk');
|
||||
|
||||
// Make sure that only custom aliases and aliases with no information about
|
||||
// their state still exist.
|
||||
$aliases = \Drupal::database()->select('url_alias', 'ua')->fields('ua', ['source'])->execute()->fetchCol();
|
||||
$this->assertEqual($aliases, ['/node/101', '/node/104', '/node/105'], 'Custom aliases still exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to generate aliases.
|
||||
*/
|
||||
function generateAliases() {
|
||||
// Delete all aliases to avoid duplicated aliases. They will be recreated below.
|
||||
$this->deleteAllAliases();
|
||||
|
||||
// We generate a bunch of aliases for nodes, users and taxonomy terms. If
|
||||
// the entities are already created we just update them, otherwise we create
|
||||
// them.
|
||||
if (empty($this->nodes)) {
|
||||
// Create a large number of nodes (100+) to make sure that the batch code works.
|
||||
for ($i = 1; $i <= 105; $i++) {
|
||||
// Set the alias of two nodes manually.
|
||||
$settings = ($i > 103) ? ['path' => ['alias' => "/custom_alias_$i", 'pathauto' => PathautoState::SKIP]] : [];
|
||||
$node = $this->drupalCreateNode($settings);
|
||||
$this->nodes[$node->id()] = $node;
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach ($this->nodes as $node) {
|
||||
if ($node->id() > 103) {
|
||||
// The alias is set manually.
|
||||
$node->set('path', ['alias' => '/custom_alias_' . $node->id()]);
|
||||
}
|
||||
$node->save();
|
||||
}
|
||||
}
|
||||
// Delete information about the state of an alias to make sure that aliases
|
||||
// with no such data are left alone by default.
|
||||
\Drupal::keyValue('pathauto_state.node')->delete(101);
|
||||
|
||||
if (empty($this->accounts)) {
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$account = $this->drupalCreateUser();
|
||||
$this->accounts[$account->id()] = $account;
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach ($this->accounts as $id => $account) {
|
||||
$account->save();
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->terms)) {
|
||||
$vocabulary = $this->addVocabulary(array('name' => 'test vocabulary', 'vid' => 'test_vocabulary'));
|
||||
for ($i = 1; $i <= 5; $i++) {
|
||||
$term = $this->addTerm($vocabulary);
|
||||
$this->terms[$term->id()] = $term;
|
||||
}
|
||||
}
|
||||
else {
|
||||
foreach ($this->terms as $term) {
|
||||
$term->save();
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we have aliases for the entities.
|
||||
foreach (array('nodes', 'accounts', 'terms') as $attribute) {
|
||||
foreach ($this->{$attribute} as $entity) {
|
||||
$this->assertEntityAliasExists($entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
292
web/modules/contrib/pathauto/src/Tests/PathautoNodeWebTest.php
Normal file
292
web/modules/contrib/pathauto/src/Tests/PathautoNodeWebTest.php
Normal file
|
@ -0,0 +1,292 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
use Drupal\pathauto\Entity\PathautoPattern;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\pathauto\PathautoState;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests pathauto node UI integration.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoNodeWebTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'pathauto', 'views', 'taxonomy', 'pathauto_views_test');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
$this->drupalCreateContentType(array('type' => 'article'));
|
||||
|
||||
// Allow other modules to add additional permissions for the admin user.
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer nodes',
|
||||
'bypass node access',
|
||||
'access content overview',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->createPattern('node', '/content/[node:title]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests editing nodes with different settings.
|
||||
*/
|
||||
function testNodeEditing() {
|
||||
// Ensure that the Pathauto checkbox is checked by default on the node add form.
|
||||
$this->drupalGet('node/add/page');
|
||||
$this->assertFieldChecked('edit-path-0-pathauto');
|
||||
|
||||
// Create a node by saving the node form.
|
||||
$title = ' Testing: node title [';
|
||||
$automatic_alias = '/content/testing-node-title';
|
||||
$this->drupalPostForm(NULL, array('title[0][value]' => $title), t('Save and publish'));
|
||||
$node = $this->drupalGetNodeByTitle($title);
|
||||
|
||||
// Look for alias generated in the form.
|
||||
$this->drupalGet("node/{$node->id()}/edit");
|
||||
$this->assertFieldChecked('edit-path-0-pathauto');
|
||||
$this->assertFieldByName('path[0][alias]', $automatic_alias, 'Generated alias visible in the path alias field.');
|
||||
|
||||
// Check whether the alias actually works.
|
||||
$this->drupalGet($automatic_alias);
|
||||
$this->assertText($title, 'Node accessible through automatic alias.');
|
||||
|
||||
// Manually set the node's alias.
|
||||
$manual_alias = '/content/' . $node->id();
|
||||
$edit = array(
|
||||
'path[0][pathauto]' => FALSE,
|
||||
'path[0][alias]' => $manual_alias,
|
||||
);
|
||||
$this->drupalPostForm($node->toUrl('edit-form'), $edit, t('Save and keep published'));
|
||||
$this->assertText(t('@type @title has been updated.', array('@type' => 'page', '@title' => $title)));
|
||||
|
||||
// Check that the automatic alias checkbox is now unchecked by default.
|
||||
$this->drupalGet("node/{$node->id()}/edit");
|
||||
$this->assertNoFieldChecked('edit-path-0-pathauto');
|
||||
$this->assertFieldByName('path[0][alias]', $manual_alias);
|
||||
|
||||
// Submit the node form with the default values.
|
||||
$this->drupalPostForm(NULL, array('path[0][pathauto]' => FALSE), t('Save and keep published'));
|
||||
$this->assertText(t('@type @title has been updated.', array('@type' => 'page', '@title' => $title)));
|
||||
|
||||
// Test that the old (automatic) alias has been deleted and only accessible
|
||||
// through the new (manual) alias.
|
||||
$this->drupalGet($automatic_alias);
|
||||
$this->assertResponse(404, 'Node not accessible through automatic alias.');
|
||||
$this->drupalGet($manual_alias);
|
||||
$this->assertText($title, 'Node accessible through manual alias.');
|
||||
|
||||
// Test that the manual alias is not kept for new nodes when the pathauto
|
||||
// checkbox is ticked.
|
||||
$title = 'Automatic Title';
|
||||
$edit = array(
|
||||
'title[0][value]' => $title,
|
||||
'path[0][pathauto]' => TRUE,
|
||||
'path[0][alias]' => '/should-not-get-created',
|
||||
);
|
||||
$this->drupalPostForm('node/add/page', $edit, t('Save and publish'));
|
||||
$this->assertNoAliasExists(array('alias' => 'should-not-get-created'));
|
||||
$node = $this->drupalGetNodeByTitle($title);
|
||||
$this->assertEntityAlias($node, '/content/automatic-title');
|
||||
|
||||
// Remove the pattern for nodes, the pathauto checkbox should not be
|
||||
// displayed.
|
||||
$ids = \Drupal::entityQuery('pathauto_pattern')
|
||||
->condition('type', 'canonical_entities:node')
|
||||
->execute();
|
||||
foreach (PathautoPattern::loadMultiple($ids) as $pattern) {
|
||||
$pattern->delete();
|
||||
}
|
||||
|
||||
$this->drupalGet('node/add/article');
|
||||
$this->assertNoFieldById('edit-path-0-pathauto');
|
||||
$this->assertFieldByName('path[0][alias]', '');
|
||||
|
||||
$edit = array();
|
||||
$edit['title'] = 'My test article';
|
||||
$this->drupalCreateNode($edit);
|
||||
//$this->drupalPostForm(NULL, $edit, t('Save and keep published'));
|
||||
$node = $this->drupalGetNodeByTitle($edit['title']);
|
||||
|
||||
// Pathauto checkbox should still not exist.
|
||||
$this->drupalGet($node->toUrl('edit-form'));
|
||||
$this->assertNoFieldById('edit-path-0-pathauto');
|
||||
$this->assertFieldByName('path[0][alias]', '');
|
||||
$this->assertNoEntityAlias($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test node operations.
|
||||
*/
|
||||
function testNodeOperations() {
|
||||
$node1 = $this->drupalCreateNode(array('title' => 'node1'));
|
||||
$node2 = $this->drupalCreateNode(array('title' => 'node2'));
|
||||
|
||||
// Delete all current URL aliases.
|
||||
$this->deleteAllAliases();
|
||||
|
||||
$this->drupalGet('admin/content');
|
||||
|
||||
// Check which of the two nodes is first.
|
||||
if (strpos($this->getTextContent(), 'node1') < strpos($this->getTextContent(), 'node2')) {
|
||||
$index = 0;
|
||||
}
|
||||
else {
|
||||
$index = 1;
|
||||
}
|
||||
|
||||
$edit = array(
|
||||
'action' => 'pathauto_update_alias_node',
|
||||
'node_bulk_form[' . $index . ']' => TRUE,
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, t('Apply to selected items'));
|
||||
$this->assertText('Update URL alias was applied to 1 item.');
|
||||
|
||||
$this->assertEntityAlias($node1, '/content/' . $node1->getTitle());
|
||||
$this->assertEntityAlias($node2, '/node/' . $node2->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo Merge this with existing node test methods?
|
||||
*/
|
||||
public function testNodeState() {
|
||||
$nodeNoAliasUser = $this->drupalCreateUser(array('bypass node access'));
|
||||
$nodeAliasUser = $this->drupalCreateUser(array('bypass node access', 'create url aliases'));
|
||||
|
||||
$node = $this->drupalCreateNode(array(
|
||||
'title' => 'Node version one',
|
||||
'type' => 'page',
|
||||
'path' => array(
|
||||
'pathauto' => PathautoState::SKIP,
|
||||
),
|
||||
));
|
||||
|
||||
$this->assertNoEntityAlias($node);
|
||||
|
||||
// Set a manual path alias for the node.
|
||||
$node->path->alias = '/test-alias';
|
||||
$node->save();
|
||||
|
||||
// Ensure that the pathauto field was saved to the database.
|
||||
\Drupal::entityTypeManager()->getStorage('node')->resetCache();
|
||||
$node = Node::load($node->id());
|
||||
$this->assertIdentical($node->path->pathauto, PathautoState::SKIP);
|
||||
|
||||
// Ensure that the manual path alias was saved and an automatic alias was not generated.
|
||||
$this->assertEntityAlias($node, '/test-alias');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-one');
|
||||
|
||||
// Save the node as a user who does not have access to path fieldset.
|
||||
$this->drupalLogin($nodeNoAliasUser);
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->assertNoFieldByName('path[0][pathauto]');
|
||||
|
||||
$edit = array('title[0][value]' => 'Node version two');
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Basic page Node version two has been updated.');
|
||||
|
||||
$this->assertEntityAlias($node, '/test-alias');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-one');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-two');
|
||||
|
||||
// Load the edit node page and check that the Pathauto checkbox is unchecked.
|
||||
$this->drupalLogin($nodeAliasUser);
|
||||
$this->drupalGet('node/' . $node->id() . '/edit');
|
||||
$this->assertNoFieldChecked('edit-path-0-pathauto');
|
||||
|
||||
// Edit the manual alias and save the node.
|
||||
$edit = array(
|
||||
'title[0][value]' => 'Node version three',
|
||||
'path[0][alias]' => '/manually-edited-alias',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Basic page Node version three has been updated.');
|
||||
|
||||
$this->assertEntityAlias($node, '/manually-edited-alias');
|
||||
$this->assertNoEntityAliasExists($node, '/test-alias');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-one');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-two');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-three');
|
||||
|
||||
// Programatically save the node with an automatic alias.
|
||||
\Drupal::entityTypeManager()->getStorage('node')->resetCache();
|
||||
$node = Node::load($node->id());
|
||||
$node->path->pathauto = PathautoState::CREATE;
|
||||
$node->save();
|
||||
|
||||
// Ensure that the pathauto field was saved to the database.
|
||||
\Drupal::entityTypeManager()->getStorage('node')->resetCache();
|
||||
$node = Node::load($node->id());
|
||||
$this->assertIdentical($node->path->pathauto, PathautoState::CREATE);
|
||||
|
||||
$this->assertEntityAlias($node, '/content/node-version-three');
|
||||
$this->assertNoEntityAliasExists($node, '/manually-edited-alias');
|
||||
$this->assertNoEntityAliasExists($node, '/test-alias');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-one');
|
||||
$this->assertNoEntityAliasExists($node, '/content/node-version-two');
|
||||
|
||||
$node->delete();
|
||||
$this->assertNull(\Drupal::keyValue('pathauto_state.node')->get($node->id()), 'Pathauto state was deleted');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that nodes without a Pathauto pattern can set custom aliases.
|
||||
*/
|
||||
public function testCustomAliasWithoutPattern() {
|
||||
// First, delete all patterns to be sure that there will be no match.
|
||||
$entity_ids = \Drupal::entityQuery('pathauto_pattern')->execute();
|
||||
$entities = PathautoPattern::loadMultiple($entity_ids);
|
||||
foreach ($entities as $entity) {
|
||||
$entity->delete();
|
||||
}
|
||||
|
||||
// Next, create a node with a custom alias.
|
||||
$edit = [
|
||||
'title[0][value]' => 'Sample article',
|
||||
'path[0][alias]' => '/sample-article',
|
||||
];
|
||||
$this->drupalPostForm('node/add/article', $edit, t('Save and publish'));
|
||||
$this->assertText(t('article Sample article has been created.'));
|
||||
|
||||
// Test the alias.
|
||||
$this->assertAliasExists(array('alias' => '/sample-article'));
|
||||
$this->drupalGet('sample-article');
|
||||
$this->assertResponse(200, 'A node without a pattern can have a custom alias.');
|
||||
|
||||
// Now create a node through the API.
|
||||
$node = Node::create(['type' => 'article', 'title' => 'Sample article API', 'path' => ['alias' => '/sample-article-api']]);
|
||||
$node->save();
|
||||
|
||||
// Test the alias.
|
||||
$this->assertAliasExists(['alias' => '/sample-article-api']);
|
||||
$this->drupalGet('sample-article-api');
|
||||
$this->assertResponse(200);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\pathauto\PathautoGeneratorInterface;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests pathauto settings form.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoSettingsFormWebTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'pathauto');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* Form values that are set by default.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultFormValues = array(
|
||||
'verbose' => FALSE,
|
||||
'separator' => '-',
|
||||
'case' => '1',
|
||||
'max_length' => '100',
|
||||
'max_component_length' => '100',
|
||||
'update_action' => '2',
|
||||
'transliterate' => '1',
|
||||
'reduce_ascii' => FALSE,
|
||||
'ignore_words' => 'a, an, as, at, before, but, by, for, from, is, in, into, like, of, off, on, onto, per, since, than, the, this, that, to, up, via, with',
|
||||
);
|
||||
|
||||
/**
|
||||
* Punctuation form items with default values.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $defaultPunctuations = array(
|
||||
'punctuation[double_quotes]' => '0',
|
||||
'punctuation[quotes]' => '0',
|
||||
'punctuation[backtick]' => '0',
|
||||
'punctuation[comma]' => '0',
|
||||
'punctuation[period]' => '0',
|
||||
'punctuation[hyphen]' => '1',
|
||||
'punctuation[underscore]' => '0',
|
||||
'punctuation[colon]' => '0',
|
||||
'punctuation[semicolon]' => '0',
|
||||
'punctuation[pipe]' => '0',
|
||||
'punctuation[left_curly]' => '0',
|
||||
'punctuation[left_square]' => '0',
|
||||
'punctuation[right_curly]' => '0',
|
||||
'punctuation[right_square]' => '0',
|
||||
'punctuation[plus]' => '0',
|
||||
'punctuation[equal]' => '0',
|
||||
'punctuation[asterisk]' => '0',
|
||||
'punctuation[ampersand]' => '0',
|
||||
'punctuation[percent]' => '0',
|
||||
'punctuation[caret]' => '0',
|
||||
'punctuation[dollar]' => '0',
|
||||
'punctuation[hash]' => '0',
|
||||
'punctuation[exclamation]' => '0',
|
||||
'punctuation[tilde]' => '0',
|
||||
'punctuation[left_parenthesis]' => '0',
|
||||
'punctuation[right_parenthesis]' => '0',
|
||||
'punctuation[question_mark]' => '0',
|
||||
'punctuation[less_than]' => '0',
|
||||
'punctuation[greater_than]' => '0',
|
||||
'punctuation[slash]' => '0',
|
||||
'punctuation[back_slash]' => '0',
|
||||
);
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'article'));
|
||||
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'notify of path changes',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer nodes',
|
||||
'bypass node access',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
$this->createPattern('node', '/content/[node:title]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the default values are shown correctly in the form.
|
||||
*/
|
||||
function testDefaultFormValues() {
|
||||
$this->drupalGet('/admin/config/search/path/settings');
|
||||
$this->assertNoFieldChecked('edit-verbose');
|
||||
$this->assertField('edit-separator', $this->defaultFormValues['separator']);
|
||||
$this->assertFieldChecked('edit-case');
|
||||
$this->assertField('edit-max-length', $this->defaultFormValues['max_length']);
|
||||
$this->assertField('edit-max-component-length', $this->defaultFormValues['max_component_length']);
|
||||
$this->assertFieldChecked('edit-update-action-2');
|
||||
$this->assertFieldChecked('edit-transliterate');
|
||||
$this->assertNoFieldChecked('edit-reduce-ascii');
|
||||
$this->assertField('edit-ignore-words', $this->defaultFormValues['ignore_words']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the verbose option.
|
||||
*/
|
||||
function testVerboseOption() {
|
||||
$edit = array('verbose' => '1');
|
||||
$this->drupalPostForm('/admin/config/search/path/settings', $edit, t('Save configuration'));
|
||||
$this->assertText(t('The configuration options have been saved.'));
|
||||
$this->assertFieldChecked('edit-verbose');
|
||||
|
||||
$title = 'Verbose settings test';
|
||||
$this->drupalGet('/node/add/article');
|
||||
$this->assertFieldChecked('edit-path-0-pathauto');
|
||||
$this->drupalPostForm(NULL, array('title[0][value]' => $title), t('Save and publish'));
|
||||
$this->assertText('Created new alias /content/verbose-settings-test for');
|
||||
|
||||
$node = $this->drupalGetNodeByTitle($title);
|
||||
$this->drupalPostForm('/node/' . $node->id() . '/edit', array('title[0][value]' => 'Updated title'), t('Save and keep published'));
|
||||
$this->assertText('Created new alias /content/updated-title for');
|
||||
$this->assertText('replacing /content/verbose-settings-test.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests generating aliases with different settings.
|
||||
*/
|
||||
function testSettingsForm() {
|
||||
// Ensure the separator settings apply correctly.
|
||||
$this->checkAlias('My awesome content', '/content/my.awesome.content', array('separator' => '.'));
|
||||
|
||||
// Ensure the character case setting works correctly.
|
||||
// Leave case the same as source token values.
|
||||
$this->checkAlias('My awesome Content', '/content/My-awesome-Content', array('case' => FALSE));
|
||||
$this->checkAlias('Change Lower', '/content/change-lower', array('case' => '1'));
|
||||
|
||||
// Ensure the maximum alias length is working.
|
||||
$this->checkAlias('My awesome Content', '/content/my-awesome', array('max_length' => '23'));
|
||||
|
||||
// Ensure the maximum component length is working.
|
||||
$this->checkAlias('My awesome Content', '/content/my', array('max_component_length' => '2'));
|
||||
|
||||
// Ensure transliteration option is working.
|
||||
$this->checkAlias('è é àl ö äl ü', '/content/e-e-al-o-al-u', array('transliterate' => '1'));
|
||||
$this->checkAlias('è é àl äl ö ü', '/content/è-é-àl-äl-ö-ü', array('transliterate' => FALSE));
|
||||
|
||||
$ignore_words = 'a, new, very, should';
|
||||
$this->checkAlias('a very new alias to test', '/content/alias-to-test', array('ignore_words' => $ignore_words));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the punctuation setting form items.
|
||||
*/
|
||||
function testPunctuationSettings() {
|
||||
// Test the replacement of punctuations.
|
||||
$settings = [];
|
||||
foreach ($this->defaultPunctuations as $key => $punctuation) {
|
||||
$settings[$key] = PathautoGeneratorInterface::PUNCTUATION_REPLACE;
|
||||
}
|
||||
|
||||
$title = 'aa"b`c,d.e-f_g:h;i|j{k[l}m]n+o=p*q%r^s$t#u!v~w(x)y?z>1/2\3';
|
||||
$alias = '/content/aa-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z-1-2-3';
|
||||
$this->checkAlias($title, $alias, $settings);
|
||||
|
||||
// Test the removal of punctuations.
|
||||
$settings = [];
|
||||
foreach ($this->defaultPunctuations as $key => $punctuation) {
|
||||
$settings[$key] = PathautoGeneratorInterface::PUNCTUATION_REMOVE;
|
||||
}
|
||||
|
||||
$title = 'a"b`c,d.e-f_g:h;i|j{k[l}m]n+o=p*q%r^s$t#u!v~w(x)y?z>1/2\3';
|
||||
$alias = '/content/abcdefghijklmnopqrstuvwxyz123';
|
||||
$this->checkAlias($title, $alias, $settings);
|
||||
|
||||
// Keep all punctuations in alias.
|
||||
$settings = [];
|
||||
foreach ($this->defaultPunctuations as $key => $punctuation) {
|
||||
$settings[$key] = PathautoGeneratorInterface::PUNCTUATION_DO_NOTHING;
|
||||
}
|
||||
|
||||
$title = 'al"b`c,d.e-f_g:h;i|j{k[l}m]n+o=p*q%r^s$t#u!v~w(x)y?z>1/2\3';
|
||||
$alias = '/content/al"b`c,d.e-f_g:h;i|j{k[l}m]n+o=p*q%r^s$t#u!v~w(x)y?z>1/2\3';
|
||||
$this->checkAlias($title, $alias, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check the an aliases.
|
||||
*
|
||||
* @param string $title
|
||||
* The node title to build the aliases from.
|
||||
* @param string $alias
|
||||
* The expected alias.
|
||||
* @param array $settings
|
||||
* The form values the alias should be generated with.
|
||||
*/
|
||||
protected function checkAlias($title, $alias, $settings = array()) {
|
||||
// Submit the settings form.
|
||||
$edit = array_merge($this->defaultFormValues + $this->defaultPunctuations, $settings);
|
||||
$this->drupalPostForm('/admin/config/search/path/settings', $edit, t('Save configuration'));
|
||||
$this->assertText(t('The configuration options have been saved.'));
|
||||
|
||||
// If we do not clear the caches here, AliasCleaner will use its
|
||||
// cleanStringCache instance variable. Due to that the creation of aliases
|
||||
// with $this->createNode() will only work correctly on the first call.
|
||||
\Drupal::service('pathauto.generator')->resetCaches();
|
||||
|
||||
// Create a node and check if the settings applied.
|
||||
$node = $this->createNode(
|
||||
array(
|
||||
'title' => $title,
|
||||
'type' => 'article',
|
||||
)
|
||||
);
|
||||
|
||||
$this->drupalGet($alias);
|
||||
$this->assertResponse(200);
|
||||
$this->assertEntityAlias($node, $alias);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests pathauto taxonomy UI integration.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoTaxonomyWebTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('taxonomy', 'pathauto', 'views');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Allow other modules to add additional permissions for the admin user.
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer taxonomy',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->createPattern('taxonomy_term', '/[term:vocabulary]/[term:name]');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Basic functional testing of Pathauto with taxonomy terms.
|
||||
*/
|
||||
function testTermEditing() {
|
||||
$this->drupalGet('admin/structure');
|
||||
$this->drupalGet('admin/structure/taxonomy');
|
||||
|
||||
// Add vocabulary "tags".
|
||||
$vocabulary = $this->addVocabulary(array('name' => 'tags', 'vid' => 'tags'));
|
||||
|
||||
// Create term for testing.
|
||||
$name = 'Testing: term name [';
|
||||
$automatic_alias = '/tags/testing-term-name';
|
||||
$this->drupalPostForm('admin/structure/taxonomy/manage/tags/add', array('name[0][value]' => $name), 'Save');
|
||||
$name = trim($name);
|
||||
$this->assertText("Created new term $name.");
|
||||
$term = $this->drupalGetTermByName($name);
|
||||
|
||||
// Look for alias generated in the form.
|
||||
$this->drupalGet("taxonomy/term/{$term->id()}/edit");
|
||||
$this->assertFieldChecked('edit-path-0-pathauto');
|
||||
$this->assertFieldByName('path[0][alias]', $automatic_alias, 'Generated alias visible in the path alias field.');
|
||||
|
||||
// Check whether the alias actually works.
|
||||
$this->drupalGet($automatic_alias);
|
||||
$this->assertText($name, 'Term accessible through automatic alias.');
|
||||
|
||||
// Manually set the term's alias.
|
||||
$manual_alias = '/tags/' . $term->id();
|
||||
$edit = array(
|
||||
'path[0][pathauto]' => FALSE,
|
||||
'path[0][alias]' => $manual_alias,
|
||||
);
|
||||
$this->drupalPostForm("taxonomy/term/{$term->id()}/edit", $edit, t('Save'));
|
||||
$this->assertText("Updated term $name.");
|
||||
|
||||
// Check that the automatic alias checkbox is now unchecked by default.
|
||||
$this->drupalGet("taxonomy/term/{$term->id()}/edit");
|
||||
$this->assertNoFieldChecked('edit-path-0-pathauto');
|
||||
$this->assertFieldByName('path[0][alias]', $manual_alias);
|
||||
|
||||
// Submit the term form with the default values.
|
||||
$this->drupalPostForm(NULL, array('path[0][pathauto]' => FALSE), t('Save'));
|
||||
$this->assertText("Updated term $name.");
|
||||
|
||||
// Test that the old (automatic) alias has been deleted and only accessible
|
||||
// through the new (manual) alias.
|
||||
$this->drupalGet($automatic_alias);
|
||||
$this->assertResponse(404, 'Term not accessible through automatic alias.');
|
||||
$this->drupalGet($manual_alias);
|
||||
$this->assertText($name, 'Term accessible through manual alias.');
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\pathauto\Entity\PathautoPattern;
|
||||
use Drupal\pathauto\PathautoPatternInterface;
|
||||
use Drupal\taxonomy\VocabularyInterface;
|
||||
use Drupal\taxonomy\Entity\Vocabulary;
|
||||
use Drupal\taxonomy\Entity\Term;
|
||||
|
||||
/**
|
||||
* Helper test class with some added functions for testing.
|
||||
*/
|
||||
trait PathautoTestHelperTrait {
|
||||
|
||||
/**
|
||||
* Creates a pathauto pattern.
|
||||
*
|
||||
* @param string $entity_type_id
|
||||
* The entity type.
|
||||
* @param string $pattern
|
||||
* The path pattern.
|
||||
* @param int $weight
|
||||
* (optional) The pattern weight.
|
||||
*
|
||||
* @return \Drupal\pathauto\PathautoPatternInterface
|
||||
* The created pattern.
|
||||
*/
|
||||
protected function createPattern($entity_type_id, $pattern, $weight = 10) {
|
||||
$type = ($entity_type_id == 'forum') ? 'forum' : 'canonical_entities:' . $entity_type_id;
|
||||
|
||||
$pattern = PathautoPattern::create([
|
||||
'id' => Unicode::strtolower($this->randomMachineName()),
|
||||
'type' => $type,
|
||||
'pattern' => $pattern,
|
||||
'weight' => $weight,
|
||||
]);
|
||||
$pattern->save();
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bundle condition to a pathauto pattern.
|
||||
*
|
||||
* @param \Drupal\pathauto\PathautoPatternInterface $pattern
|
||||
* The pattern.
|
||||
* @param string $entity_type
|
||||
* The entity type ID.
|
||||
* @param string $bundle
|
||||
* The bundle
|
||||
*/
|
||||
protected function addBundleCondition(PathautoPatternInterface $pattern, $entity_type, $bundle) {
|
||||
$plugin_id = $entity_type == 'node' ? 'node_type' : 'entity_bundle:' . $entity_type;
|
||||
|
||||
$pattern->addSelectionCondition(
|
||||
[
|
||||
'id' => $plugin_id,
|
||||
'bundles' => [
|
||||
$bundle => $bundle,
|
||||
],
|
||||
'negate' => FALSE,
|
||||
'context_mapping' => [
|
||||
$entity_type => $entity_type,
|
||||
]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function assertToken($type, $object, $token, $expected) {
|
||||
$bubbleable_metadata = new BubbleableMetadata();
|
||||
$tokens = \Drupal::token()->generate($type, array($token => $token), array($type => $object), [], $bubbleable_metadata);
|
||||
$tokens += array($token => '');
|
||||
$this->assertIdentical($tokens[$token], $expected, t("Token value for [@type:@token] was '@actual', expected value '@expected'.", array('@type' => $type, '@token' => $token, '@actual' => $tokens[$token], '@expected' => $expected)));
|
||||
}
|
||||
|
||||
public function saveAlias($source, $alias, $langcode = Language::LANGCODE_NOT_SPECIFIED) {
|
||||
\Drupal::service('path.alias_storage')->delete(array('source' => $source, 'language', 'langcode' => $langcode));
|
||||
return \Drupal::service('path.alias_storage')->save($source, $alias, $langcode);
|
||||
}
|
||||
|
||||
public function saveEntityAlias(EntityInterface $entity, $alias, $langcode = NULL) {
|
||||
// By default, use the entity language.
|
||||
if (!$langcode) {
|
||||
$langcode = $entity->language()->getId();
|
||||
}
|
||||
return $this->saveAlias('/' . $entity->toUrl()->getInternalPath(), $alias, $langcode);
|
||||
}
|
||||
|
||||
public function assertEntityAlias(EntityInterface $entity, $expected_alias, $langcode = NULL) {
|
||||
// By default, use the entity language.
|
||||
if (!$langcode) {
|
||||
$langcode = $entity->language()->getId();
|
||||
}
|
||||
$this->assertAlias('/' . $entity->toUrl()->getInternalPath(), $expected_alias, $langcode);
|
||||
}
|
||||
|
||||
public function assertEntityAliasExists(EntityInterface $entity) {
|
||||
return $this->assertAliasExists(array('source' => '/' . $entity->toUrl()->getInternalPath()));
|
||||
}
|
||||
|
||||
public function assertNoEntityAlias(EntityInterface $entity, $langcode = NULL) {
|
||||
// By default, use the entity language.
|
||||
if (!$langcode) {
|
||||
$langcode = $entity->language()->getId();
|
||||
}
|
||||
$this->assertEntityAlias($entity, '/' . $entity->toUrl()->getInternalPath(), $langcode);
|
||||
}
|
||||
|
||||
public function assertNoEntityAliasExists(EntityInterface $entity, $alias = NULL) {
|
||||
$path = array('source' => '/' . $entity->toUrl()->getInternalPath());
|
||||
if (!empty($alias)) {
|
||||
$path['alias'] = $alias;
|
||||
}
|
||||
$this->assertNoAliasExists($path);
|
||||
}
|
||||
|
||||
public function assertAlias($source, $expected_alias, $langcode = Language::LANGCODE_NOT_SPECIFIED) {
|
||||
\Drupal::service('path.alias_manager')->cacheClear($source);
|
||||
$this->assertEqual($expected_alias, \Drupal::service('path.alias_manager')->getAliasByPath($source, $langcode), t("Alias for %source with language '@language' is correct.",
|
||||
array('%source' => $source, '@language' => $langcode)));
|
||||
}
|
||||
|
||||
public function assertAliasExists($conditions) {
|
||||
$path = \Drupal::service('path.alias_storage')->load($conditions);
|
||||
$this->assertTrue($path, t('Alias with conditions @conditions found.', array('@conditions' => var_export($conditions, TRUE))));
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function assertNoAliasExists($conditions) {
|
||||
$alias = \Drupal::service('path.alias_storage')->load($conditions);
|
||||
$this->assertFalse($alias, t('Alias with conditions @conditions not found.', array('@conditions' => var_export($conditions, TRUE))));
|
||||
}
|
||||
|
||||
public function deleteAllAliases() {
|
||||
\Drupal::database()->delete('url_alias')->execute();
|
||||
\Drupal::service('path.alias_manager')->cacheClear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $values
|
||||
* @return \Drupal\taxonomy\VocabularyInterface
|
||||
*/
|
||||
public function addVocabulary(array $values = array()) {
|
||||
$name = Unicode::strtolower($this->randomMachineName(5));
|
||||
$values += array(
|
||||
'name' => $name,
|
||||
'vid' => $name,
|
||||
);
|
||||
$vocabulary = Vocabulary::create($values);
|
||||
$vocabulary->save();
|
||||
|
||||
return $vocabulary;
|
||||
}
|
||||
|
||||
public function addTerm(VocabularyInterface $vocabulary, array $values = array()) {
|
||||
$values += array(
|
||||
'name' => Unicode::strtolower($this->randomMachineName(5)),
|
||||
'vid' => $vocabulary->id(),
|
||||
);
|
||||
|
||||
$term = Term::create($values);
|
||||
$term->save();
|
||||
return $term;
|
||||
}
|
||||
|
||||
public function assertEntityPattern($entity_type, $bundle, $langcode = Language::LANGCODE_NOT_SPECIFIED, $expected) {
|
||||
|
||||
$values = [
|
||||
'langcode' => $langcode,
|
||||
\Drupal::entityTypeManager()->getDefinition($entity_type)->getKey('bundle') => $bundle,
|
||||
];
|
||||
$entity = \Drupal::entityTypeManager()->getStorage($entity_type)->create($values);
|
||||
|
||||
$pattern = \Drupal::service('pathauto.generator')->getPatternByEntity($entity);
|
||||
$this->assertIdentical($expected, $pattern->getPattern());
|
||||
}
|
||||
|
||||
public function drupalGetTermByName($name, $reset = FALSE) {
|
||||
if ($reset) {
|
||||
// @todo - implement cache reset.
|
||||
}
|
||||
$terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(array('name' => $name));
|
||||
return !empty($terms) ? reset($terms) : FALSE;
|
||||
}
|
||||
|
||||
}
|
189
web/modules/contrib/pathauto/src/Tests/PathautoUiTest.php
Normal file
189
web/modules/contrib/pathauto/src/Tests/PathautoUiTest.php
Normal file
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\pathauto\Entity\PathautoPattern;
|
||||
|
||||
/**
|
||||
* Test basic pathauto functionality.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoUiTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('pathauto', 'node');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
|
||||
$this->drupalCreateContentType(array('type' => 'article'));
|
||||
|
||||
// Allow other modules to add additional permissions for the admin user.
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer nodes',
|
||||
'bypass node access',
|
||||
'access content overview',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
function testSettingsValidation() {
|
||||
$edit = array();
|
||||
$edit['max_length'] = 'abc';
|
||||
$edit['max_component_length'] = 'abc';
|
||||
$this->drupalPostForm('admin/config/search/path/settings', $edit, 'Save configuration');
|
||||
/*$this->assertText('The field Maximum alias length is not a valid number.');
|
||||
$this->assertText('The field Maximum component length is not a valid number.');*/
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
$edit['max_length'] = '0';
|
||||
$edit['max_component_length'] = '0';
|
||||
$this->drupalPostForm('admin/config/search/path/settings', $edit, 'Save configuration');
|
||||
/*$this->assertText('The field Maximum alias length cannot be less than 1.');
|
||||
$this->assertText('The field Maximum component length cannot be less than 1.');*/
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
$edit['max_length'] = '999';
|
||||
$edit['max_component_length'] = '999';
|
||||
$this->drupalPostForm('admin/config/search/path/settings', $edit, 'Save configuration');
|
||||
/*$this->assertText('The field Maximum alias length cannot be greater than 255.');
|
||||
$this->assertText('The field Maximum component length cannot be greater than 255.');*/
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
$edit['max_length'] = '50';
|
||||
$edit['max_component_length'] = '50';
|
||||
$this->drupalPostForm('admin/config/search/path/settings', $edit, 'Save configuration');
|
||||
$this->assertText('The configuration options have been saved.');
|
||||
}
|
||||
|
||||
function testPatternsWorkflow() {
|
||||
// Try to save an empty pattern, should not be allowed.
|
||||
$this->drupalGet('admin/config/search/path/patterns/add');
|
||||
$edit = array(
|
||||
'type' => 'canonical_entities:node',
|
||||
);
|
||||
$this->drupalPostAjaxForm(NULL, $edit, 'type');
|
||||
$edit += array(
|
||||
'bundles[page]' => TRUE,
|
||||
'label' => 'Page pattern',
|
||||
'id' => 'page_pattern',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Path pattern field is required.');
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
// Try to save an invalid pattern.
|
||||
$edit += array(
|
||||
'pattern' => '[node:title]/[user:name]/[term:name]',
|
||||
);
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Path pattern is using the following invalid tokens: [user:name], [term:name].');
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
$edit['pattern'] = '#[node:title]';
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('The Path pattern is using the following invalid characters: #.');
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
// Checking whitespace ending of the string.
|
||||
$edit['pattern'] = '[node:title] ';
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('The Path pattern doesn\'t allow the patterns ending with whitespace.');
|
||||
$this->assertNoText('The configuration options have been saved.');
|
||||
|
||||
// Fix the pattern, then check that it gets saved successfully.
|
||||
$edit['pattern'] = '[node:title]';
|
||||
$this->drupalPostForm(NULL, $edit, 'Save');
|
||||
$this->assertText('Pattern Page pattern saved.');
|
||||
|
||||
\Drupal::service('pathauto.generator')->resetCaches();
|
||||
|
||||
// Create a node with pattern enabled and check if the pattern applies.
|
||||
$title = 'Page Pattern enabled';
|
||||
$alias = '/page-pattern-enabled';
|
||||
$node = $this->createNode(['title' => $title, 'type' => 'page']);
|
||||
$this->drupalGet($alias);
|
||||
$this->assertResponse(200);
|
||||
$this->assertEntityAlias($node, $alias);
|
||||
|
||||
// Edit workflow, set a new label and weight for the pattern.
|
||||
$this->drupalPostForm('/admin/config/search/path/patterns', ['entities[page_pattern][weight]' => '4'], t('Save'));
|
||||
$this->clickLink(t('Edit'));
|
||||
$this->assertUrl('/admin/config/search/path/patterns/page_pattern');
|
||||
$this->assertFieldByName('pattern', '[node:title]');
|
||||
$this->assertFieldByName('label', 'Page pattern');
|
||||
$this->assertFieldChecked('edit-status');
|
||||
$this->assertLink(t('Delete'));
|
||||
|
||||
$edit = array('label' => 'Test');
|
||||
$this->drupalPostForm('/admin/config/search/path/patterns/page_pattern', $edit, t('Save'));
|
||||
$this->assertText('Pattern Test saved.');
|
||||
// Check that the pattern weight did not change.
|
||||
$this->assertOptionSelected('edit-entities-page-pattern-weight', '4');
|
||||
|
||||
// Disable workflow.
|
||||
$this->drupalGet('/admin/config/search/path/patterns');
|
||||
$this->assertNoLink(t('Enable'));
|
||||
$this->clickLink(t('Disable'));
|
||||
$this->assertUrl('/admin/config/search/path/patterns/page_pattern/disable');
|
||||
$this->drupalPostForm(NULL, [], t('Disable'));
|
||||
$this->assertText('Disabled pattern Test.');
|
||||
|
||||
// Load the pattern from storage and check if its disabled.
|
||||
$pattern = PathautoPattern::load('page_pattern');
|
||||
$this->assertFalse($pattern->status());
|
||||
|
||||
\Drupal::service('pathauto.generator')->resetCaches();
|
||||
|
||||
// Create a node with pattern disabled and check that we have no new alias.
|
||||
$title = 'Page Pattern disabled';
|
||||
$node = $this->createNode(['title' => $title, 'type' => 'page']);
|
||||
$this->assertNoEntityAlias($node);
|
||||
|
||||
// Enable workflow.
|
||||
$this->drupalGet('/admin/config/search/path/patterns');
|
||||
$this->assertNoLink(t('Disable'));
|
||||
$this->clickLink(t('Enable'));
|
||||
$this->assertUrl('/admin/config/search/path/patterns/page_pattern/enable');
|
||||
$this->drupalPostForm(NULL, [], t('Enable'));
|
||||
$this->assertText('Enabled pattern Test.');
|
||||
|
||||
// Reload pattern from storage and check if its enabled.
|
||||
$pattern = PathautoPattern::load('page_pattern');
|
||||
$this->assertTrue($pattern->status());
|
||||
|
||||
// Delete workflow.
|
||||
$this->drupalGet('/admin/config/search/path/patterns');
|
||||
$this->clickLink(t('Delete'));
|
||||
$this->assertUrl('/admin/config/search/path/patterns/page_pattern/delete');
|
||||
$this->assertText(t('This action cannot be undone.'));
|
||||
$this->drupalPostForm(NULL, [], t('Delete'));
|
||||
$this->assertText('The pathauto pattern Test has been deleted.');
|
||||
|
||||
$this->assertFalse(PathautoPattern::load('page_pattern'));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto\Tests;
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
use Drupal\views\Views;
|
||||
|
||||
/**
|
||||
* Tests pathauto user UI integration.
|
||||
*
|
||||
* @group pathauto
|
||||
*/
|
||||
class PathautoUserWebTest extends WebTestBase {
|
||||
|
||||
use PathautoTestHelperTrait;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('pathauto', 'views');
|
||||
|
||||
/**
|
||||
* Admin user.
|
||||
*
|
||||
* @var \Drupal\user\UserInterface
|
||||
*/
|
||||
protected $adminUser;
|
||||
|
||||
/**
|
||||
* {inheritdoc}
|
||||
*/
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Allow other modules to add additional permissions for the admin user.
|
||||
$permissions = array(
|
||||
'administer pathauto',
|
||||
'administer url aliases',
|
||||
'create url aliases',
|
||||
'administer users',
|
||||
);
|
||||
$this->adminUser = $this->drupalCreateUser($permissions);
|
||||
$this->drupalLogin($this->adminUser);
|
||||
|
||||
$this->createPattern('user', '/users/[user:name]');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Basic functional testing of Pathauto with users.
|
||||
*/
|
||||
function testUserEditing() {
|
||||
// There should be no Pathauto checkbox on user forms.
|
||||
$this->drupalGet('user/' . $this->adminUser->id() . '/edit');
|
||||
$this->assertNoFieldById('path[0][pathauto]');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test user operations.
|
||||
*/
|
||||
function testUserOperations() {
|
||||
$account = $this->drupalCreateUser();
|
||||
|
||||
// Delete all current URL aliases.
|
||||
$this->deleteAllAliases();
|
||||
|
||||
// Find the position of just created account in the user_admin_people view.
|
||||
$view = Views::getView('user_admin_people');
|
||||
$view->initDisplay();
|
||||
$view->preview('page_1');
|
||||
|
||||
|
||||
foreach ($view->result as $key => $row) {
|
||||
if ($view->field['name']->getValue($row) == $account->getUsername()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$edit = array(
|
||||
'action' => 'pathauto_update_alias_user',
|
||||
"user_bulk_form[$key]" => TRUE,
|
||||
);
|
||||
$this->drupalPostForm('admin/people', $edit, t('Apply to selected items'));
|
||||
$this->assertText('Update URL alias was applied to 1 item.');
|
||||
|
||||
$this->assertEntityAlias($account, '/users/' . Unicode::strtolower($account->getUsername()));
|
||||
$this->assertEntityAlias($this->adminUser, '/user/' . $this->adminUser->id());
|
||||
}
|
||||
|
||||
}
|
63
web/modules/contrib/pathauto/src/VerboseMessenger.php
Normal file
63
web/modules/contrib/pathauto/src/VerboseMessenger.php
Normal file
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\pathauto;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Provides a verbose messenger.
|
||||
*/
|
||||
class VerboseMessenger implements MessengerInterface {
|
||||
|
||||
/**
|
||||
* The verbose flag.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $isVerbose;
|
||||
|
||||
/**
|
||||
* The config factory.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* The current user account.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* Creates a verbose messenger.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory, AccountInterface $account) {
|
||||
$this->configFactory = $config_factory;
|
||||
$this->account = $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addMessage($message, $op = NULL) {
|
||||
|
||||
if (!isset($this->isVerbose)) {
|
||||
$config = $this->configFactory->get('pathauto.settings');
|
||||
$this->isVerbose = $config->get('verbose') && $this->account->hasPermission('notify of path changes');
|
||||
}
|
||||
|
||||
if (!$this->isVerbose || (isset($op) && in_array($op, array('bulkupdate', 'return')))) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ($message) {
|
||||
drupal_set_message($message);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue