Problem/Motivation

block_content.post_update.php has this code:

\Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'view', function ($view) use ($table) {
  // ...fun stuff!
});

The problem is that, if Views is not installed, this fails with an "undefined entity type" exception. The config entity updater assumes (and understandably so) that the entity type being updated, well, exists.

This bug also appears in other post-update functions in core:

  • taxonomy_post_update_handle_publishing_status_addition_in_views()
  • views_post_update_exposed_filter_blocks_label_display()
  • content_moderation_post_update_views_field_plugin_id()
  • ...others? (hopefully not)

I'm also nominating this rather embarrassing bug for backport to 8.7.x, since it is present there as well.

Proposed resolution

Post-update functions should validate their expectations prior to using the config entity updater.

Remaining tasks

Write a failing test and fix it, then document that ConfigEntityUpdater expects you to mind your P's and Q's before you use it.

User interface changes

None.

API changes

None.

Data model changes

None.

Release notes snippet

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

phenaproxima created an issue. See original summary.

phenaproxima’s picture

Status: Active » Needs review
FileSize
788 bytes

Here's a fail patch...I'm not sure what the proper fix would be.

phenaproxima’s picture

This is blocking work on Panelizer; see #3065652: Fix failing tests.

phenaproxima’s picture

Turns out that the Taxonomy module also suffers from this problem; see taxonomy_post_update_handle_publishing_status_addition_in_views(). It makes me wonder if we shouldn't fix this in ConfigEntityUpdater, rather than in the calling code.

If we don't fix it there, then I need to expand the scope of this issue because I can't get the test to pass unless I fix the problem everywhere it occurs (which is at least two places so far, but there could be others).

phenaproxima’s picture

Tagging for framework manager input.

Status: Needs review » Needs work

The last submitted patch, 2: 3065663-2-FAIL.patch, failed testing. View results

phenaproxima’s picture

Title: block_content post-update function fails hard without Views » Post-update functions in block_content and taxonomy hard without Views
Component: block_content.module » other
Status: Needs work » Needs review
Issue tags: -Needs framework manager review
FileSize
788 bytes
2.35 KB

This should look Christmas-ey.

I discussed this briefly with @alexpott on Slack and we decided that the fixes should be made in the update functions themselves, since "the update should handle its expectations". So, in order to get the test to pass, I had to fix the Taxonomy update function too. I'm re-titling this issue and changing the component, since this is no longer confined to the block_content module only.

phenaproxima’s picture

Title: Post-update functions in block_content and taxonomy hard without Views » Post-update functions in block_content and taxonomy fail hard without Views

Fixing the issue title.

alexpott’s picture

Status: Needs review » Needs work

Nice sleuthing @phenaproxima.

I'm not sure that ConfigEntityUpdater should check this because it's likely to hide other problems - for example an incorrect entity type ID. So I think we should do \Drupal::moduleHandler()->moduleExists() checks in the update hook.

So +1 on expanding the scope.

There's also:
content_moderation_post_update_views_field_plugin_id() - needs a views module check
views_post_update_exposed_filter_blocks_label_display() - needs a block module check

I think we should add some documentation to \Drupal\Core\Config\Entity\ConfigEntityUpdater() that it is the responsibility of the update hook to check that the entity type provider is installed. We could even add this to the example code.

phenaproxima’s picture

Title: Post-update functions in block_content and taxonomy fail hard without Views » Several post-update functions try to update config entity types that do not exist

Re-titling to take the content_moderation and views post-update hooks into account.

phenaproxima’s picture

Title: Several post-update functions try to update config entity types that do not exist » Several post-update functions try to update config entity types without checking if they exist

Fine-tuning that.

phenaproxima’s picture

Issue summary: View changes
phenaproxima’s picture

Status: Needs work » Needs review
FileSize
8.74 KB

OK, I think this will be green. I added tests for each of the offending post-update functions.

tim.plunkett’s picture

Component: other » configuration entity system

My first thought when reading this patch is that the moduleExists check is not exactly what we care about. More correct would be

if (!\Drupal::entityTypeManager()->getDefinition('view', FALSE)) {
 return;
}

Which then begs the question, why not move that check into ConfigEntityUpdater itself?

Status: Needs review » Needs work

The last submitted patch, 13: 3065663-13.patch, failed testing. View results

phenaproxima’s picture

Status: Needs work » Needs review
FileSize
9.11 KB
994 bytes

Okay, this should fix that one failure.

alexpott’s picture

re #14 my reasoning for going this way is because making the change in ConfigEntityUpdater makes the code susceptible to silent failure when you get the string identifier incorrect. #14 is the exact opposite of the direction already taken in the class which does...

      $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
      if (!($entity_type instanceof ConfigEntityTypeInterface)) {
        throw new \InvalidArgumentException("The provided entity type ID '$entity_type_id' is not a configuration entity type");
      }

This one is tricky... because both ways are can cause some annoyance. But I think failing when you get an ID incorrect is better.

Wim Leers’s picture

+++ b/core/modules/block_content/tests/src/Functional/Update/BlockContentReusableUpdateTest.php
@@ -150,4 +150,12 @@ public function testReusableFieldAddition() {
+  /**
+   * Tests that the update is bypassed if Views is not installed.
+   */
+  public function testReusableFieldAdditionWithoutViews() {
+    $this->container->get('module_installer')->uninstall(['views']);
+    $this->runUpdates();
+  }

How does this test that updates are bypassed?

amateescu’s picture

+++ b/core/modules/block_content/tests/src/Functional/Update/BlockContentReusableUpdateTest.php
@@ -150,4 +150,12 @@ public function testReusableFieldAddition() {
+   * Tests that the update is bypassed if Views is not installed.
+   */
+  public function testReusableFieldAdditionWithoutViews() {
+    $this->container->get('module_installer')->uninstall(['views']);
+    $this->runUpdates();

The only feedback I have is that this comment (and the others in similar places) is not really accurate. We're not testing that the update function is bypassed, we're just testing that it doesn't fail if the module/entity type is not available :)

At least to me, "bypassed" means that we'd have an assertion to check that the function was not executed at all, which is not the case here.

As for the module vs. entity type check discussion from #14 / #17, I can't say I have any preference, so I'll trust @alexpott's feeling :)

phenaproxima’s picture

amateescu’s picture

Status: Needs review » Reviewed & tested by the community

Much better! :D

  • larowlan committed 24d99ff on 8.8.x
    Issue #3065663 by phenaproxima, alexpott, amateescu, tim.plunkett, Wim...
larowlan’s picture

Version: 8.8.x-dev » 8.7.x-dev
Status: Reviewed & tested by the community » Patch (to be ported)

Committed 24d99ff and pushed to 8.8.x. Thanks!

Doesn't apply cleanly to 8.7.x

phenaproxima’s picture

phenaproxima’s picture

Status: Patch (to be ported) » Reviewed & tested by the community

Back to RTBC since this is a simple reroll.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 7ee5e1d and pushed to 8.7.x. Thanks!

  • alexpott committed 7ee5e1d on 8.7.x
    Issue #3065663 by phenaproxima, amateescu, alexpott, tim.plunkett, Wim...
alexpott’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.