pathauto.install 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. <?php
  2. /**
  3. * @file
  4. * Install, update, and uninstall functions for Pathauto.
  5. *
  6. * @ingroup pathauto
  7. */
  8. use Drupal\Core\Entity\Entity\EntityFormDisplay;
  9. use Drupal\Core\Plugin\Context\Context;
  10. use Drupal\Core\Plugin\Context\ContextDefinition;
  11. use Drupal\pathauto\Entity\PathautoPattern;
  12. /**
  13. * Implements hook_install().
  14. */
  15. function pathauto_install() {
  16. // Set the weight to 1
  17. module_set_weight('pathauto', 1);
  18. // Ensure the url_alias table exists.
  19. _pathauto_ensure_url_alias_table_exists();
  20. }
  21. /**
  22. * Helper function to ensure the url_alias table exists.
  23. *
  24. * Only necessary on Drupal 8.1.x.
  25. *
  26. * @see https://www.drupal.org/node/2704821
  27. */
  28. function _pathauto_ensure_url_alias_table_exists() {
  29. $alias_storage = \Drupal::service('path.alias_storage');
  30. if (method_exists($alias_storage, 'schemaDefinition')) {
  31. $database_schema = \Drupal::database()->schema();
  32. if (!$database_schema->tableExists($alias_storage::TABLE)) {
  33. $schema_definition = $alias_storage->schemaDefinition();
  34. $database_schema->createTable($alias_storage::TABLE, $schema_definition);
  35. }
  36. }
  37. }
  38. /**
  39. * Updates pathauto widgets to use the path widget ID.
  40. */
  41. function pathauto_update_8001() {
  42. // Replace values in the 'entity.definitions.installed' keyvalue collection.
  43. $collection = \Drupal::service('keyvalue')->get('entity.definitions.installed');
  44. foreach ($collection->getAll() as $key => $definitions) {
  45. if (!is_array($definitions) || empty($definitions['path'])) {
  46. continue;
  47. }
  48. // Retrieve and change path base field definition.
  49. $path_definition = $definitions['path'];
  50. if (($options = $path_definition->getDisplayOptions('form')) && $options['type'] = 'pathauto') {
  51. $options['type'] = 'path';
  52. $path_definition->setDisplayOptions('form', $options);
  53. // Save the new value.
  54. $collection->set($key, $definitions);
  55. }
  56. }
  57. foreach (EntityFormDisplay::loadMultiple() as $form_display) {
  58. if ($component = $form_display->getComponent('path')) {
  59. if (isset($component['type']) && $component['type'] == 'pathauto') {
  60. $component['type'] = 'path';
  61. $form_display->setComponent('path', $component);
  62. $form_display->save();
  63. }
  64. }
  65. }
  66. }
  67. /**
  68. * Converts patterns from configuration objects to configuration entities.
  69. */
  70. function pathauto_update_8100() {
  71. \Drupal::service('module_installer')->install(['ctools']);
  72. $messages = array();
  73. /** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info */
  74. $entity_bundle_info = \Drupal::service('entity_type.bundle.info');
  75. $entity_type_manager = \Drupal::entityTypeManager();
  76. $language_manager = \Drupal::languageManager();
  77. $entity_type_manager->clearCachedDefinitions();
  78. \Drupal::service('plugin.manager.alias_type')->clearCachedDefinitions();
  79. $entity_types = $entity_type_manager->getDefinitions();
  80. // 1. Load all patterns.
  81. $config = \Drupal::configFactory()->getEditable('pathauto.pattern');
  82. $patterns = $config->get('patterns');
  83. // 2. Create a configuration entity per pattern.
  84. foreach ($patterns as $entity_type => $entity_patterns) {
  85. if (!array_key_exists($entity_type, $entity_types)) {
  86. // We found an unknown entity type. Report it.
  87. $messages[] = t('Entity of type @type was not processed. It defines the following patterns: @patterns', array(
  88. '@type' => $entity_type,
  89. '@patterns' => print_r($entity_patterns, TRUE),
  90. ));
  91. continue;
  92. }
  93. $entity_label = $entity_types[$entity_type]->getLabel();
  94. if (!empty($entity_patterns['default'])) {
  95. // This is a pattern for an entity type, such as "node".
  96. $pattern = PathautoPattern::create([
  97. 'id' => $entity_type,
  98. 'label' => $entity_label,
  99. 'type' => 'canonical_entities:' . $entity_type,
  100. 'pattern' => $entity_patterns['default'],
  101. 'weight' => 0,
  102. ]);
  103. $pattern->save();
  104. }
  105. // Loop over bundles and create patterns if they have a value.
  106. // Bundle keys may have a language suffix for language-dependant patterns.
  107. if (isset($entity_patterns['bundles'])) {
  108. $bundle_info = $entity_bundle_info->getBundleInfo($entity_type);
  109. foreach ($entity_patterns['bundles'] as $bundle => $bundle_patterns) {
  110. if (empty($bundle_patterns['default'])) {
  111. // This bundle does not define a pattern. Move on to the next one.
  112. continue;
  113. }
  114. if (isset($bundle_info[$bundle])) {
  115. // This is a pattern for a bundle, such as "node_article".
  116. $pattern = PathautoPattern::create([
  117. 'id' => $entity_type . '_' . $bundle,
  118. 'label' => $entity_label . ' ' . $bundle_info[$bundle]['label'],
  119. 'type' => 'canonical_entities:' . $entity_type,
  120. 'pattern' => $bundle_patterns['default'],
  121. 'weight' => -5,
  122. ]);
  123. // Add the bundle condition.
  124. $pattern->addSelectionCondition([
  125. 'id' => 'entity_bundle:' . $entity_type,
  126. 'bundles' => array($bundle => $bundle),
  127. 'negate' => FALSE,
  128. 'context_mapping' => [ $entity_type => $entity_type ],
  129. ]);
  130. $pattern->save();
  131. }
  132. else {
  133. // This is either a language dependent pattern such as "article_es" or
  134. // an unknown bundle or langcode. Let's figure it out.
  135. $matches = NULL;
  136. $langcode = NULL;
  137. $extracted_bundle = NULL;
  138. $language = NULL;
  139. preg_match('/^(.*)_([a-z-]*)$/', $bundle, $matches);
  140. if (count($matches) == 3) {
  141. list(, $extracted_bundle, $langcode) = $matches;
  142. $language = $language_manager->getLanguage($langcode);
  143. }
  144. // Validate bundle, langcode and language.
  145. if (!isset($bundle_info[$extracted_bundle]) || ($langcode == NULL) || ($language == NULL)) {
  146. $messages[] = t('Unrecognized entity bundle @entity:@bundle was not processed. It defines the following patterns: @patterns', array(
  147. '@entity' => $entity_type,
  148. '@bundle' => $bundle,
  149. '@patterns' => print_r($entity_patterns, TRUE),
  150. ));
  151. continue;
  152. }
  153. // This is a pattern for a bundle and a language, such as "node_article_es".
  154. $pattern = PathautoPattern::create([
  155. 'id' => $entity_type . '_' . $extracted_bundle . '_' . str_replace('-', '_', $langcode),
  156. 'label' => $entity_label . ' ' . $bundle_info[$extracted_bundle]['label'] . ' ' . $language->getName(),
  157. 'type' => 'canonical_entities:' . $entity_type,
  158. 'pattern' => $bundle_patterns['default'],
  159. 'weight' => -10,
  160. ]);
  161. // Add the bundle condition.
  162. $pattern->addSelectionCondition([
  163. 'id' => 'entity_bundle:' . $entity_type,
  164. 'bundles' => array($extracted_bundle => $extracted_bundle),
  165. 'negate' => FALSE,
  166. 'context_mapping' => [ $entity_type => $entity_type ],
  167. ]);
  168. // Add the language condition.
  169. $language_mapping = $entity_type . ':' . $entity_type_manager->getDefinition($entity_type)->getKey('langcode') . ':language';
  170. $pattern->addSelectionCondition([
  171. 'id' => 'language',
  172. 'langcodes' => [ $langcode => $langcode ],
  173. 'negate' => FALSE,
  174. 'context_mapping' => [
  175. 'language' => $language_mapping,
  176. ]
  177. ]);
  178. // Add the context relationship for this language.
  179. $pattern->addRelationship($language_mapping, 'Language');
  180. $pattern->save();
  181. }
  182. }
  183. }
  184. }
  185. // 3. Delete the old configuration object that stores patterns.
  186. $config->delete();
  187. // 4. Print out messages.
  188. if (!empty($messages)) {
  189. return implode('</br>', $messages);
  190. }
  191. }
  192. /**
  193. * Update relationship storage.
  194. */
  195. function pathauto_update_8101() {
  196. foreach (\Drupal::configFactory()->listAll('pathauto.pattern.') as $pattern_config_name) {
  197. $pattern_config = \Drupal::configFactory()->getEditable($pattern_config_name);
  198. $relationships = [];
  199. foreach ((array) $pattern_config->get('context_definitions') as $context_definition) {
  200. $relationships[$context_definition['id']] = ['label' => $context_definition['label']];
  201. }
  202. $pattern_config->clear('context_definitions');
  203. $pattern_config->set('relationships', $relationships);
  204. $pattern_config->save();
  205. }
  206. }
  207. /**
  208. * Update node type conditions from entity_bundle to node_type.
  209. */
  210. function pathauto_update_8102() {
  211. // Load all pattern configuration entities.
  212. foreach (\Drupal::configFactory()->listAll('pathauto.pattern.') as $pattern_config_name) {
  213. $pattern_config = \Drupal::configFactory()->getEditable($pattern_config_name);
  214. // Loop patterns and swap the entity_bundle:node plugin by the node_type
  215. // plugin.
  216. if ($pattern_config->get('type') == 'canonical_entities:node') {
  217. $selection_criteria = $pattern_config->get('selection_criteria');
  218. foreach ($selection_criteria as $uuid => $condition) {
  219. if ($condition['id'] == 'entity_bundle:node') {
  220. $selection_criteria[$uuid]['id'] = 'node_type';
  221. $pattern_config->set('selection_criteria', $selection_criteria);
  222. $pattern_config->save();
  223. break;
  224. }
  225. }
  226. }
  227. }
  228. }
  229. /**
  230. * Fix invalid default value for ignore_words.
  231. */
  232. function pathauto_update_8103() {
  233. $config_factory = \Drupal::configFactory();
  234. $config = $config_factory->getEditable('pathauto.settings');
  235. $ignore_words = $config->get('ignore_words');
  236. if ($ignore_words === ', in, is,that, the , this, with, ') {
  237. $config->set('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')->save(TRUE);
  238. }
  239. }
  240. /**
  241. * Resave patterns so that lookup keys are updated.
  242. */
  243. function pathauto_update_8104() {
  244. \Drupal::entityTypeManager()->clearCachedDefinitions();
  245. // Load all pattern configuration entities and save them, so that the new
  246. // status lookup keys are saved.
  247. foreach (\Drupal::configFactory()->listAll('pathauto.pattern.') as $pattern_config_name) {
  248. $pattern_config = \Drupal::configFactory()->getEditable($pattern_config_name);
  249. $pattern_config->save();
  250. }
  251. }
  252. /**
  253. * Ensure the url_alias table exists.
  254. */
  255. function pathauto_update_8105() {
  256. _pathauto_ensure_url_alias_table_exists();
  257. }
  258. /**
  259. * Update default configuration for enabled entity types.
  260. */
  261. function pathauto_update_8106() {
  262. $config_factory = \Drupal::configFactory();
  263. $config = $config_factory->getEditable('pathauto.settings');
  264. $config->set('enabled_entity_types', ['user']);
  265. $config->save();
  266. }