Chris@14
|
1 <?php
|
Chris@14
|
2
|
Chris@14
|
3 /**
|
Chris@14
|
4 * @file
|
Chris@14
|
5 * Post update functions for the Content Moderation module.
|
Chris@14
|
6 */
|
Chris@14
|
7
|
Chris@18
|
8 use Drupal\Core\Config\Entity\ConfigEntityUpdater;
|
Chris@18
|
9 use Drupal\Core\Entity\Entity\EntityFormDisplay;
|
Chris@14
|
10 use Drupal\Core\Site\Settings;
|
Chris@18
|
11 use Drupal\views\Entity\View;
|
Chris@14
|
12 use Drupal\workflows\Entity\Workflow;
|
Chris@14
|
13
|
Chris@14
|
14 /**
|
Chris@14
|
15 * Synchronize moderation state default revisions with their host entities.
|
Chris@14
|
16 */
|
Chris@14
|
17 function content_moderation_post_update_update_cms_default_revisions(&$sandbox) {
|
Chris@14
|
18 // For every moderated entity, identify the default revision ID, track the
|
Chris@14
|
19 // corresponding "content_moderation_state" revision and save it as the new
|
Chris@14
|
20 // default revision, if needed.
|
Chris@14
|
21
|
Chris@14
|
22 // Initialize sandbox info.
|
Chris@14
|
23 $entity_type_id = &$sandbox['entity_type_id'];
|
Chris@14
|
24 if (!isset($entity_type_id)) {
|
Chris@14
|
25 $sandbox['bundles'] = [];
|
Chris@16
|
26 $sandbox['entity_type_ids'] = [];
|
Chris@14
|
27 /** @var \Drupal\workflows\WorkflowInterface $workflow */
|
Chris@14
|
28 foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
|
Chris@14
|
29 /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration $plugin */
|
Chris@14
|
30 $plugin = $workflow->getTypePlugin();
|
Chris@14
|
31 foreach ($plugin->getEntityTypes() as $entity_type_id) {
|
Chris@14
|
32 $sandbox['entity_type_ids'][$entity_type_id] = $entity_type_id;
|
Chris@14
|
33 foreach ($plugin->getBundlesForEntityType($entity_type_id) as $bundle) {
|
Chris@14
|
34 $sandbox['bundles'][$entity_type_id][$bundle] = $bundle;
|
Chris@14
|
35 }
|
Chris@14
|
36 }
|
Chris@14
|
37 }
|
Chris@14
|
38 $sandbox['offset'] = 0;
|
Chris@14
|
39 $sandbox['limit'] = Settings::get('entity_update_batch_size', 50);
|
Chris@14
|
40 $sandbox['total'] = count($sandbox['entity_type_ids']);
|
Chris@14
|
41 $entity_type_id = array_shift($sandbox['entity_type_ids']);
|
Chris@14
|
42 }
|
Chris@14
|
43
|
Chris@14
|
44 // If there are no moderated bundles or we processed all of them, we are done.
|
Chris@14
|
45 $entity_type_manager = \Drupal::entityTypeManager();
|
Chris@14
|
46 /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $content_moderation_state_storage */
|
Chris@14
|
47 $content_moderation_state_storage = $entity_type_manager->getStorage('content_moderation_state');
|
Chris@14
|
48 if (!$entity_type_id) {
|
Chris@14
|
49 $content_moderation_state_storage->resetCache();
|
Chris@14
|
50 $sandbox['#finished'] = 1;
|
Chris@14
|
51 return;
|
Chris@14
|
52 }
|
Chris@14
|
53
|
Chris@14
|
54 // Retrieve a batch of moderated entities to be processed.
|
Chris@14
|
55 $storage = $entity_type_manager->getStorage($entity_type_id);
|
Chris@14
|
56 $entity_type = $entity_type_manager->getDefinition($entity_type_id);
|
Chris@14
|
57 $query = $storage->getQuery()
|
Chris@14
|
58 ->accessCheck(FALSE)
|
Chris@14
|
59 ->sort($entity_type->getKey('id'))
|
Chris@14
|
60 ->range($sandbox['offset'], $sandbox['limit']);
|
Chris@14
|
61 $bundle_key = $entity_type->getKey('bundle');
|
Chris@14
|
62 if ($bundle_key && !empty($sandbox['bundles'][$entity_type_id])) {
|
Chris@14
|
63 $bundles = array_keys($sandbox['bundles'][$entity_type_id]);
|
Chris@14
|
64 $query->condition($bundle_key, $bundles, 'IN');
|
Chris@14
|
65 }
|
Chris@14
|
66 $entity_ids = $query->execute();
|
Chris@14
|
67
|
Chris@14
|
68 // Compute progress status and skip to the next entity type, if needed.
|
Chris@14
|
69 $sandbox['#finished'] = ($sandbox['total'] - count($sandbox['entity_type_ids']) - 1) / $sandbox['total'];
|
Chris@14
|
70 if (!$entity_ids) {
|
Chris@14
|
71 $sandbox['offset'] = 0;
|
Chris@14
|
72 $entity_type_id = array_shift($sandbox['entity_type_ids']) ?: FALSE;
|
Chris@14
|
73 return;
|
Chris@14
|
74 }
|
Chris@14
|
75
|
Chris@14
|
76 // Load the "content_moderation_state" revisions corresponding to the
|
Chris@14
|
77 // moderated entity default revisions.
|
Chris@14
|
78 $result = $content_moderation_state_storage->getQuery()
|
Chris@14
|
79 ->allRevisions()
|
Chris@14
|
80 ->condition('content_entity_type_id', $entity_type_id)
|
Chris@14
|
81 ->condition('content_entity_revision_id', array_keys($entity_ids), 'IN')
|
Chris@14
|
82 ->execute();
|
Chris@14
|
83 /** @var \Drupal\Core\Entity\ContentEntityInterface[] $revisions */
|
Chris@14
|
84 $revisions = $content_moderation_state_storage->loadMultipleRevisions(array_keys($result));
|
Chris@14
|
85
|
Chris@14
|
86 // Update "content_moderation_state" data.
|
Chris@14
|
87 foreach ($revisions as $revision) {
|
Chris@14
|
88 if (!$revision->isDefaultRevision()) {
|
Chris@14
|
89 $revision->setNewRevision(FALSE);
|
Chris@14
|
90 $revision->isDefaultRevision(TRUE);
|
Chris@14
|
91 $content_moderation_state_storage->save($revision);
|
Chris@14
|
92 }
|
Chris@14
|
93 }
|
Chris@14
|
94
|
Chris@14
|
95 // Clear static cache to avoid memory issues.
|
Chris@14
|
96 $storage->resetCache($entity_ids);
|
Chris@14
|
97
|
Chris@14
|
98 $sandbox['offset'] += $sandbox['limit'];
|
Chris@14
|
99 }
|
Chris@18
|
100
|
Chris@18
|
101 /**
|
Chris@18
|
102 * Set the default moderation state for new content to 'draft'.
|
Chris@18
|
103 */
|
Chris@18
|
104 function content_moderation_post_update_set_default_moderation_state(&$sandbox) {
|
Chris@18
|
105 \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'workflow', function (Workflow $workflow) {
|
Chris@18
|
106 if ($workflow->get('type') === 'content_moderation') {
|
Chris@18
|
107 $configuration = $workflow->getTypePlugin()->getConfiguration();
|
Chris@18
|
108 $configuration['default_moderation_state'] = 'draft';
|
Chris@18
|
109 $workflow->getTypePlugin()->setConfiguration($configuration);
|
Chris@18
|
110 return TRUE;
|
Chris@18
|
111 }
|
Chris@18
|
112 return FALSE;
|
Chris@18
|
113 });
|
Chris@18
|
114 }
|
Chris@18
|
115
|
Chris@18
|
116 /**
|
Chris@18
|
117 * Set the filter on the moderation view to be the latest translation affected.
|
Chris@18
|
118 */
|
Chris@18
|
119 function content_moderation_post_update_set_views_filter_latest_translation_affected_revision(&$sandbox) {
|
Chris@18
|
120 $original_plugin_name = 'latest_revision';
|
Chris@18
|
121 $new_plugin_name = 'latest_translation_affected_revision';
|
Chris@18
|
122
|
Chris@18
|
123 // Check that views is installed and the moderated content view exists.
|
Chris@18
|
124 if (\Drupal::moduleHandler()->moduleExists('views') && $view = View::load('moderated_content')) {
|
Chris@18
|
125 $display = &$view->getDisplay('default');
|
Chris@18
|
126 if (!isset($display['display_options']['filters'][$original_plugin_name])) {
|
Chris@18
|
127 return;
|
Chris@18
|
128 }
|
Chris@18
|
129
|
Chris@18
|
130 $translation_affected_filter = [
|
Chris@18
|
131 'id' => $new_plugin_name,
|
Chris@18
|
132 'field' => $new_plugin_name,
|
Chris@18
|
133 'plugin_id' => $new_plugin_name,
|
Chris@18
|
134 ] + $display['display_options']['filters'][$original_plugin_name];
|
Chris@18
|
135
|
Chris@18
|
136 $display['display_options']['filters'] = [$new_plugin_name => $translation_affected_filter] + $display['display_options']['filters'];
|
Chris@18
|
137 unset($display['display_options']['filters'][$original_plugin_name]);
|
Chris@18
|
138
|
Chris@18
|
139 $view->save();
|
Chris@18
|
140 }
|
Chris@18
|
141 }
|
Chris@18
|
142
|
Chris@18
|
143 /**
|
Chris@18
|
144 * Update the dependencies of entity displays to include associated workflow.
|
Chris@18
|
145 */
|
Chris@18
|
146 function content_moderation_post_update_entity_display_dependencies(&$sandbox) {
|
Chris@18
|
147 /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
|
Chris@18
|
148 $moderation_info = \Drupal::service('content_moderation.moderation_information');
|
Chris@18
|
149 /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
|
Chris@18
|
150 $entity_type_manager = \Drupal::service('entity_type.manager');
|
Chris@18
|
151
|
Chris@18
|
152 \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_form_display', function (EntityFormDisplay $entity_form_display) use ($moderation_info, $entity_type_manager) {
|
Chris@18
|
153 $associated_entity_type = $entity_type_manager->getDefinition($entity_form_display->getTargetEntityTypeId());
|
Chris@18
|
154
|
Chris@18
|
155 if ($moderation_info->isModeratedEntityType($associated_entity_type)) {
|
Chris@18
|
156 $entity_form_display->calculateDependencies();
|
Chris@18
|
157 return TRUE;
|
Chris@18
|
158 }
|
Chris@18
|
159 elseif ($moderation_state_component = $entity_form_display->getComponent('moderation_state')) {
|
Chris@18
|
160 // Remove the component from the entity form display, then manually delete
|
Chris@18
|
161 // it from the hidden components list, completely purging it.
|
Chris@18
|
162 $entity_form_display->removeComponent('moderation_state');
|
Chris@18
|
163 $hidden_components = $entity_form_display->get('hidden');
|
Chris@18
|
164 unset($hidden_components['moderation_state']);
|
Chris@18
|
165 $entity_form_display->set('hidden', $hidden_components);
|
Chris@18
|
166 $entity_form_display->calculateDependencies();
|
Chris@18
|
167 return TRUE;
|
Chris@18
|
168 }
|
Chris@18
|
169
|
Chris@18
|
170 return FALSE;
|
Chris@18
|
171 });
|
Chris@18
|
172 }
|