diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php index 37e5fb1aa87b..571b9914250a 100644 --- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php +++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityUpdater.php @@ -11,8 +11,11 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * * Use this in a post update function like so: * @code - * // Update the dependencies of all Vocabulary configuration entities. - * \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'taxonomy_vocabulary'); + * // Ensure Taxonomy module installed before trying to update vocabularies. + * if (\Drupal::moduleHandler()->moduleExists('taxonomy')) { + * // Update the dependencies of all Vocabulary configuration entities. + * \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'taxonomy_vocabulary'); + * } * @endcode * * The number of entities processed in each batch is determined by the @@ -65,6 +68,9 @@ class ConfigEntityUpdater implements ContainerInjectionInterface { * Stores information for batch updates. * @param string $entity_type_id * The configuration entity type ID. For example, 'view' or 'vocabulary'. + * The calling code should ensure that the entity type exists beforehand + * (i.e., by checking that the entity type is defined or that the module + * that provides it is installed). * @param callable $callback * (optional) A callback to determine if a configuration entity should be * saved. The callback will be passed each entity of the provided type that diff --git a/core/modules/block_content/block_content.post_update.php b/core/modules/block_content/block_content.post_update.php index daf5b0d4e44d..db7f50460cb8 100644 --- a/core/modules/block_content/block_content.post_update.php +++ b/core/modules/block_content/block_content.post_update.php @@ -12,6 +12,11 @@ use Drupal\Core\Entity\Sql\SqlContentEntityStorage; * Adds a 'reusable' filter to all Custom Block views. */ 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'); diff --git a/core/modules/block_content/tests/src/Functional/Update/BlockContentReusableUpdateTest.php b/core/modules/block_content/tests/src/Functional/Update/BlockContentReusableUpdateTest.php index fb261db70e0a..64eeadde57ad 100644 --- a/core/modules/block_content/tests/src/Functional/Update/BlockContentReusableUpdateTest.php +++ b/core/modules/block_content/tests/src/Functional/Update/BlockContentReusableUpdateTest.php @@ -150,4 +150,12 @@ class BlockContentReusableUpdateTest extends UpdatePathTestBase { $assert_session->statusCodeEquals('403'); } + /** + * Tests that the update succeeds even if Views is not installed. + */ + public function testReusableFieldAdditionWithoutViews() { + $this->container->get('module_installer')->uninstall(['views']); + $this->runUpdates(); + } + } diff --git a/core/modules/content_moderation/content_moderation.post_update.php b/core/modules/content_moderation/content_moderation.post_update.php index d5c2606cce6b..918238ea154f 100644 --- a/core/modules/content_moderation/content_moderation.post_update.php +++ b/core/modules/content_moderation/content_moderation.post_update.php @@ -175,6 +175,11 @@ function content_moderation_post_update_entity_display_dependencies(&$sandbox) { * 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; diff --git a/core/modules/content_moderation/tests/src/Functional/Update/ModerationStateViewsFieldUpdateTest.php b/core/modules/content_moderation/tests/src/Functional/Update/ModerationStateViewsFieldUpdateTest.php index 5fc5ac52dc7c..da961279e865 100644 --- a/core/modules/content_moderation/tests/src/Functional/Update/ModerationStateViewsFieldUpdateTest.php +++ b/core/modules/content_moderation/tests/src/Functional/Update/ModerationStateViewsFieldUpdateTest.php @@ -39,4 +39,12 @@ class ModerationStateViewsFieldUpdateTest extends UpdatePathTestBase { $this->assertEquals('moderation_state_field', $views_display['display_options']['fields']['moderation_state']['plugin_id']); } + /** + * Tests that the update succeeds even if Views is not installed. + */ + public function testViewsFieldIdUpdateWithoutViews() { + $this->container->get('module_installer')->uninstall(['views']); + $this->runUpdates(); + } + } diff --git a/core/modules/taxonomy/taxonomy.post_update.php b/core/modules/taxonomy/taxonomy.post_update.php index 5b98cce9480d..6b1c6bde0841 100644 --- a/core/modules/taxonomy/taxonomy.post_update.php +++ b/core/modules/taxonomy/taxonomy.post_update.php @@ -30,6 +30,11 @@ function taxonomy_post_update_clear_entity_bundle_field_definitions_cache() { * existing ones that were using the 'content_translation_status' field. */ function taxonomy_post_update_handle_publishing_status_addition_in_views(&$sandbox = NULL) { + // If Views is not installed, there is nothing to do. + if (!\Drupal::moduleHandler()->moduleExists('views')) { + return; + } + $definition_update_manager = \Drupal::entityDefinitionUpdateManager(); $entity_type = $definition_update_manager->getEntityType('taxonomy_term'); $published_key = $entity_type->getKey('published'); diff --git a/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php index 7a1dd357f04d..4d897715f347 100644 --- a/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php +++ b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php @@ -91,6 +91,22 @@ class TaxonomyTermUpdatePathTest extends UpdatePathTestBase { $this->assertEquals('Another message', (string) taxonomy_update_8601()); } + /** + * Tests taxonomy term views updates succeed even if Views is not installed. + */ + public function testPublishingStatusUpdateForTaxonomyTermViewsWithoutViews() { + // Uninstalling Views will trigger some activity in the menu tree storage + // system, which will cause errors until system_update_8001() is run. This + // is because, in the drupal-8.filled.standard database fixture used for + // this update test, the menu link titles are not serialized (this is what + // gets done by system_update_8001()). Since this method is not testing + // anything relating to menu links, it's OK to just truncate the menu_tree + // table before uninstalling Views. + $this->container->get('database')->truncate('menu_tree')->execute(); + $this->container->get('module_installer')->uninstall(['views']); + $this->runUpdates(); + } + /** * Tests handling of the publishing status in taxonomy term views updates. * diff --git a/core/modules/views/tests/src/Functional/Update/ExposedFilterBlocksUpdateTest.php b/core/modules/views/tests/src/Functional/Update/ExposedFilterBlocksUpdateTest.php index cd5e95446643..a9a952670f33 100644 --- a/core/modules/views/tests/src/Functional/Update/ExposedFilterBlocksUpdateTest.php +++ b/core/modules/views/tests/src/Functional/Update/ExposedFilterBlocksUpdateTest.php @@ -36,4 +36,18 @@ class ExposedFilterBlocksUpdateTest extends UpdatePathTestBase { $this->assertEquals('0', $config['label_display']); } + /** + * Tests that the update succeeds even if Block is not installed. + */ + public function testViewsPostUpdateExposedFilterBlocksWithoutBlock() { + // This block is created during the update process, but since we are + // uninstalling the Block module for this test, it will fail config schema + // validation. Since that's okay for the purposes of this test, just make + // the config schema checker ignore the block. + static::$configSchemaCheckerExclusions[] = 'block.block.seven_secondary_local_tasks'; + + $this->container->get('module_installer')->uninstall(['block']); + $this->runUpdates(); + } + } diff --git a/core/modules/views/views.post_update.php b/core/modules/views/views.post_update.php index fc6324146af1..496b55c3be9a 100644 --- a/core/modules/views/views.post_update.php +++ b/core/modules/views/views.post_update.php @@ -371,6 +371,11 @@ function views_post_update_table_display_cache_max_age(&$sandbox = NULL) { * Update exposed filter blocks label display to be disabled. */ function views_post_update_exposed_filter_blocks_label_display(&$sandbox = NULL) { + // If Block is not installed, there's nothing to do. + if (!\Drupal::moduleHandler()->moduleExists('block')) { + return; + } + \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'block', function ($block) { /** @var \Drupal\block\BlockInterface $block */ if (strpos($block->getPluginId(), 'views_exposed_filter_block:') === 0) {