Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
Follow-up to #2779647: Add a workflow component, ui module, and implement it in content moderation.
\Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::calculateDependencies() needs to add dependencies on the entity type provider and the bundle configuration. It also needs to react to removal by just removing the entity type or bundle from the config.
Proposed resolution
Remaining tasks
User interface changes
None
API changes
Add WorkflowTypeInterface::onDependencyRemoval() to allow Workflow type plugins to respond to dependency removal.
Data model changes
New dependencies in Workflows
Comment | File | Size | Author |
---|---|---|---|
#57 | 2830581-57.patch | 12.42 KB | Sam152 |
#49 | 2830581-49.patch | 12.61 KB | alexpott |
#49 | 33-49-interdiff.txt | 5.12 KB | alexpott |
#49 | 2830581-test-only-49.patch | 12.61 KB | alexpott |
#49 | 33-49-interdiff.txt | 5.12 KB | alexpott |
Comments
Comment #2
alexpottComment #3
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedDidn't seem to be a plugin interface that also had onDependencyRemoval, considered extending DependentPluginInterface into RemovableDependentPluginInterface but decided it was also fine directly on the workflow type plugin interface.
Comment #4
alexpottSo nice how this works to add config or module dependencies depending if the entity has configurable bundles or not.
As these are negative assertions we should have the corresponding positive assertions before doing the delete and uninstall.
This is not necessary. Its handled in ConfigEntityBase::calculateDependencies(). Unfortunately there is no corollary for onDependencyRemoval(). There should be though because then onDependencyRemoval() wouldn't bleed into the WorkflowTypeBase. The ContentModeration workflow type could then implement it and it should just work :)
I think this needs a comment to say that the way this is constructed guarantees the parent is called regardless of
$changed
value. Otherwise someone might file a performance issue to put the cheap check first.Comment #5
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #6
alexpottThere is an issue about onDependencyRemoval() already #2579743: Config entities implementing EntityWithPluginCollectionInterface should ask the plugins to react when their dependencies are removed - there are a few complexities there.
Comment #7
alexpottJust a few more nits
Creates
Need to update the @return to document the fact that it'll return an empty array if the entity type is not managed by the workflow.
Not entirely sure this is necessary but there's no harm. So let's leave this here.
Tests
Comment #8
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #9
alexpott@Sam152 yeah you can only depend on config entities. Simple config is only dependent on the providing module and if you depend on the simple config you just depend on the module. There's no harm in it so let's get this important task done.
Comment #10
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedGood to know about depending on config entities only. FYI the patch in #8 doesn't include the instanceof check.
Comment #12
timmillwoodSimple re-roll to take into effect changes to ContentModerationStateTest.
Comment #13
timmillwoodSeeing as it was just a re-roll this can go straight to RTBC.
Comment #14
alexpottRemoved unused use.
The interdiff in #12 looks weird - odd spaces.
Comment #16
xjm(Posting a partial review and leaving RTBC for the moment since my internet connection is unreliable.)
So this change made me question why we would be looking up the bundles for an entity type that's not used for a workflow, or if there's a valid scenario for an entity type that is used for a workflow to have an empty list of bundles. The reason for my concern was that this is changing the method to silently return an empty array if the entity type ID is not valid. In HEAD, this method is only used within a foreach of
getEntityTypes()
so it is impossible that the entity type would not be valid. The method appliesToEntityTypeAndBundle() already exists, so it seemed to me that this API change was unnecessary. Instead, the calling code could just checkappliesToEntityTypeAndBundle()
before calling this method. @alexpott made the case that this API change makes the calling code more robust by always returning an array.I also wondered if a developer would instead expect an explicit failure (exception, FALSE return value, or whatever) from this method for an unsupported entity type. @alexpott pointed out that
\Drupal\field\Entity\FieldConfig::__construct()
(for example) doesn't validate that the bundle matches the entity type, so maybe the rest of core does not let developers expect such explicit failures.At the least, we need to change the one-line summary of the function to allow that it might not return any values (in addition to updating the parameter docs as the patch does). @alexpott and I came up with:
Still, it feels borderline out of scope to me to make this change/improvement here. In an ideal world I'd prefer that such an API improvement happen in a separate issue.
@alexpott also suggested that
appliesToEntityTypeAndBundle()
could be changed in a followup to be simpler and call this updated version ofgetBundlesForEntityType()
.Comment #17
alexpottI think the change to \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::getBundlesForEntityType() is fine - it is required because without this change the following code would produce a PHP warning:
It makes the code more resilient and I think behave as expected.
The patch attached updates the docs.
Comment #18
alexpottCreated #2850341: Improve \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::appliesToEntityTypeAndBundle() and ::getBundlesForEntityType() and #2850353: Test content_moderation with a non-bundleable content entity after discussions with @xjm
Comment #19
xjmNo, as we discussed, the method could instead check
appliesToEntityTypeAndBundle()
. That would use the existing API. If we want to change an API, we ideally should do so deliberately in a dedicated issue so that it is clear what the intent is, rather than it being a hack to make new code work. If it needs to happen beforehand, then that other issue can happen first.Comment #20
xjmI also asked alexpott if it was always expected that a workflow was applied to a specific bundle of an entity type, and whether workflows were supported for non-bundleable entity types, because there seem to be a lot of assumptions about bundles (both in the patch and in HEAD). At first @alexpott thought that non-bundleable entities were supported by content_moderation and even tested, but then realized #2799785: Entity types with non-config bundles can not be moderated actually added testing and support for bundles that were not backed by config entities. He said he was not sure that anyone had tried applying moderation workflows to non-bundleable entity types.
This made me wonder about this part of the dependency removal method:
This only removes bundles that are defined as the bundle providers for the removed config, and not bundles like those supported in #2799785: Entity types with non-config bundles can not be moderated. So how do we clean up the workflow config if a bundle that is not provided by a config entity goes away? Maybe core doesn't support that yet, but it seems #2799785: Entity types with non-config bundles can not be moderated tries to.
@alexpott suggested:
At the least, if we add information about non-config bundles to workflow config, we should confirm it's cleaned up on uninstall in a followup. I couldn't figure out how to test this manually with core.
I don't think we should try to fix that here, since I think it's a real edgecase and this issue fixes an actual data integrity bug in HEAD for everyone. But it might be another followup.
Comment #21
timmillwoodFrom manual tests moderation does work on entity types without a bundle, but there is no way to set them as moderated via the UI, because the UI lives in the bundle settings. #2843083: Select entity type / bundle in workflow settings is working to resolve this.
Comment #22
xjmThanks @timmillwood.
Maybe @amateescu can clarify/test in the as-yet unfiled potential followup whether this also successfully removes workflows for the non-config bundles he is using that led to posting #2799785: Entity types with non-config bundles can not be moderated, and if there are any cases where those non-config bundle definitions would go away other than module uninstallation.
Comment #23
xjm@alexpott and I agreed to split the (small) API change out from this into another issue. This one may be briefly postponed as we look at that. However, I'm in the process of manually testing some different scenarios for this patch so assigning this issue to myself while I do that.
Comment #24
xjm#2850341: Improve \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::appliesToEntityTypeAndBundle() and ::getBundlesForEntityType() is the new blocking issue.
Comment #25
xjmThe first scenario I tested:
With the patch applied, the workflow is correctly updated in step 6:
And, in step 9, the new article type is correctly created with no workflow pre-applied.
So far so good!
Comment #26
xjmForgot to mention in #25. The patch also fixes the config entity to actually include the dependency for the bundle.
In HEAD, after adding the moderation workflow to the article bundle
With patch
I also tested the patch with leaving the node module installed, but deleting the article type. It is fixed in the same way as #25. The expectations that the workflow will be updated are also correctly communicated in the UI after the patch, e.g.:
I then tested adding the same workflow to both page and article content type to ensure they could be added and removed independently and the config would be updated correctly. That also worked correctly, but I did notice a strange schema change in the process of testing this. By:
article
type.(Steps 1 and 2 may not be necessary to reproduce, but that is what I did.)
I got this diff:
Are those serial keys being exported accidentally? Are they weights? It feels like the weights should not be changed since I did not reorder anything, and if they are weights, shouldn't we always store them for a clean diff?
There are still some scenarios I haven't tested that I might (actually having content in these workflows, taxonomy, etc.), but setting NR for this last issue.
Comment #27
xjm(BTW the committer crediting bug appeared on this issue and alexpott is currently unintentionally uncredited. drumm wanted an example of this bug happening so not fixing that yet.)
Comment #28
xjmComment #29
xjm(drumm says it is okay to correct the credit.)
Comment #30
xjm#2850341: Improve \Drupal\content_moderation\Plugin\WorkflowType\ContentModeration::appliesToEntityTypeAndBundle() and ::getBundlesForEntityType() is in now so we can update this on top of it. Thanks @alexpott and @timmillwood for accommodating the scope fix.
Comment #31
xjmI just retested and found the bug from
#25#26 also happens before the patch, so not in scope here. It definitely seems like a bug somewhere in the config entity implementation though, so let's file a followup for it.Comment #32
xjmRegarding #22 about non-config bundles. In this diff:
The first part does not happen in HEAD, but the second part already does. The first part is only relevant for bundles defined via a config entity; the second is relevant for any. So hopefully this patch is also fine for those non-config-entity bundles too.
Edit: Except the second part does not happen on uninstallation in HEAD, only on installation. Right. So this patch should still also be fixing that for the non-config bundles as well. I think maybe it does? Edit 2: let's still file the followup for that as well, I guess, something like "Ensure non-configuration bundles are correctly removed when the bundles go away".
Comment #33
alexpottRerolled the patch.
Comment #34
alexpottFor #26 created #2850601: ContentModeration workflow type plugin incorrectly preserves bundle keys on sorting and does not sort entity types
Comment #35
xjmI wanted to test this for taxonomy terms (as the other core example of a config entity defining a bundle for a content entity) but could not apply a workflow to taxonomy terms through the UI. Is this because taxonomy terms are technically revisionable but not yet revisioned due to #2721313: Upgrade path between revisionable / non-revisionable entities being outstanding?
Comment #36
xjmOr maybe #35 is also fixed by #2843083: Select entity type / bundle in workflow settings. Edit: Looks like no; that issue is showing taxonomy in that UI with help from a contrib module. But it does make it clear that core does not support it yet, at least. Is there an existing issue for supporting content moderation for taxonomy etc. in core?
Comment #37
xjmAh, looks like I can maybe test it with content blocks? (I always forget about content blocks.)
Comment #38
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThe requirement right now is that entities are revisionable. This has sort of been floating around as a task on the radar, but without an issue. Opened #2850627: Do not require a revisionable entity type when using content_moderation..
Comment #39
xjmI tested with content blocks as well, and they also work fine in the same scenarios I tested above. E.g.:
Comment #40
xjmComment #41
amateescu CreditAttribution: amateescu for Pfizer, Inc. commentedFWIW, I don't have a specific use-case for moderating entities with non-config bundles. I was just reviewing a Content Moderation patch, saw that the settings were stored in config bundles and thought it's whack so I opened that issue and started to work on it :)
Comment #42
xjmRe: #41, thanks @amateescu! Based on that, @alexpott and I agreed to file a followup meta about the matrix of what entity type properties (revisionable, bundleable, publishable, etc.) the module does and doesn't support and ensuring validation, config management etc. is all robust, as we add support and testing. There is #2850627: Do not require a revisionable entity type when using content_moderation. already (added above) and a few other issues connected to this, but no overall discussion that I could find. The needs followup tag is on for that.
One thing I have gone back and forth about is whether we should improve the inline docs for these two methods to better explain what's happening in each case, since it's always so confusing to understand what's going on with entity types that define bundles for entity types etc. It took me a long time parsing code in my head and reading API docs to verify what each bit was doing, even though each one is only a few lines. I may post some suggestions for better docs (which can also be elucidating if I mis-explain what's happening) or someone else can if they like.
I also just tested to confirm that there are no circular dependencies -- no entity type configuration is harmed when a workflow is deleted. (I did find a different bug while testing that, but confirmed said bug is also in HEAD so I'll file it separately.)
Similarly, I tested that there aren't leaky dependencies from other things like fields and displays (which could cause data loss), by uninstalling the taxonomy module which futzes with articles, but not the bundle itself.
No other concerns from me at this point. I've tested several core scenarios and not sure I have the energy to do much more reinstallation and config exporting and diffing. ;) I do like to test config dependency patches thoroughly since they are so important for data integrity. A couple other scenarios someone could examine if they like, not blocking:
So really just the Multiversion one is worthwhile I guess.
Edit: putting my comment in a numbered list for readability.
Comment #43
xjmForgot to mention, the docs improvements I suggest in #42.2 could also be a followup since the code obviously works and someone who does know the entity system inside out can follow it. I realize it's vague "make it better" feedback. So nothing in #42 is really a hard blocker; we just need reviewer to do a final review of the latest patch and to make sure none of my feedback raises flags, and then there are followups.
Comment #44
xjmSorry, two more things I had in a note on my laptop from an airport:
I don't understand what this is doing or why it is needed, despite the comment.
I was surprised that this isn't provided by some generic interface since it seems like it's going to be the same for every config entity ever. Is there a similar example I can look at on a different core entity interface?
Comment #45
xjmAhh. Maybe #44.2 is already mentioned in #3 and covered by #2579743: Config entities implementing EntityWithPluginCollectionInterface should ask the plugins to react when their dependencies are removed? If so can we stick an @todo on the method for it?
Comment #46
xjmNW for #44 I think. Sorry for the comment-monologue.
Comment #47
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commented1. The interface calls for:
parent::onDependencyRemoval() sorts out things like 3rd party settings getTypePlugin()->onDependencyRemoval(), as you know, sorts out the entity types and bundles. Returning $parent_changed || $plugin_changed ensures that if either of those two things change a dependency, we return the correct value.
Better comment needed?
2. PluginSettingsInterface contains it, but that is deprecated. Other than that it's found (or something similar) in these places:
\Drupal\Core\Config\Entity\ConfigEntityInterface::onDependencyRemoval
\Drupal\Core\Field\FieldItemInterface::onDependencyRemoval
Unlike calculateDependencies which has a neat DependentPluginInterface. Perhaps RemovalDependentPluginInterface that extends DependentPluginInterface? Possibly follow-up territory.
Comment #48
alexpott@xjm thanks for making me look at
return parent::onDependencyRemoval($dependencies) || $changed;
again. It's apparent that this line is not actually tested because we don't have a module that sets third-party settings on a workflow config entity. Working on that and the other changesRe the generic handling of dependency removal and plugins - I had a look at #2579743: Config entities implementing EntityWithPluginCollectionInterface should ask the plugins to react when their dependencies are removed recently and thought I got to place where I realised that each plugin would need to handle this on their on own. But I can't recall why :(.
Comment #49
alexpottThe test only swaps the order of this to prove we have this logic covered.
Still need to create the followups - might have missed one:
Comment #51
xjmOnly other potential followup is @xjm's vague "please hold my hand with inline comments to help me understand how the entity system works".
Comment #52
xjm#49 resolves #45 for me, especially with the tests. Followups can be added before or after RTBC since they are not directly in scope.
Comment #53
alexpottI've filed the followups #2851225: Ensure non-configuration bundles are correctly removed when the bundles go away and #2851225: Ensure non-configuration bundles are correctly removed when the bundles go away
Comment #54
timmillwoodLooks ready to me.
Comment #55
xjmPosted this stub for now: #2851603: Add inline documentation to content moderation onDependencyRemoval() that describes what's happening
#53 is the same issue twice but I assume the second is #2851228: Warn users of what features are not available on a given entity type.
Comment #56
xjmIt's not applying to 8.4.x; I guess needs a reroll for the other content moderation patch?
Comment #57
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRerolled.
Comment #58
alexpottI did the reroll myself and diffed the resulting patches. The conflict was only in core/modules/workflows/src/WorkflowTypeInterface.php because this patch and #2844594: Default workflow states and transitions are both adding a new method to the end. @Sam152's reroll looks great - thanks.
Comment #59
xjmSome coding standards errors. I can probably fix these on commit, but a bit frayed, so bear with me here.
Comment #60
xjmComment #63
xjmIt's a patch for a thing that fixes things. And the things that it fixes make data integrity bug-magic so I backported it. Thanks!
Comment #64
xjmHm the coding standards issues were outside of this patch's additions, just in a changed file, and apparently I am using coder 8.2.10 instead of 8.2.8 so I accidentally cleaned up out-of-scope lines with my pre-commit hooks. Sorry for the noise -- going to leave the commit though.
Comment #65
xjmI think this issue was a regression from 8.2.0 so originally I did not tag it for that reason, but we should at least mention it in the beta release note and probably the content moderation section of the overall notes as well.
Comment #66
xjmI just spent 5 minutes clicking in related issue circles looking for this one. ;)
Comment #67
xjm@alexpott and I agreed that this does not need to go in the 8.3.0 release notes/changelog, since it is just a followup to the workflow conversion that happened in 8.3.x only and so was a regression since 8.2.x, but I am mentioning it in the beta release notes since the bug affected the alpha.