Commit 4c453683 authored by xjm's avatar xjm
Browse files

Issue #3106666 by catch, jungle, xjm, alexpott, tim.plunkett, Berdir: Remove...

Issue #3106666 by catch, jungle, xjm, alexpott, tim.plunkett, Berdir: Remove post updates added prior to 8.8.0
parent 05b122f2
......@@ -6,96 +6,12 @@
*/
/**
* Disable all blocks with missing context IDs in block_update_8001().
* Implements hook_removed_post_updates().
*/
function block_post_update_disable_blocks_with_missing_contexts() {
// Don't execute the function if block_update_8002() got executed already,
// which used to do the same. Note: Its okay to check here, because
// update_do_one() does not update the installed schema version until the
// batch is finished.
$module_schema = drupal_get_installed_schema_version('block');
// The state entry 'block_update_8002_placeholder' is used in order to
// indicate that the placeholder block_update_8002() function has been
// executed, so this function needs to be executed as well. If the non
// placeholder version of block_update_8002() got executed already, the state
// won't be set and we skip this update.
if ($module_schema >= 8002 && !\Drupal::state()->get('block_update_8002_placeholder', FALSE)) {
return;
}
// Cleanup the state entry as its no longer needed.
\Drupal::state()->delete('block_update_8002');
$block_update_8001 = \Drupal::keyValue('update_backup')->get('block_update_8001', []);
$block_ids = array_keys($block_update_8001);
$block_storage = \Drupal::entityTypeManager()->getStorage('block');
$blocks = $block_storage->loadMultiple($block_ids);
/** @var $blocks \Drupal\block\BlockInterface[] */
foreach ($blocks as $block) {
// This block has had conditions removed due to an inability to resolve
// contexts in block_update_8001() so disable it.
// Disable currently enabled blocks.
if ($block_update_8001[$block->id()]['status']) {
$block->setStatus(FALSE);
$block->save();
}
}
// Provides a list of plugin labels, keyed by plugin ID.
$condition_plugin_id_label_map = array_column(\Drupal::service('plugin.manager.condition')->getDefinitions(), 'label', 'id');
// Override with the UI labels we are aware of. Sadly they are not machine
// accessible, see
// \Drupal\node\Plugin\Condition\NodeType::buildConfigurationForm().
$condition_plugin_id_label_map['node_type'] = t('Content types');
$condition_plugin_id_label_map['request_path'] = t('Pages');
$condition_plugin_id_label_map['user_role'] = t('Roles');
if (count($block_ids) > 0) {
$message = t('Encountered an unknown context mapping key coming probably from a contributed or custom module: One or more mappings could not be updated. Please manually review your visibility settings for the following blocks, which are disabled now:');
$message .= '<ul>';
foreach ($blocks as $disabled_block_id => $disabled_block) {
$message .= '<li>' . t('@label (Visibility: @plugin_ids)', [
'@label' => $disabled_block->get('settings')['label'],
'@plugin_ids' => implode(', ', array_intersect_key($condition_plugin_id_label_map, array_flip(array_keys($block_update_8001[$disabled_block_id]['missing_context_ids'])))),
]) . '</li>';
}
$message .= '</ul>';
return $message;
}
}
/**
* Disable blocks that are placed into the "disabled" region.
*/
function block_post_update_disabled_region_update() {
// An empty update will flush caches, forcing block_rebuild() to run.
}
/**
* Fix invalid 'negate' values in block visibility conditions.
*/
function block_post_update_fix_negate_in_conditions() {
$block_storage = \Drupal::entityTypeManager()->getStorage('block');
/** @var \Drupal\block\BlockInterface[] $blocks */
$blocks = $block_storage->loadMultiple();
foreach ($blocks as $block) {
$block_needs_saving = FALSE;
// Check each visibility condition for an invalid negate value, and fix it.
foreach ($block->getVisibilityConditions() as $condition_id => $condition) {
$configuration = $condition->getConfiguration();
if (array_key_exists('negate', $configuration) && !is_bool($configuration['negate'])) {
$configuration['negate'] = (bool) $configuration['negate'];
$condition->setConfiguration($configuration);
$block_needs_saving = TRUE;
}
}
if ($block_needs_saving) {
$block->save();
}
}
function block_removed_post_updates() {
return [
'block_post_update_disable_blocks_with_missing_contexts' => '9.0.0',
'block_post_update_disabled_region_update' => '9.0.0',
'block_post_update_fix_negate_in_conditions' => '9.0.0',
];
}
......@@ -5,91 +5,11 @@
* Post update functions for Custom Block.
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
/**
* Adds a 'reusable' filter to all Custom Block views.
* Implements hook_removed_post_updates().
*/
function block_content_post_update_add_views_reusable_filter(&$sandbox = NULL) {
// If Views is not installed, there is nothing to do.
if (!\Drupal::moduleHandler()->moduleExists('views')) {
return;
}
$entity_type = \Drupal::entityTypeManager()->getDefinition('block_content');
$storage = \Drupal::entityTypeManager()->getStorage('block_content');
// If the storage class is an instance SqlContentEntityStorage we can use it
// to determine the table to use, otherwise we have to get the table from the
// entity type.
if ($storage instanceof SqlContentEntityStorage) {
$table = $entity_type->isTranslatable() ? $storage->getDataTable() : $storage->getBaseTable();
}
else {
$table = $entity_type->isTranslatable() ? $entity_type->getDataTable() : $entity_type->getBaseTable();
}
// If we were not able to get a table name we can not update the views.
if (empty($table)) {
return;
}
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($table) {
/** @var \Drupal\views\ViewEntityInterface $view */
if ($view->get('base_table') !== $table) {
return FALSE;
}
$save_view = FALSE;
$displays = $view->get('display');
foreach ($displays as $display_name => &$display) {
// Update the default display and displays that have overridden filters.
if (!isset($display['display_options']['filters']['reusable']) &&
($display_name === 'default' || isset($display['display_options']['filters']))) {
$display['display_options']['filters']['reusable'] = [
'id' => 'reusable',
'table' => $table,
'field' => 'reusable',
'relationship' => 'none',
'group_type' => 'group',
'admin_label' => '',
'operator' => '=',
'value' => '1',
'group' => 1,
'exposed' => FALSE,
'expose' => [
'operator_id' => '',
'label' => '',
'description' => '',
'use_operator' => FALSE,
'operator' => '',
'identifier' => '',
'required' => FALSE,
'remember' => FALSE,
'multiple' => FALSE,
],
'is_grouped' => FALSE,
'group_info' => [
'label' => '',
'description' => '',
'identifier' => '',
'optional' => TRUE,
'widget' => 'select',
'multiple' => FALSE,
'remember' => FALSE,
'default_group' => 'All',
'default_group_multiple' => [],
'group_items' => [],
],
'entity_type' => 'block_content',
'entity_field' => 'reusable',
'plugin_id' => 'boolean',
];
$save_view = TRUE;
}
}
if ($save_view) {
$view->set('display', $displays);
}
return $save_view;
});
function block_content_removed_post_updates() {
return [
'block_content_post_update_add_views_reusable_filter' => '9.0.0',
];
}
......@@ -5,44 +5,12 @@
* Post update functions for the comment module.
*/
use Drupal\Core\Config\FileStorage;
use Drupal\Core\Config\InstallStorage;
/**
* Enable the comment admin view.
*/
function comment_post_update_enable_comment_admin_view() {
$module_handler = \Drupal::moduleHandler();
$entity_type_manager = \Drupal::entityTypeManager();
// Save the comment delete action to config.
$config_install_path = $module_handler->getModule('comment')->getPath() . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
$storage = new FileStorage($config_install_path);
$entity_type_manager
->getStorage('action')
->create($storage->read('system.action.comment_delete_action'))
->save();
// Only create if the views module is enabled.
if (!$module_handler->moduleExists('views')) {
return;
}
// Save the comment admin view to config.
$optional_install_path = $module_handler->getModule('comment')->getPath() . '/' . InstallStorage::CONFIG_OPTIONAL_DIRECTORY;
$storage = new FileStorage($optional_install_path);
$entity_type_manager
->getStorage('view')
->create($storage->read('views.view.comment'))
->save();
}
/**
* Add comment settings.
* Implements hook_removed_post_updates().
*/
function comment_post_update_add_ip_address_setting() {
$config_factory = \Drupal::configFactory();
$settings = $config_factory->getEditable('comment.settings');
$settings->set('log_ip_addresses', TRUE)
->save(TRUE);
function comment_removed_post_updates() {
return [
'comment_post_update_enable_comment_admin_view' => '9.0.0',
'comment_post_update_add_ip_address_setting' => '9.0.0',
];
}
......@@ -5,17 +5,11 @@
* Post update functions for Contact.
*/
use Drupal\contact\Entity\ContactForm;
/**
* Initialize 'message' and 'redirect' field values to 'contact_form' entities.
* Implements hook_removed_post_updates().
*/
function contact_post_update_add_message_redirect_field_to_contact_form() {
/** @var \Drupal\contact\ContactFormInterface $contact */
foreach (ContactForm::loadMultiple() as $contact) {
$contact
->setMessage('Your message has been sent.')
->setRedirectPath('')
->save();
}
function contact_removed_post_updates() {
return [
'contact_post_update_add_message_redirect_field_to_contact_form' => '9.0.0',
];
}
......@@ -5,197 +5,15 @@
* 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.
* Implements hook_removed_post_updates().
*/
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;
});
}
/**
* Update the moderation state views field plugin ID.
*/
function content_moderation_post_update_views_field_plugin_id(&$sandbox) {
// If Views is not installed, there is nothing to do.
if (!\Drupal::moduleHandler()->moduleExists('views')) {
return;
}
\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) {
/** @var \Drupal\views\ViewEntityInterface $view */
$updated = FALSE;
$displays = $view->get('display');
foreach ($displays as &$display) {
if (empty($display['display_options']['fields'])) {
continue;
}
foreach ($display['display_options']['fields'] as &$display_field) {
if ($display_field['id'] === 'moderation_state' && $display_field['plugin_id'] === 'field') {
$display_field['plugin_id'] = 'moderation_state_field';
$updated = TRUE;
}
}
}
$view->set('display', $displays);
return $updated;
});
function content_moderation_removed_post_updates() {
return [
'content_moderation_post_update_update_cms_default_revisions' => '9.0.0',
'content_moderation_post_update_set_default_moderation_state' => '9.0.0',
'content_moderation_post_update_set_views_filter_latest_translation_affected_revision' => '9.0.0',
'content_moderation_post_update_entity_display_dependencies' => '9.0.0',
'content_moderation_post_update_views_field_plugin_id' => '9.0.0',
];
}
......@@ -6,9 +6,10 @@
*/
/**
* Ensure new page loads use the updated JS and get the updated markup.
* Implements hook_removed_post_updates().
*/
function contextual_post_update_fixed_endpoint_and_markup() {
// Empty update to trigger a change to css_js_query_string and invalidate
// cached markup.
function contextual_removed_post_updates() {
return [
'contextual_post_update_fixed_endpoint_and_markup' => '9.0.0',
];
}
......@@ -5,88 +5,12 @@
* Post-update functions for Datetime Range module.
*/
use Drupal\views\Views;
/**
* Clear caches to ensure schema changes are read.
*/
function datetime_range_post_update_translatable_separator() {
// Empty post-update hook to cause a cache rebuild.
}
/**
* Update existing views using datetime_range fields.
* Implements hook_removed_post_updates().
*/
function datetime_range_post_update_views_string_plugin_id() {
/* @var \Drupal\views\Entity\View[] $views */
$views = \Drupal::entityTypeManager()->getStorage('view')->loadMultiple();
$config_factory = \Drupal::configFactory();
$message = NULL;
$ids = [];
foreach ($views as $view) {
$displays = $view->get('display');
$needs_bc_layer_update = FALSE;
foreach ($displays as $display_name => $display) {
// Check if datetime_range filters need updates.
if (!$needs_bc_layer_update && isset($display['display_options']['filters'])) {
foreach ($display['display_options']['filters'] as $field_name => $filter) {
if ($filter['plugin_id'] == 'string') {
// Get field config.
$filter_views_data = Views::viewsData()->get($filter['table'])[$filter['field']]['filter'];
if (!isset($filter_views_data['entity_type']) || !isset($filter_views_data['field_name'])) {
continue;
}
$field_storage_name = 'field.storage.' . $filter_views_data['entity_type'] . '.' . $filter_views_data['field_name'];
$field_configuration = $config_factory->get($field_storage_name);
if ($field_configuration->get('type') == 'daterange') {
// Trigger the BC layer control.
$needs_bc_layer_update = TRUE;
continue 2;
}
}
}
}
// Check if datetime_range sort handlers need updates.
if (!$needs_bc_layer_update && isset($display['display_options']['sorts'])) {
foreach ($display['display_options']['sorts'] as $field_name => $sort) {
if ($sort['plugin_id'] == 'standard') {
// Get field config.
$sort_views_data = Views::viewsData()->get($sort['table'])[$sort['field']]['sort'];
if (!isset($sort_views_data['entity_type']) || !isset($sort_views_data['field_name'])) {
continue;
}
$field_storage_name = 'field.storage.' . $sort_views_data['entity_type'] . '.' . $sort_views_data['field_name'];
$field_configuration = $config_factory->get($field_storage_name);
if ($field_configuration->get('type') == 'daterange') {
// Trigger the BC layer control.
$needs_bc_layer_update = TRUE;
continue 2;
}
}
}
}
}
// If current view needs BC layer updates save it and the hook view_presave
// will do the rest.
if ($needs_bc_layer_update) {
$view->save();
$ids[] = $view->id();
}
}
if (!empty($ids)) {
$message = \Drupal::translation()->translate('Updated date