Example #1
0
 /**
  * {@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));
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function cleanAlias($alias)
 {
     if (!isset($this->aliasMaxLength)) {
         $config = $this->configFactory->get('pathauto.settings');
         $this->aliasMaxLength = 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, $this->aliasMaxLength, TRUE);
     return $output;
 }
Example #3
0
 /**
  * {@inheritdoc}
  */
 public function isReserved($alias, $source, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED)
 {
     // First check whether the alias exists for another source.
     if ($this->aliasStorageHelper->exists($alias, $source, $langcode)) {
         return TRUE;
     }
     // 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;
 }
Example #4
0
 /**
  * {@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 PathautoManagerInterface::PUNCTUATION_REMOVE:
                     $cache['punctuation'][$details['value']] = '';
                     $this->cleanStringCache;
                 case PathautoManagerInterface::PUNCTUATION_REPLACE:
                     $this->cleanStringCache['punctuation'][$details['value']] = $this->cleanStringCache['separator'];
                     break;
                 case PathautoManagerInterface::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 createAlias($module, $op, $source, $data, $type = NULL, $langcode = LanguageInterface::LANGCODE_NOT_SPECIFIED)
 {
     $config = $this->configFactory->get('pathauto.settings');
     // Retrieve and apply the pattern for this content type.
     $pattern = $this->getPatternByEntity($module, $type, $langcode);
     // Allow other modules to alter the pattern.
     $context = array('module' => $module, 'op' => $op, 'source' => $source, 'data' => $data, 'type' => $type, 'language' => &$langcode);
     $this->moduleHandler->alter('pathauto_pattern', $pattern, $context);
     if (empty($pattern)) {
         // No pattern? Do nothing (otherwise we may blow away existing aliases...)
         return NULL;
     }
     // 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 PathautoManagerInterface::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, $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);
     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);
 }