Problem/Motivation

Content Moderation stores what a workflow can be used on with entity type ID and bundle ID in the workflow config entity. By using the entity type ID as the bundle ID in the workflow config entity we can already make a workflow attach to an entity type with non-config bundles.

The issue lies in the updates made to entity types, the additional handlers, computed field, etc are only added to entity types with config bundles.

Proposed resolution

- Update EntityTypeInfo to add all additional information to all revisionable entity types.
- Add a test using the entity_test_rev test entity type.

Remaining tasks

Review the patch.

User interface changes

Nope.

API changes

Moderation can now be added to any revisionable entity type.

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

amateescu created an issue. See original summary.

amateescu’s picture

And here's the patch.

This is RC eligible per https://www.drupal.org/core/d8-allowed-changes#rc

The last submitted patch, 2: test-only.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 2: moderation-settings.patch, failed testing.

amateescu’s picture

Status: Needs work » Needs review
FileSize
73.06 KB
813 bytes

The test-only patch needs a bit more work because we have to test it "the old way" (without the ContentModerationSettings entity), but the real patch is ready for review.

dawehner’s picture

Issue tags: -rc eligible

rc eligible is just added by committers

IMHO in #2363155: content_translation.settings config is not scalable the point was that it also storing stuff per bundle/field, which we at least wouldn't do here :) But yeah, for example the fact that we can use config entities is a huge plus.

dawehner’s picture

Just some quick feedback.

  1. +++ b/core/modules/content_moderation/content_moderation.services.yml
    --- /dev/null
    +++ b/core/modules/content_moderation/src/ContentModerationSettingsException.php
    

    Can we put them into an exception folder?

  2. +++ b/core/modules/content_moderation/src/Entity/ContentModerationSettings.php
    @@ -0,0 +1,204 @@
    + *   list_cache_tags = { "rendered" }
    

    Any idea why this is added here?

  3. +++ b/core/modules/content_moderation/src/Entity/ContentModerationSettings.php
    @@ -0,0 +1,204 @@
    +  /**
    +   * The default moderation state for new content of the entity type bundle.
    +   *
    +   * @var array
    +   */
    +  protected $default_moderation_state;
    

    IMHO its hard to define multiple default states, I guess this is a string?

  4. +++ b/core/modules/content_moderation/src/Entity/ContentModerationSettings.php
    @@ -0,0 +1,204 @@
    +      $entity = self::create(['target_entity_type_id' => $entity_type_id, 'target_bundle' => $bundle]);
    

    Nitpick: let's use static::create

  5. +++ b/core/modules/content_moderation/src/Entity/ContentModerationSettings.php
    @@ -0,0 +1,204 @@
    +    // Create dependency on the target bundle.
    +    $entity_type = \Drupal::entityTypeManager()->getDefinition($this->target_entity_type_id);
    +    $bundle_config_dependency = $entity_type->getBundleConfigDependency($this->target_bundle);
    +    $this->addDependency($bundle_config_dependency['type'], $bundle_config_dependency['name']);
    +
    +    // Create dependencies on the the allowed moderation states. We don't need
    

    Does this code assumes that there is always a target bundle?

  6. +++ b/core/modules/content_moderation/src/EntityTypeInfo.php
    @@ -127,7 +136,7 @@ public function entityTypeAlter(array &$entity_types) {
    -  protected function addModerationToEntity(ContentEntityTypeInterface $type) {
    +  protected function addModerationToEntityType(ContentEntityTypeInterface $type) {
         if (!$type->hasHandlerClass('moderation')) {
           $handler_class = !empty($this->moderationHandlers[$type->id()]) ? $this->moderationHandlers[$type->id()] : ModerationHandler::class;
           $type->setHandlerClass('moderation', $handler_class);
    @@ -161,13 +170,13 @@ protected function addModerationToEntity(ContentEntityTypeInterface $type) {
    
    @@ -161,13 +170,13 @@ protected function addModerationToEntity(ContentEntityTypeInterface $type) {
        * @return \Drupal\Core\Config\Entity\ConfigEntityTypeInterface
        *   The modified config entity definition.
        */
    -  protected function addModerationToEntityType(ConfigEntityTypeInterface $type) {
    +  protected function addModerationToBundleEntityType(ConfigEntityTypeInterface $type) {
         if ($type->hasLinkTemplate('edit-form') && !$type->hasLinkTemplate('moderation-form')) {
           $type->setLinkTemplate('moderation-form', $type->getLinkTemplate('edit-form') . '/moderation');
         }
    

    These new method names are a bit weird, IMHO.

amateescu’s picture

Thanks for the review!

  1. Sure, why not.
  2. Overzealous copy paste on my part :)
  3. Hehe, indeed!
  4. Fixed.
  5. Yes, a target bundle is always there because the ID of the config entity is a compound of target_entity_type_id and target_bundle. It's even enforced in the entity constructor.
  6. Are you sure? The previous names were addModerationToEntity() and addModerationToEntityType(), but the first one was adding moderation support to a (content) entity type, not to an entity, and the second one is adding moderation support to a config entity type. IMO, the new names are much more clear about what they do :)

I tried again to write a test-only patch but I realized that's impossible to write because with the current code there's no place to store moderation settings for a bundle that's not a config object, so we'll have to live without a test-only patch for this bug.

dawehner’s picture

  1. +++ b/core/modules/content_moderation/src/Entity/ContentModerationSettings.php
    @@ -0,0 +1,203 @@
    +  public static function loadByEntityTypeBundle($entity_type_id, $bundle) {
    +    if ($entity_type_id == NULL || $bundle == NULL) {
    +      return NULL;
    +    }
    

    I know this is just c&p, but IMHO that's horrible code. We should throw an exception or something. If someone passes in invalid values, than getting back the wrong value is a bad idea.

  2. +++ b/core/modules/content_moderation/src/ModerationInformation.php
    @@ -34,6 +33,13 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) {
    +  public function getModerationSettings($entity_type_id, $bundle) {
    +    return ContentModerationSettings::loadByEntityTypeBundle($entity_type_id, $bundle);
    +  }
    

    I would actually turn that around. Write the proper method in the service and just call it from ContentModerationSettings for the lazy people out there.

  3. +++ b/core/modules/content_moderation/tests/src/Kernel/ModerationInformationTest.php
    @@ -0,0 +1,63 @@
    +    $this->assertEquals(FALSE, $moderation_information->isModeratedEntity($entity));
    ...
    +    $this->assertEquals(FALSE, $moderation_information->canModerateEntitiesOfEntityType($entity_type));
    ...
    +    $this->assertEquals(TRUE, $moderation_information->canModerateEntitiesOfEntityType($entity_type));
    ...
    +    $this->assertEquals(FALSE, $moderation_information->shouldModerateEntitiesOfBundle($entity_type, 'entity_test_rev'));
    ...
    +    $this->assertEquals(TRUE, $moderation_information->shouldModerateEntitiesOfBundle($entity_type, 'entity_test_rev'));
    ...
    +    $this->assertEquals(FALSE, $moderation_information->shouldModerateEntitiesOfBundle($entity_type, 'entity_test_rev'));
    

    Nitpick: Those cold all use $this->assertTrue/$this->assertFalse

  4. +++ b/core/modules/content_moderation/tests/src/Kernel/ViewsDataIntegrationTest.php
    deleted file mode 100644
    index 2b2e6f2..0000000
    
    index 2b2e6f2..0000000
    --- a/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php
    
    --- a/core/modules/content_moderation/tests/src/Unit/ModerationInformationTest.php
    +++ /dev/null
    
    +++ /dev/null
    +++ /dev/null
    @@ -1,124 +0,0 @@
    

    Is there a reason why this test got removed?

alexpott’s picture

Issue tags: +rc eligible

As content_moderation is an experimental module this is RC eligible. Looking at the patch - nice to see dependency calculations there already. Also given this is a new config entity it'd be nice to have this done before 8.2.0.

dawehner’s picture

In general this patch looks really sane.

amateescu’s picture

Re #9:

  1. Sure thing, fixed.
  2. Hm.. ok, why not :)
  3. Fixed.
  4. That unit test was changed into a kernel test: \Drupal\Tests\content_moderation\Kernel\ModerationInformationTest
dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you for the quick fixing

That unit test was changed into a kernel test: \Drupal\Tests\content_moderation\Kernel\ModerationInformationTest

Ah gotcha, I missed that.

alexpott’s picture

+++ b/core/modules/content_moderation/src/EntityTypeInfo.php
@@ -262,16 +271,10 @@ public function entityExtraFieldInfo() {
+    foreach (ContentModerationSettings::loadMultiple() as $moderation_settings) {

+++ b/core/modules/content_moderation/src/Form/BundleModerationSettingsForm.php
@@ -33,40 +55,44 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager) {
+    return ContentModerationSettings::loadByEntityTypeBundle($bundle->getEntityType()->getBundleOf(), $bundle->id());

Since this thing is injected I don't think we should be using statics. I think we should do this in a follow since making this change prior to the 8.2.0 is advantageous.

That said #2779647: Add a workflow component, ui module, and implement it in content moderation also gives me pause for thought because if we go down that route we might have no need for this either.

amateescu’s picture

Fixed those two places to not use statics anymore, it's a very simple change so leaving at RTBC.

That said #2779647: Add a workflow component, ui module, and implement it in content moderation also gives me pause for thought because if we go down that route we might have no need for this either.

We actually do have a need for a per-bundle object to store workflow settings, as mentioned in #2779647-5: Add a workflow component, ui module, and implement it in content moderation, so maybe we just need to make sure that the current name of ContentModerationSettings is good enough so we don't have to change it again in that issue :)

alexpott’s picture

@amateescu - we probably will need an object to store which workflow applies to which bundle. I'm not sure that the default should be on bundle. I think the default is a property of the workflow not the way the workflow is applied to the bundle.

joachim’s picture

> Move the per-bundle moderation settings to a new config entity type: ContentModerationSettings, since we already know that keeping all the settings in a single config object is not scalable

So sometimes settings about a bundle go in the bundle config entity, and sometimes they go elsewhere? That's kind of breaking our own system...

amateescu’s picture

@joachim, what do you mean? This issue/patch is about creating an object for storing moderation settings which also covers the case when bundles are not config entities.

joachim’s picture

Surely the case when bundles are not config entities breaks *all* systems that use third-party system to store settings in a config entity bundle. So does that mean that the third-party settings is now no longer to be used? If not, when should it be used and when should it not be used?

alexpott’s picture

Status: Reviewed & tested by the community » Postponed

Discussed with @amateescu and @berdir we agreed to do #2779647: Add a workflow component, ui module, and implement it in content moderation and use hook_entity_bundle_info_alter() which would mean that we would end up removing the config entity objects added here. So let's postpone this issue on that one and probably once that is completed we'll just mark this as a duplicate.

timmillwood’s picture

amateescu’s picture

We're looking into adding a test to content moderation for an entity type without config bundles in #2812811: Use EntityPublishedInterface during moderation of entities to add support beyond nodes, and if that turns out ok then we can close this one :)

timmillwood’s picture

Moving this firmly back to "needs work".

Specifically for altering \Drupal\content_moderation\EntityTypeInfo::filterNonRevisionableEntityTypes (http://cgit.drupalcode.org/drupal/tree/core/modules/content_moderation/s...) to not look for instances of ConfigEntityTypeInterface

timmillwood’s picture

Version: 8.2.x-dev » 8.3.x-dev
Status: Needs work » Needs review
Issue tags: -rc eligible
FileSize
2.6 KB
5.99 KB

Here's a little patch that changes Content Moderation to work with entity types without a config entity bundle.

timmillwood’s picture

With a simpler test which comes from the patch in #15.

The last submitted patch, 24: 2799785-24-test-only.patch, failed testing.

Sam152’s picture

Status: Needs review » Reviewed & tested by the community

This is great. Love to see CM becoming more flexible.

Gábor Hojtsy’s picture

IMHO this needs an issue summary update, it says "Move the per-bundle moderation settings to a new config entity type: ContentModerationSettings" but then it does not introduce a new entity type.

Sam152’s picture

Issue summary: View changes
Issue tags: -Needs issue summary update

Good call, done.

timmillwood’s picture

Issue summary: View changes
alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 82f1668 and pushed to 8.3.x. Thanks!

/me ponders when we're going to change the name to entity_moderation :)

  • alexpott committed 82f1668 on 8.3.x
    Issue #2799785 by amateescu, timmillwood, dawehner, alexpott: Entity...

Status: Fixed » Closed (fixed)

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

timmillwood’s picture