summaryrefslogtreecommitdiffstats
path: root/core/modules/content_moderation/content_moderation.post_update.php
blob: 3405fc28fe498c3542363784e173d0150ed11a19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<?php

/**
 * @file
 * Post update functions for the Content Moderation module.
 */

use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Site\Settings;
use Drupal\views\Entity\View;
use Drupal\workflows\Entity\Workflow;

/**
 * Synchronize moderation state default revisions with their host entities.
 */
function content_moderation_post_update_update_cms_default_revisions(&$sandbox) {
  // For every moderated entity, identify the default revision ID, track the
  // corresponding "content_moderation_state" revision and save it as the new
  // default revision, if needed.

  // Initialize sandbox info.
  $entity_type_id = &$sandbox['entity_type_id'];
  if (!isset($entity_type_id)) {
    $sandbox['bundles'] = [];
    $sandbox['entity_type_ids'] = [];
    /** @var \Drupal\workflows\WorkflowInterface $workflow */
    foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
      /** @var \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration $plugin */
      $plugin = $workflow->getTypePlugin();
      foreach ($plugin->getEntityTypes() as $entity_type_id) {
        $sandbox['entity_type_ids'][$entity_type_id] = $entity_type_id;
        foreach ($plugin->getBundlesForEntityType($entity_type_id) as $bundle) {
          $sandbox['bundles'][$entity_type_id][$bundle] = $bundle;
        }
      }
    }
    $sandbox['offset'] = 0;
    $sandbox['limit'] = Settings::get('entity_update_batch_size', 50);
    $sandbox['total'] = count($sandbox['entity_type_ids']);
    $entity_type_id = array_shift($sandbox['entity_type_ids']);
  }

  // If there are no moderated bundles or we processed all of them, we are done.
  $entity_type_manager = \Drupal::entityTypeManager();
  /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $content_moderation_state_storage */
  $content_moderation_state_storage = $entity_type_manager->getStorage('content_moderation_state');
  if (!$entity_type_id) {
    $content_moderation_state_storage->resetCache();
    $sandbox['#finished'] = 1;
    return;
  }

  // Retrieve a batch of moderated entities to be processed.
  $storage = $entity_type_manager->getStorage($entity_type_id);
  $entity_type = $entity_type_manager->getDefinition($entity_type_id);
  $query = $storage->getQuery()
    ->accessCheck(FALSE)
    ->sort($entity_type->getKey('id'))
    ->range($sandbox['offset'], $sandbox['limit']);
  $bundle_key = $entity_type->getKey('bundle');
  if ($bundle_key && !empty($sandbox['bundles'][$entity_type_id])) {
    $bundles = array_keys($sandbox['bundles'][$entity_type_id]);
    $query->condition($bundle_key, $bundles, 'IN');
  }
  $entity_ids = $query->execute();

  // Compute progress status and skip to the next entity type, if needed.
  $sandbox['#finished'] = ($sandbox['total'] - count($sandbox['entity_type_ids']) - 1) / $sandbox['total'];
  if (!$entity_ids) {
    $sandbox['offset'] = 0;
    $entity_type_id = array_shift($sandbox['entity_type_ids']) ?: FALSE;
    return;
  }

  // Load the "content_moderation_state" revisions corresponding to the
  // moderated entity default revisions.
  $result = $content_moderation_state_storage->getQuery()
    ->allRevisions()
    ->condition('content_entity_type_id', $entity_type_id)
    ->condition('content_entity_revision_id', array_keys($entity_ids), 'IN')
    ->execute();
  /** @var \Drupal\Core\Entity\ContentEntityInterface[] $revisions */
  $revisions = $content_moderation_state_storage->loadMultipleRevisions(array_keys($result));

  // Update "content_moderation_state" data.
  foreach ($revisions as $revision) {
    if (!$revision->isDefaultRevision()) {
      $revision->setNewRevision(FALSE);
      $revision->isDefaultRevision(TRUE);
      $content_moderation_state_storage->save($revision);
    }
  }

  // Clear static cache to avoid memory issues.
  $storage->resetCache($entity_ids);

  $sandbox['offset'] += $sandbox['limit'];
}

/**
 * Set the default moderation state for new content to 'draft'.
 */
function content_moderation_post_update_set_default_moderation_state(&$sandbox) {
  \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'workflow', function (Workflow $workflow) {
    if ($workflow->get('type') === 'content_moderation') {
      $configuration = $workflow->getTypePlugin()->getConfiguration();
      $configuration['default_moderation_state'] = 'draft';
      $workflow->getTypePlugin()->setConfiguration($configuration);
      return TRUE;
    }
    return FALSE;
  });
}

/**
 * Set the filter on the moderation view to be the latest translation affected.
 */
function content_moderation_post_update_set_views_filter_latest_translation_affected_revision(&$sandbox) {
  $original_plugin_name = 'latest_revision';
  $new_plugin_name = 'latest_translation_affected_revision';

  // Check that views is installed and the moderated content view exists.
  if (\Drupal::moduleHandler()->moduleExists('views') && $view = View::load('moderated_content')) {
    $display = &$view->getDisplay('default');
    if (!isset($display['display_options']['filters'][$original_plugin_name])) {
      return;
    }

    $translation_affected_filter = [
      'id' => $new_plugin_name,
      'field' => $new_plugin_name,
      'plugin_id' => $new_plugin_name,
    ] + $display['display_options']['filters'][$original_plugin_name];

    $display['display_options']['filters'] = [$new_plugin_name => $translation_affected_filter] + $display['display_options']['filters'];
    unset($display['display_options']['filters'][$original_plugin_name]);

    $view->save();
  }
}

/**
 * Update the dependencies of entity displays to include associated workflow.
 */
function content_moderation_post_update_entity_display_dependencies(&$sandbox) {
  /** @var \Drupal\content_moderation\ModerationInformationInterface $moderation_info */
  $moderation_info = \Drupal::service('content_moderation.moderation_information');
  /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
  $entity_type_manager = \Drupal::service('entity_type.manager');

  \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'entity_form_display', function (EntityFormDisplay $entity_form_display) use ($moderation_info, $entity_type_manager) {
    $associated_entity_type = $entity_type_manager->getDefinition($entity_form_display->getTargetEntityTypeId());

    if ($moderation_info->isModeratedEntityType($associated_entity_type)) {
      $entity_form_display->calculateDependencies();
      return TRUE;
    }
    elseif ($moderation_state_component = $entity_form_display->getComponent('moderation_state')) {
      // Remove the component from the entity form display, then manually delete
      // it from the hidden components list, completely purging it.
      $entity_form_display->removeComponent('moderation_state');
      $hidden_components = $entity_form_display->get('hidden');
      unset($hidden_components['moderation_state']);
      $entity_form_display->set('hidden', $hidden_components);
      $entity_form_display->calculateDependencies();
      return TRUE;
    }

    return FALSE;
  });
}