Trash is not compatible with Content Moderation

Created on 10 November 2022, about 2 years ago
Updated 5 October 2023, about 1 year ago

Problem/Motivation

This module breaks when Content Moderation is installed and enabled for a bundle of an entity type for which Trash is also enabled. Specifically, the restore link in the trash view produces a 404 and an error message.

Steps to reproduce

  1. Install Drupal.
  2. Enable error messages with backtrace.
  3. Install Trash.
  4. Create an Article, then delete the Article.
  5. Go to the trash view and see the deleted Article.
  6. Click Restore for the article and see the restore confirmation form.
  7. Confirm the restoration.
  8. Install Content Moderation.
  9. Enable the default workflow for the Article content type.
  10. Delete the test article again.
  11. Go to the Trash view and click the Restore button, and get a 404 with the following error:
    Warning: array_flip(): Can only flip string and integer values, entry skipped in Drupal\Core\Entity\ContentEntityStorageBase->loadMultipleRevisions() (line 670 of core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php).
    Drupal\Core\Entity\ContentEntityStorageBase->loadMultipleRevisions(Array) (Line: 637)
    Drupal\Core\Entity\ContentEntityStorageBase->loadRevision(NULL) (Line: 295)
    Drupal\Core\Entity\EntityRepository->loadRevision(Object, NULL) (Line: 272)
    Drupal\Core\Entity\EntityRepository->getLatestTranslationAffectedRevision(Object, 'en') (Line: 156)
    Drupal\Core\Entity\EntityRepository->getActiveMultiple('node', Array, Array) (Line: 130)
    Drupal\Core\Entity\EntityRepository->getActive('node', '1') (Line: 123)
    Drupal\Core\ParamConverter\EntityConverter->convert('1', Array, 'node', Array) (Line: 100)
    Drupal\Core\ParamConverter\ParamConverterManager->convert(Array) (Line: 45)
    Drupal\Core\Routing\Enhancer\ParamConversionEnhancer->enhance(Array, Object) (Line: 256)
    Drupal\Core\Routing\Router->applyRouteEnhancers(Array, Object) (Line: 130)
    Drupal\Core\Routing\Router->matchRequest(Object) (Line: 93)
    Drupal\Core\Routing\AccessAwareRouter->matchRequest(Object) (Line: 112)
    Symfony\Component\HttpKernel\EventListener\RouterListener->onKernelRequest(Object, 'kernel.request', Object)
    call_user_func(Array, Object, 'kernel.request', Object) (Line: 142)
    Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'kernel.request') (Line: 135)
    Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
    Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
    Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
    Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
    Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
    Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
    Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
    Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
    Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
    Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Proposed resolution

TBD

Remaining tasks

Debug/figure out why/how Content Moderation causes the restore page to give a 404.

User interface changes

TBD

API changes

TBD

Data model changes

TBD

Feature request
Status

Active

Version

3.0

Component

Code

Created by

🇺🇸United States xaqrox Washington, D.C.

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • 🇺🇸United States SocialNicheGuru

    Any progress here? We are using content_moderation and would love to have the 'trash' option available.

  • 🇸🇪Sweden twod Sweden

    I am using Trash 3 with the patch from Translation support Needs review and Content Moderation without any issues like the one described here.
    Our node translations have independent moderation states and the patch also allows for [mostly] independent trash states. (Deleting the source translation marks all translations as deleted, and restoring a translation requires that the source translation has also been restored.)
    Any help reviewing that would be much appreviated. It may even be benificial if you don't need the actual translation support since your review could confirm that use case is still working, but it also improves revision handling.

    I do however have an unrelated issue with revisions at the moment that I'm looking into. Specifically it's when a View is based on say the node revision table instead of the main node table (or pulls in the node revision table). Trash gets a bit confused about which "deleted" field to check and uses the main table name in stead of the revision table name, breaking the query. If I get any further with that I'll post it as a separate issue.

  • 🇸🇪Sweden twod Sweden

    I based a relatively simple way to make Trash work nicer with Content Moderation based on Translation support Needs review as it already refactors entity operations - which should fix the issue in the OP - and it also refactors the storage trait to make this change easier.

    Essentially it check if you're trying to trash or restore a non-default revision. If so, it performs the same operation on the existing default revision as well. That way if you have a draft and delete the entity, the published revision will become inaccessible.
    If you then restore the entity it also restores the default revision along with the draft.
    Because it already uses $entity->isSyncing(TRUE), Content Moderation will not attempt to change which revision is the default, or force a new one to be created.

    It also decorates the moderation state validator to block any changes to the state while an entity is deleted.
    Not had time to write any automated tests for this yet, but it seems to even work well with Workspaces (Core often creates links to blocked forms but I think's that's more to do with issues like 🐛 Views entity operations lack cacheability support, resulting in incorrect dropbuttons Needs work and 🐛 Operations links on the translations overview page do not link to the correct route Needs work ).

    The PR against the translation branch makes it easier to see only the changes relevant here: https://git.drupalcode.org/issue/trash-3376216/-/merge_requests/1

  • 🇨🇳China lawxen

    Another revision(Content moderation) problem:
    Delete an node with revisons, the node is not in trash, but can't be visited

    Reproduced Steps:

    1. Jump to comment: Most recent, Add new
    2. Enable content moderation for node:article
    3. Create an article and publish it
    4. Create an draft for above node.
    5. Delete the the node by /node/{nid}/delete
    6. The node still in "/admin/content", not in "/admin/content/trash" but can't be viewed or edit
  • Merge request !20Compatibility with content_moderation module → (Open) created by twod
  • Pipeline finished with Failed
    10 months ago
    Total: 200s
    #99756
  • 🇦🇺Australia pameeela

    @xaqrox I can't reproduce this on a fresh install, tested both with content moderation enabled from the start, and then also with a new content type that initially didn't have moderation enabled. I'm still able to restore, so not sure if I am missing a step, or this has been resolved?

  • Pipeline finished with Success
    3 months ago
    Total: 368s
    #292570
  • Pipeline finished with Success
    3 months ago
    Total: 223s
    #293162
  • 🇸🇪Sweden twod Sweden

    Merged in latest changes to Translation support Needs review .

  • First commit to issue fork.
  • Status changed to Needs review 30 days ago
  • 🇷🇴Romania amateescu

    Since the MR is not really reviewable because it's created on top of another one, here's a patch with the actual changes proposed in this issue.

  • 🇷🇴Romania amateescu

    And a quick review:

    1. +++ b/src/TrashStorageTrait.php
      @@ -51,6 +51,17 @@ trait TrashStorageTrait {
      +          // Mark the default revision deleted, or it will remain accessible.
      +          $default = $this->getTrashManager()->executeInTrashContext('ignore', function () use ($entity) {
      

      This is very problematic in the context of Workspaces, because the current architecture of Trash provides the ability for editors to "stage" content deletions (!) in a workspace alongside other content changes.

      We'll have to come up with a different idea for Content Moderation integration, but I don't have a concrete proposal yet :/

    2. +++ b/trash.module
      @@ -377,3 +378,15 @@ function trash_configurable_language_insert(EntityInterface $entity) {
      +function trash_form_content_moderation_entity_moderation_form_alter(&$form, FormStateInterface $form_state, $form_id) {
      
      +++ b/trash.services.yml
      @@ -44,3 +44,8 @@ services:
      +  trash.state_transition_validation:
      

      Instead of decorating this service (+ a temporary form alter), I'm wondering whether we should decorate Drupal\content_moderation\ModerationInformation instead, and return FALSE in isModeratedEntity().

      It seems to me that would broaden the impact of this change to say "a deleted entity can not be moderated", and it should exclude it from all (or most?) moderation code paths.

Production build 0.71.5 2024