5 * Install, update, and uninstall functions for Pathauto.
10 use Drupal\Core\Entity\Entity\EntityFormDisplay;
11 use Drupal\pathauto\Entity\PathautoPattern;
14 * Implements hook_install().
16 function pathauto_install() {
17 // Set the weight to 1.
18 module_set_weight('pathauto', 1);
20 // Ensure the url_alias table exists.
21 _pathauto_ensure_url_alias_table_exists();
25 * Helper function to ensure the url_alias table exists.
27 * Only necessary on Drupal 8.1.x.
29 * @see https://www.drupal.org/node/2704821
31 function _pathauto_ensure_url_alias_table_exists() {
32 $alias_storage = \Drupal::service('path.alias_storage');
33 if (method_exists($alias_storage, 'schemaDefinition')) {
34 $database_schema = \Drupal::database()->schema();
35 if (!$database_schema->tableExists($alias_storage::TABLE)) {
36 $schema_definition = $alias_storage->schemaDefinition();
37 $database_schema->createTable($alias_storage::TABLE, $schema_definition);
43 * Updates pathauto widgets to use the path widget ID.
45 function pathauto_update_8001() {
47 // Replace values in the 'entity.definitions.installed' keyvalue collection.
48 $collection = \Drupal::service('keyvalue')->get('entity.definitions.installed');
49 foreach ($collection->getAll() as $key => $definitions) {
50 if (!is_array($definitions) || empty($definitions['path'])) {
54 // Retrieve and change path base field definition.
55 $path_definition = $definitions['path'];
56 if (($options = $path_definition->getDisplayOptions('form')) && $options['type'] = 'pathauto') {
57 $options['type'] = 'path';
58 $path_definition->setDisplayOptions('form', $options);
59 // Save the new value.
60 $collection->set($key, $definitions);
65 foreach (EntityFormDisplay::loadMultiple() as $form_display) {
66 if ($component = $form_display->getComponent('path')) {
67 if (isset($component['type']) && $component['type'] == 'pathauto') {
68 $component['type'] = 'path';
69 $form_display->setComponent('path', $component);
70 $form_display->save();
77 * Converts patterns from configuration objects to configuration entities.
79 function pathauto_update_8100() {
80 \Drupal::service('module_installer')->install(['ctools']);
83 /** @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_bundle_info */
84 $entity_bundle_info = \Drupal::service('entity_type.bundle.info');
85 $entity_type_manager = \Drupal::entityTypeManager();
86 $language_manager = \Drupal::languageManager();
87 $entity_type_manager->clearCachedDefinitions();
88 \Drupal::service('plugin.manager.alias_type')->clearCachedDefinitions();
89 $entity_types = $entity_type_manager->getDefinitions();
91 // 1. Load all patterns.
92 $config = \Drupal::configFactory()->getEditable('pathauto.pattern');
93 $patterns = $config->get('patterns');
95 // 2. Create a configuration entity per pattern.
96 foreach ($patterns as $entity_type => $entity_patterns) {
97 if (!array_key_exists($entity_type, $entity_types)) {
98 // We found an unknown entity type. Report it.
99 $messages[] = t('Entity of type @type was not processed. It defines the following patterns: @patterns', array(
100 '@type' => $entity_type,
101 '@patterns' => print_r($entity_patterns, TRUE),
105 $entity_label = $entity_types[$entity_type]->getLabel();
107 if (!empty($entity_patterns['default'])) {
108 // This is a pattern for an entity type, such as "node".
109 $pattern = PathautoPattern::create([
110 'id' => $entity_type,
111 'label' => $entity_label,
112 'type' => 'canonical_entities:' . $entity_type,
113 'pattern' => $entity_patterns['default'],
119 // Loop over bundles and create patterns if they have a value.
120 // Bundle keys may have a language suffix for language-dependant patterns.
121 if (isset($entity_patterns['bundles'])) {
122 $bundle_info = $entity_bundle_info->getBundleInfo($entity_type);
123 foreach ($entity_patterns['bundles'] as $bundle => $bundle_patterns) {
124 if (empty($bundle_patterns['default'])) {
125 // This bundle does not define a pattern. Move on to the next one.
129 if (isset($bundle_info[$bundle])) {
130 // This is a pattern for a bundle, such as "node_article".
131 $pattern = PathautoPattern::create([
132 'id' => $entity_type . '_' . $bundle,
133 'label' => $entity_label . ' ' . $bundle_info[$bundle]['label'],
134 'type' => 'canonical_entities:' . $entity_type,
135 'pattern' => $bundle_patterns['default'],
139 // Add the bundle condition.
140 $pattern->addSelectionCondition([
141 'id' => 'entity_bundle:' . $entity_type,
142 'bundles' => array($bundle => $bundle),
144 'context_mapping' => [ $entity_type => $entity_type ],
150 // This is either a language dependent pattern such as "article_es" or
151 // an unknown bundle or langcode. Let's figure it out.
154 $extracted_bundle = NULL;
156 preg_match('/^(.*)_([a-z-]*)$/', $bundle, $matches);
157 if (count($matches) == 3) {
158 list(, $extracted_bundle, $langcode) = $matches;
159 $language = $language_manager->getLanguage($langcode);
161 // Validate bundle, langcode and language.
162 if (!isset($bundle_info[$extracted_bundle]) || ($langcode == NULL) || ($language == NULL)) {
163 $messages[] = t('Unrecognized entity bundle @entity:@bundle was not processed. It defines the following patterns: @patterns', array(
164 '@entity' => $entity_type,
165 '@bundle' => $bundle,
166 '@patterns' => print_r($entity_patterns, TRUE),
171 // This is a pattern for a bundle and a language, such as
172 // "node_article_es".
173 $pattern = PathautoPattern::create([
174 'id' => $entity_type . '_' . $extracted_bundle . '_' . str_replace('-', '_', $langcode),
175 'label' => $entity_label . ' ' . $bundle_info[$extracted_bundle]['label'] . ' ' . $language->getName(),
176 'type' => 'canonical_entities:' . $entity_type,
177 'pattern' => $bundle_patterns['default'],
181 // Add the bundle condition.
182 $pattern->addSelectionCondition([
183 'id' => 'entity_bundle:' . $entity_type,
184 'bundles' => array($extracted_bundle => $extracted_bundle),
186 'context_mapping' => [ $entity_type => $entity_type ],
189 // Add the language condition.
190 $language_mapping = $entity_type . ':' . $entity_type_manager->getDefinition($entity_type)->getKey('langcode') . ':language';
191 $pattern->addSelectionCondition([
193 'langcodes' => [ $langcode => $langcode ],
195 'context_mapping' => [
196 'language' => $language_mapping,
200 // Add the context relationship for this language.
201 $pattern->addRelationship($language_mapping, 'Language');
209 // 3. Delete the old configuration object that stores patterns.
212 // 4. Print out messages.
213 if (!empty($messages)) {
214 return implode('</br>', $messages);
219 * Update relationship storage.
221 function pathauto_update_8101() {
222 foreach (\Drupal::configFactory()->listAll('pathauto.pattern.') as $pattern_config_name) {
223 $pattern_config = \Drupal::configFactory()->getEditable($pattern_config_name);
226 foreach ((array) $pattern_config->get('context_definitions') as $context_definition) {
227 $relationships[$context_definition['id']] = ['label' => $context_definition['label']];
230 $pattern_config->clear('context_definitions');
231 $pattern_config->set('relationships', $relationships);
232 $pattern_config->save();
237 * Update node type conditions from entity_bundle to node_type.
239 function pathauto_update_8102() {
240 // Load all pattern configuration entities.
241 foreach (\Drupal::configFactory()->listAll('pathauto.pattern.') as $pattern_config_name) {
242 $pattern_config = \Drupal::configFactory()->getEditable($pattern_config_name);
244 // Loop patterns and swap the entity_bundle:node plugin by the node_type
246 if ($pattern_config->get('type') == 'canonical_entities:node') {
247 $selection_criteria = $pattern_config->get('selection_criteria');
248 foreach ($selection_criteria as $uuid => $condition) {
249 if ($condition['id'] == 'entity_bundle:node') {
250 $selection_criteria[$uuid]['id'] = 'node_type';
251 $pattern_config->set('selection_criteria', $selection_criteria);
252 $pattern_config->save();
261 * Fix invalid default value for ignore_words.
263 function pathauto_update_8103() {
264 $config_factory = \Drupal::configFactory();
265 $config = $config_factory->getEditable('pathauto.settings');
266 $ignore_words = $config->get('ignore_words');
267 if ($ignore_words === ', in, is,that, the , this, with, ') {
268 $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);
273 * Resave patterns so that lookup keys are updated.
275 function pathauto_update_8104() {
276 \Drupal::entityTypeManager()->clearCachedDefinitions();
277 // Load all pattern configuration entities and save them, so that the new
278 // status lookup keys are saved.
279 foreach (\Drupal::configFactory()->listAll('pathauto.pattern.') as $pattern_config_name) {
280 $pattern_config = \Drupal::configFactory()->getEditable($pattern_config_name);
281 $pattern_config->save();
286 * Ensure the url_alias table exists.
288 function pathauto_update_8105() {
289 _pathauto_ensure_url_alias_table_exists();
293 * Update default configuration for enabled entity types.
295 function pathauto_update_8106() {
296 $config_factory = \Drupal::configFactory();
297 $config = $config_factory->getEditable('pathauto.settings');
298 $config->set('enabled_entity_types', ['user']);
303 * Initialize the new safe tokens setting.
305 function pathauto_update_8107() {
317 \Drupal::configFactory()->getEditable('pathauto.settings')
318 ->set('safe_tokens', $safe_tokens)