Problem/Motivation
Followup to #2779647: Add a workflow component, ui module, and implement it in content moderation.
In #2779647-48: Add a workflow component, ui module, and implement it in content moderation bojanz:
Why store the workflow ID inside the bundle info, and bless it as the "one true workflow"? Why not simply have a state_item field type that holds the state, and references the workflow? It would be convenient, and more natural when allowing multiple workflows.
This also makes sense when formatting the state, we currently store only the state ID, but will need to show the state label in various places. There's also a use case for a formatter that renders transition buttons (Jira-style), which would benefit from a field type.
This issue is proposing adding a new FieldType plugin which could be added to any entity which would reference a workflow and store the current state the content is at. The plugin would have formatters and widgets to allow users that can edit the content to transition the state. With pluggable workflow types, this could be used for things beyond moderation.
Right now Content Moderation doesn't use a field type. In #2725533-67: Add experimental content_moderation module, concerns were raised that storing the state of content in a field would have ramifications for installing and uninstalling content_moderation as an experimental module. Thus a computed field was used instead, with a separate entity type for storage. Other issues were raised about the usability of creating a field on an entity vs checking a box on a workflow edit screen.
However, those concerns are no longer relevant because we now have the ability to delete base fields, and therefore uninstall any module which uses a base field, like Content Moderation.
Proposed resolution
Introduce a new workflow_state
field type, and use it for Content Moderation in #3057946: Move content moderation information to a base field of the entity being moderated.
Remaining tasks
- Reviews to finalize the architecture
- Write test coverage
User interface changes
None.
API changes
A new field type is introduced.
Data model changes
None.
Comment | File | Size | Author |
---|---|---|---|
#68 | interdiff-2835545-54-mr3400.txt | 0 bytes | Bhanu951 |
#61 | 2835545-nr-bot.txt | 4.56 KB | needs-review-queue-bot |
#54 | interdiff-54.txt | 1.85 KB | amateescu |
#54 | 2835545-54.patch | 15.67 KB | amateescu |
#52 | interdiff-52.txt | 905 bytes | amateescu |
Issue fork drupal-2835545
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
saltednutStoring a workflow reference in a field makes sense, but I am not sure why allowing the field to be multi-value is desired - and defined as part of the issue. The summary does not make this clear.
I am left with the question: how would something like Publishing be resolved if there are multi workflows attached to the state field?
For example, say a bundle has two workflows:
Editorial workflow = Draft -> Needs Review -> Publish
Legal workflow = Draft -> Sent to legal -> Legal approve -> Publish
Would both workflows need to resolve to 'Publish' before the content is published? How is this resolved? How is this made clear to the user?
The effort in #2779647: Add a workflow component, ui module, and implement it in content moderation follows a central theme around simplifying the current system which requires far more config entities than we need and makes life difficult for those trying to set up a workflow. This issue, however, seems like it could add a new layer of complexity.
Comment #3
bojanz CreditAttribution: bojanz commentedIt's not desired. The field maps to a single workflow and stores a single state. You achieve multiple workflows with multiple fields.
Comment #4
timmillwoodComment #5
saltednutWouldn't multiple fields also lead to problems? It still is not clear how publishing is resolved if multiple workflows are conflicting.
Comment #6
bojanz CreditAttribution: bojanz commentedDifferent workflows for different purposes. One might be a publishing workflow, the other might be a marketing workflow.
You could implement a workflow guard that prevents a publishing transition if the marketing workflow is not in a satisfying state.
(Note that I'm talking about general theory, AFAIK workflow in core doesn't have guards yet == a way to prevent a transition).
Comment #7
tacituseu CreditAttribution: tacituseu commentedAnother solution for content moderation itself could be adding constraint limiting the number of fields with this type of workflow selected to one per bundle.
But the way I saw the proposal, it is more about allowing/enabling other (non publishing) types of workflows, like payment status or issue resolution, without necessity of creating custom local tasks or field types per workflow type just to have the ability to add them to a bundle.
Comment #8
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedIt might be worth revisiting why a custom content entity type was chosen to store the moderation information, in the original workbench_moderation and original-original moderation_state module it was a base field entity reference on the entity being moderated, which is closer to what this issue is proposing.
Comment #9
naveenvalechaAssigning to myself to work on Add new Workflow field type
Comment #10
naveenvalechaUnassinging myself. how the field type would work for entity types? There's already another issue #2843083: Select entity type / bundle in workflow settings which allows to select entity type/bundle per workflow.
If there will be two Workflow fields in the bundle both referencing different workflow,How will two workflows work for a single entity?
//Naveen
Comment #11
timmillwoodIn #2843083: Select entity type / bundle in workflow settings we can handle an entity type or bundle only having one workflow by simply disabling the checkboxes if the entity type / bundle already has a workflow.
This issue needs to solve a few things:
How will multiple workflows / states be stored?
Maybe we can add an entity reference field in ContentModerationState to reference the workflow config entity?
Then make the moderation_state computed field an "unlimited" field with multiple values of state and workflow?
How will the state be applied?
Currently the save button on entity is what changes the state. Should we add a settings form to set which workflow should be used for the save button? But then how to the other workflow states get applied? If there is more than one workflow for an entity type do we add radio buttons for the workflow states and remove the modified save button?
Comment #12
tacituseu CreditAttribution: tacituseu commentedI think this issue having "content_moderation.module" assigned as a "Component" is the source of this confusion, it really should be "workflows.module" as it is now independent from content_moderation.module but there is no such option yet.
It was meant to be something in the direction of https://www.drupal.org/project/state_machine module.
Comment #13
timmillwoodI think this is still a content moderation issue. Having multiple Workflows on a single entity type is now easy with Workflows module, but having multiple content moderation Workflows on a single entity type is not possible.
Comment #14
tacituseu CreditAttribution: tacituseu commentedWorkflows module only provides a way for creating and configuring ConfigEntity, it doesn't provide any way of assigning it to entity/content type, you can have reference to it, but that's it.
The code that binds workflows of type "Content Moderation" to content types is inside content_moderation.module and it uses bundle info for storage.
So, right now, each "workflow type" provider is expected to handle how it is storing its reference to Workflow ConfigEntity, the idea was to make it generic, Workflows module would provide FieldType/Widget/Formatter and all the "workflow type" providers wouldn't have to worry about implementing it, and at the same time it would allow multiple Workflows per content type (most as select widgets or "a formatter that renders transition buttons", one can be blessed as 'submit button holder'), you would just select one of the configured Workflows in Field's configuration.
Comment #15
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedRight now content moderation doesn't use a field and thus has no need for a field type/widget/formatter. If this is introduced, does there need to be another use of this API in core to justify its existence or are we just acknowledging that it'll just be a useful companion to the workflow entity in core? Or is the point that content moderation would revert to using a field.
FYI, the discussion around why a field was not appropriate started here.
I think it's worth reading that thread and clarifying if this issue means "introduce a field type" or if it means "introduce a field type and revert CM back to using a field for storage", because that doesn't seem clear right now.
Comment #16
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentededit: removed double post
Comment #17
tacituseu CreditAttribution: tacituseu commented@Sam152 thanks for the context, quite a journey this module took.
So the argument was, since it is experimental module you want users to be able to try it out and then uninstall without a problem, and since the implementation at the time was adding, in its install hook, a base field "moderation_state" to all revisionable entities, it made that difficult.
To be clear, the way I understand it, this issue was about providing configurable/optional field (something like "Comments"), hence it would avoid the described uninstallation problem.
You are right with regard to justification of being in core, without converting content moderation to field it would be just "useful companion", perhaps not even that, since out of the box it would only allow to use workflows of type 'content moderation' and create confusion by adding another way of doing/configuring the same thing.
That being said, after all it went through, I can understand reluctance to do so.
Comment #18
timmillwoodI have spent today investigating what it'll actually take to support Multiple workflows per bundle and in some respects we already have it, but in other ways it's a long way off.
We currently store the moderation state of an entity (lets say a Node) in the content_moderation_state entity, here we store a number of things:
So as you can see we already can store that a revision has state X from workflow Y, thus an entity can support a moderation state from multiple workflows.
We have a computed field, moderation_state, where we return the state as a string which was fetched from the content_moderation_state entity. This makes the whole thing pretty invisible and makes the moderation_state field just act like a string. If we changed the moderation_state field to a "map" type then we could return a value such as
['workflow_a' => 'state_z', 'workflow_b' => 'state_y']
.Then we get into issues for setting things like the publishing status and the default revision, which state do we believe?
but... here's a crude work in progress.
Comment #20
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThe original proposal was to essentially dump the content_moderation_state entity for a field type plugin. Does this need an issue summary update?
I always saw multiple workflows as a side effect of making it a field which could be used for non-moderation related things, not the end goal.
Comment #21
timmillwood@Sam152 - if we make it a field we get the same issue as we had in workbench_moderation where it won't be possible to uninstall?
Comment #22
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedThis issue started as a discussion around a field type, the multiple content moderation workflows per bundle was a side effect of that discussion, but this issue has since morphed into just "make multiple content moderation workflows work better".
Renaming as such and a new issue can track the latter.
Comment #23
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #24
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedComment #25
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedSpun off #2846993: Make content moderation work better with multiple workflows attached to a single entity/bundle..
Comment #26
tacituseu CreditAttribution: tacituseu commentedCouple of quotes from parent thread about usability beyond content_moderation:
https://www.drupal.org/node/2779647#comment-11736150
@alexpott:
https://www.drupal.org/node/2779647#comment-11741016
@jhedstrom:
Comment #28
timmillwoodSwitching this back to "Active" as the patch which made this "Needs work" is irrelevant to the current direction.
Comment #29
tacituseu CreditAttribution: tacituseu commentedComment #31
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedFor use-cases that aren't at all publish-status concerned, I've spun out https://www.drupal.org/project/workflows_field. Really pleased with how simple this ended up being to implement using workflows.
Comment #32
tacituseu CreditAttribution: tacituseu commented@Sam152: Thanks, I did the same thing, a bit of a cross between
state_machine
andentity_reference
withTypedData
state property, based on 8.3, intended to update, clean it up and post it here, but contrib makes sense, will bug you in the issue queue ;).Comment #33
jibran@Sam152 For
workflows_field
module it can be ER field. In your implementation, it can just be aStringItem
FieldType
then onFieldWidget
you can extend OptionsWidgetBase and just override::getOptions()
. I can create issues in the project queue for futher discussion if you'd like.Comment #34
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedAn ER field to what entity type?
Comment #35
jonathanshawNow that #2282119: Make the Entity Field API handle field purging is RTBC, the original rationale against a field (that undeletable base fields make the module uninstallable) is gone.
Comment #36
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedI agree with #35. I do also wonder if the intermediary entity has offered any significant affordances that would be tricky with a non-computed field. Would be good to catalogue some of the special moderation related behaviors that the field has.
One such example is #2817835: When enabling moderation apply a relative state.
Comment #39
greggmarshallCould this new field be translatable? That would/should allow the possibility of different workflows for different languages(?). A use case might be where there are different legal requirements for different countries (assuming localization use of language codes), which would require different approval processes.
Comment #40
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedDoing this would require BC with the current approach. The API surface of an entity type is very broad, I have no idea how we'd approach deprecating a whole entity type, given the numerous touch points an entity has with other APIs. Some relevant information in here: #2917276: Allow entity types to be @internal in such a way that removing them doesn't violate any BC.
Comment #42
weynhamzI am facing kind of a similar but not exactly issue here, core content_moderation module enforces per workflow per bundle, but the project I am working on requires per workflow per node. It is not a multi-workflows per node scenario, it is still a single workflow per node, but different node requires a different workflow.
Although it is a different issue to be solved, both can be given the possibility to be solved separately by answering this question:
Can 'getWorkflowForEntity' method be deligated to a pluggable implementation?
What I would propose is
* Core content_moderation module handles the basic stuff of the transactions of the content
* Expose a pluggable mechanism to workflow determination
* Refactor the current workflow determination logic based on bundles to a separate plugin
This way, it would allow the site builder to implement a plugin that suits the true business needs.
Real Business Scenario
* There is a product content type
* Many departments can create the product content
* Different department has different product content moderation process
* The product content moderation process to be applied is determined by the department of the author belongs to
Comment #43
weynhamzhttps://www.drupal.org/project/drupal/issues/2835545#comment-11885892
@timmillwood:
I like this suggestion, by making moderation_sate a "map" type, even if we don't have multiple workflows per entity, as it stores the workflow used for the entity, it does allow to have a different workflow per entity set up.
Comment #44
weynhamzThe solution I need for the moment is to allow using a different workflow per entity.
I have created a custom module by overriding the content_moderation.moderation_information service, altering the getWorkflowForEntity method, I was able to prove current content_moderation does support different workflow per entity set up.
Now, what I am thinking is what actually is the right way to do this.
Currently, content_moderation module configures the bundles to use the workflow on the workflow editing page, but this 1-1 relationship is actually stored in entity bundle's metadata, doesn't this feel a little bit odd? If the relationship is stored in entity bundle's metadata, then it should be configured in entity bundle's configuration page, to choose the workflow instead, not the other way around.
And also, it feels right, if on the entity bundle level, to allow each bundle to choose the business logic of determining workflows to use. This way, we could support the core's current 1 bundle - 1 workflow setup through a pluggable system, it also enables the site builder to write a plugin that allows the different workflow to be applied to a differnt entity, it also enables the possibility to have more than one workflows to apply to an entity, because all the logic happens on entity level.
Comment #45
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedMaking this pluggable could be an interesting extension point, but it's also worth noting that this workflow can be modelled by simply creating two branches of a single workflow branching off an "Initial" state, with permissions configured to only allow users to branch off into a particular direction.
Using that model is kind of handy, since admins could be configured to move entities between these two workflows if required.
Comment #46
weynhamzThanks, @Sam152, that is indeed a viable approach to do this, but there are certain problems I can see with this approach:
1. It requires to create more roles for each department, and there're a lot of departments, the maintenance of the workflow might be getting too complicated in the long term.
2. Also, an additional requirement I forget to mention is that the approver of a different department shouldn't be able to approve/see the content that is not for him/her to approve. If we use workflow branching for this, this approver will be able to approve the content that is not meant to be his/her to approve to his/her workflow branch.
At the moment, it feels more right to me to use a dedicated workflow entity for a different department, which still brings us back to this issue.
Comment #50
amateescu CreditAttribution: amateescu for Tag1 Consulting commentedHere's an initial pass at porting the workflow state field type from
state_machine
to core's Workflows module. The main difference is that it's invoking hooks instead of dispatching events, based on #2873287-39: Dispatch events for changing content moderation states.Comment #52
amateescu CreditAttribution: amateescu for Tag1 Consulting commentedFixed those test fails.
Comment #53
geek-merlinCode looks clean and straightforward.
But i wonder: Why doens't this inherit from EntityReference? (or at least use well-known naming and concepts from there)
Also, getId() got me confused. ("Does a field have an Id?")
Maybe it's getTargetId() (if we conceptually stick to EntityReference), or getStateId().
Same for some other method names.
w
Comment #54
amateescu CreditAttribution: amateescu for Tag1 Consulting commented@geek-merlin, thanks for taking a look!
I don't think this new field type maps conceptually to Entity Reference, because the "thing" being referenced (a workflow state) is not managed by the Entity API. It's more similar to the
language
field type (\Drupal\Core\Field\Plugin\Field\FieldType\LanguageItem
) than to ER.Good point about the method names, I renamed the three methods that can be ambiguous in the context of a field:
getId()
,getOriginalId()
andgetLabel()
to includeState
in their name. Note that I leftgetTransitions()
as-is because there's no concept of transitions within the entity/field API.Comment #55
geek-merlin@amateescu
Yes, the reasoning and the patch are totally convincing to me.
Comment #58
SocialNicheGuru CreditAttribution: SocialNicheGuru commentedDoes this take the place of https://www.drupal.org/project/workflows_field?
Comment #61
needs-review-queue-bot CreditAttribution: needs-review-queue-bot as a volunteer commentedThe Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #62
Akhil Yadav CreditAttribution: Akhil Yadav commentedAdded patch against #54 in 10.1 version
Comment #63
Bhanu951 CreditAttribution: Bhanu951 as a volunteer commentedSetting as need review for tests to run.
Comment #65
Bhanu951 CreditAttribution: Bhanu951 as a volunteer commentedcore/modules/workflows/src/WorkflowStateItemInterface.php
core/modules/workflows/src/WorkflowStateFieldItemList.php
core/modules/workflows/src/Plugin/Field/FieldType/WorkflowStateItem.php
Files are missing in #62 which were present in #54.
@Akhil Yadav This is the 6th patch I have looked into today which were re-rolls made by you, missing changes from earlier patches.
It is advised to include interdiff for your re-rolls.
Hiding patch in #62
Comment #67
apaderno@Akhil There is too much difference between a 15.67 KB patch and a 2.9 KB patch. On Drupal.org, re-rolling a patch to only provide part of the changes is not helpful.
Comment #68
Bhanu951 CreditAttribution: Bhanu951 as a volunteer commentedComment #69
Bhanu951 CreditAttribution: Bhanu951 as a volunteer commentedComment #70
Bhanu951 CreditAttribution: Bhanu951 as a volunteer commentedAdopted code for commit 77a051e0- Fix tests from the below module.
https://www.drupal.org/project/workflows_field
Comment #71
Bhanu951 CreditAttribution: Bhanu951 as a volunteer commentedComment #72
smustgrave CreditAttribution: smustgrave at Mobomo commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
Removing credit for patch #62 as it removed almost the entire patch it was rerolling.
Looking at MR 3400 believe the issue summary should be updated to include that the proposed solution to add an interface, hooks, etc now vs just a new fieldtype. Should include probably a why too?
This will 100% require a change record as well.
Left a few small change requests in the MR.