Problem/Motivation

  1. @hchonov pointed out in #2860097: Ensure that content translations can be moderated independently that adding load_latest_revision to routes is a BC break because it causes behavior to change, which would break modules making different use of forward revisions.
  2. Consequently, #2860097's patch was updated to not do this for Content Translation routes.
  3. But … #2865616: Add an option for EntityConverter to load the latest entity revision and fix all entity forms to use this option. (committed in November) updated \Drupal\Core\Entity\EntityResolverManager::setRouteOptions() to automatically set the load_latest_revision flag on all _entity_form routes for revisionable entity types. In other words: that is where the real root cause of @hchonov's concerns lies.

This is a problem, because it makes all _entity_form routes use this by default, meaning that the behavior is changed by default, and can only be opted out from. Instead, the behavior should remain unchanged by default and should be an opt-in thing.

Proposed resolution

  1. Do not set the load_latest_revision on all _entity_form routes by default.
  2. Let Content Moderation set the load_latest_revision flag on _entity_form routes. This means only installing Content Moderation introduces this behavior change automatically. (It needs this, and it used to originally live in Content Moderation too, until #2865616 made this the default behavior for all of core.)

Remaining tasks

  1. Implement the proposed resolution.
  2. Review.
  3. Discuss.

User interface changes

None.

API changes

None.

Data model changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Wim Leers created an issue. See original summary.

Wim Leers’s picture

Please credit @hchonov and @plach.

Wim Leers’s picture

Version: 8.6.x-dev » 8.5.x-dev
Sam152’s picture

plach’s picture

Status: Active » Needs review
FileSize
5.74 KB

Here's some initial work

Wim Leers’s picture

  1. +++ b/core/modules/content_moderation/src/Routing/ContentModerationRouteSubscriber.php
    @@ -0,0 +1,104 @@
    + * Subscriber for entity translation routes.
    

    s/translation/form/

    Or better yet:

    revisionable entity forms

  2. +++ b/core/modules/content_moderation/src/Routing/ContentModerationRouteSubscriber.php
    @@ -0,0 +1,104 @@
    +    $events[RoutingEvents::ALTER] = ['onAlterRoutes', 10];
    

    Why 10? Can't this be 0? If not, let's document why.

Status: Needs review » Needs work

The last submitted patch, 5: cm-latest_revision_flag_revert-2940899-5.patch, failed testing. View results

plach’s picture

Status: Needs review » Needs work

The last submitted patch, 8: cm-latest_revision_flag_revert-2940899-8.patch, failed testing. View results

plach’s picture

This should fix the last test failures by moving unit test coverage to a dedicated test.

Wim Leers’s picture

Status: Needs review » Needs work
  1. +++ b/core/modules/content_moderation/content_moderation.services.yml
    @@ -20,3 +20,8 @@ services:
    +  content_moderation.subscriber:
    +    class: Drupal\content_moderation\Routing\ContentModerationRouteSubscriber
    +    arguments: ['@entity_type.manager']
    
    +++ b/core/modules/content_moderation/src/Routing/ContentModerationRouteSubscriber.php
    @@ -0,0 +1,113 @@
    + * @internal
    

    The class is marked @internal, great. Can we also set public: false then?

  2. +++ b/core/modules/content_moderation/src/EntityOperations.php
    @@ -133,6 +146,9 @@ public function entityUpdate(EntityInterface $entity) {
    +    elseif ($entity instanceof Workflow && $entity->getTypePlugin()->getPluginId() == 'content_moderation') {
    +      $this->routerBuilder->rebuild();
    +    }
    

    So … whenever a Workflow entity is updated, we must rebuild routes.

    First: this should use ::setRebuildNeeded() AFAICT.

    Second: why do we even need to do this? Why is the route subscriber alone not enough? I think it's because the route subscriber only sets that load_latest_revision flag on entity types for which a Workflow entity exists that dictates a content_moderation-powered workflow, right? It is not trivial to connect those dots. It'd be good to have a @see \F\Q\C\N::getEntityTypes(), that'd help connect those dots.

  3. +++ b/core/modules/content_moderation/src/Routing/ContentModerationRouteSubscriber.php
    @@ -0,0 +1,113 @@
    + * Subscriber for revisionable entity forms.
    

    Still not accurate, apparently it's only for moderated revisionable entity forms?

  4. +++ b/core/modules/content_moderation/src/Routing/ContentModerationRouteSubscriber.php
    @@ -0,0 +1,113 @@
    +   * Returns the moderated entity types.
    ...
    +  protected function getEntityTypes() {
    

    getModeratedEntityTypes()

  5. +++ b/core/modules/content_moderation/tests/src/Unit/ContentModerationRouteSubscriberTest.php
    @@ -0,0 +1,219 @@
    +   * {@inheritdoc}
    +   *
    +   * @covers ::__construct
    

    This is highly unusual. A ::setUp() with a @covers. Is this really correct?

  6. +++ b/core/modules/content_moderation/tests/src/Unit/ContentModerationRouteSubscriberTest.php
    @@ -0,0 +1,219 @@
    +      'Multiple entity parameters on an entity form' => [
    

    Nice edge case, I didn't even realize this was possible!

  7. +++ b/core/modules/content_moderation/tests/src/Unit/ContentModerationRouteSubscriberTest.php
    @@ -0,0 +1,219 @@
    +      'Non-revisionable entity type will not change' => [
    

    Glad to see this edge case tested.

    But I'm not seeing test coverage for an entity form for a non-moderated entity type?

plach’s picture

This should address the review above.

Wim Leers’s picture

Status: Needs review » Needs work
+++ b/core/modules/content_moderation/tests/src/Unit/ContentModerationRouteSubscriberTest.php
@@ -110,6 +108,21 @@ public function setLatestRevisionFlagTestCases() {
+        [
+          'entity_test_mulrev' => [
+            'type' => 'entity:entity_test_mulrev',
+          ],
+        ],
+        [
+          'entity_test_mulrev' => [
+            'type' => 'entity:entity_test_mulrev',
+          ],
+        ],

We're testing that they're not affected. In other test cases where we're testing that a case is unaffected, we don't pass that final array, because it is the same. We should do the same here.

Other than that, this looks great.

plach’s picture

Addressed that, I also realized I was owing you a dots-connecting comment :)

Wim Leers’s picture

Status: Needs review » Reviewed & tested by the community

👍

effulgentsia’s picture

The patch looks great to me. +1 from me on committing this to 8.6 and 8.5. But why is this prioritized as Critical? Related to the priority question, is it important (with respect to known contrib modules) for this to land before beta, or would between beta and RC be ok? My preference would be before, since it's good to minimize behavior changes between beta and RC, but I'm not currently thinking of a reason that it would be hugely problematic to do it after.

I pinged other committers for their thoughts, and also posted #2865616-92: Add an option for EntityConverter to load the latest entity revision and fix all entity forms to use this option. to get feedback from the people who intentionally introduced the behavior that this is now proposes to partially undo.

effulgentsia’s picture

Crediting @hchonov per #2.

Wim Leers’s picture

But why is this prioritized as Critical?

Because without this landing before 8.5.0, we'll have shipped a behavior change and hence a BC break.

  • catch committed f51c227 on 8.6.x
    Issue #2940899 by plach, Wim Leers, hchonov: Regression: _entity_form...

  • catch committed e084a0d on 8.5.x
    Issue #2940899 by plach, Wim Leers, hchonov: Regression: _entity_form...
catch’s picture

Status: Reviewed & tested by the community » Fixed

Right. The bc break is allowable, but given we've decided we don't want to make it, we shouldn't ship it, then change it back again later.

Committed/pushed to 8.6.x and cherry-picked to 8.5.x. Thanks!

Status: Fixed » Closed (fixed)

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