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.

Issue fork drupal-2835545

Command icon 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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

tacituseu created an issue. See original summary.

saltednut’s picture

Storing 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.

bojanz’s picture

It's not desired. The field maps to a single workflow and stores a single state. You achieve multiple workflows with multiple fields.

timmillwood’s picture

Issue tags: +Workflow Initiative
saltednut’s picture

You achieve multiple workflows with multiple fields.

Wouldn't multiple fields also lead to problems? It still is not clear how publishing is resolved if multiple workflows are conflicting.

bojanz’s picture

Different 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).

tacituseu’s picture

Another 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.

Sam152’s picture

It 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.

naveenvalecha’s picture

Assigned: Unassigned » naveenvalecha

Assigning to myself to work on Add new Workflow field type

naveenvalecha’s picture

Assigned: naveenvalecha » Unassigned

Unassinging 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

timmillwood’s picture

In #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?

tacituseu’s picture

I 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.

timmillwood’s picture

I 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.

tacituseu’s picture

Workflows 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.

Sam152’s picture

Right 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.

Sam152’s picture

edit: removed double post

tacituseu’s picture

@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.

timmillwood’s picture

Title: Provide Workflow FieldType, allow multiple workflows per bundle » Allow multiple workflows per bundle
Status: Active » Needs review
FileSize
12.5 KB

I 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:

  • The user who changed the state.
  • The workflow the moderation state is in.
  • The moderation state string.
  • The entity type id (node).
  • The entity id (node id / nid).
  • The entity revision id (vid).

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.

Status: Needs review » Needs work

The last submitted patch, 18: 28355450-18.patch, failed testing.

Sam152’s picture

The 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.

timmillwood’s picture

@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?

Sam152’s picture

Title: Allow multiple workflows per bundle » Provide a Workflow FieldType that references a workflow entity and tracks the current state of an entity

This 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.

Sam152’s picture

Title: Provide a Workflow FieldType that references a workflow entity and tracks the current state of an entity » Provide a Workflow FieldType that references a workflow entity and tracks the current state of an entity (optionally make content_moderation use this field type)
Sam152’s picture

Issue summary: View changes
Sam152’s picture

tacituseu’s picture

Couple of quotes from parent thread about usability beyond content_moderation:

https://www.drupal.org/node/2779647#comment-11736150
@alexpott:

The end goal end is to allow other modules to leverage workflows without content_moderation. For example, the Workflow Initiative is pretty keen to add a workflow to their workspace concept.

https://www.drupal.org/node/2779647#comment-11741016
@jhedstrom:

The separation of workflow from content will allow quite cool things in the future, such as moderation of configuration (eg, a Views publishing workflow), user approval workflows, and many other things that are currently not possible with the tight coupling to content entities.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.0-alpha1 will be released the week of January 30, 2017, which means new developments and disruptive changes should now be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

timmillwood’s picture

Status: Needs work » Active

Switching this back to "Active" as the patch which made this "Needs work" is irrelevant to the current direction.

tacituseu’s picture

Component: content_moderation.module » workflows.module

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Sam152’s picture

For 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.

tacituseu’s picture

@Sam152: Thanks, I did the same thing, a bit of a cross between state_machine and entity_reference with TypedData 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 ;).

jibran’s picture

@Sam152 For workflows_field module it can be ER field. In your implementation, it can just be a StringItem FieldType then on FieldWidget you can extend OptionsWidgetBase and just override ::getOptions(). I can create issues in the project queue for futher discussion if you'd like.

Sam152’s picture

For workflows_field module it can be ER field

An ER field to what entity type?

jonathanshaw’s picture

Now 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.

Sam152’s picture

I 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.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

greggmarshall’s picture

Could 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.

Sam152’s picture

Doing 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.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

weynhamz’s picture

I 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

weynhamz’s picture

https://www.drupal.org/project/drupal/issues/2835545#comment-11885892
@timmillwood:

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'].

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.

weynhamz’s picture

The 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.

Sam152’s picture

  1. There is a product content type
  2. Many departments can create the product content
  3. Different department has different product content moderation process
  4. The product content moderation process to be applied is determined by the department of the author belongs to

Making 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.

weynhamz’s picture

Thanks, @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.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

amateescu’s picture

Status: Active » Needs review
FileSize
15.55 KB

Here'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.

Status: Needs review » Needs work

The last submitted patch, 50: 2835545-50.patch, failed testing. View results

amateescu’s picture

Title: Provide a Workflow FieldType that references a workflow entity and tracks the current state of an entity (optionally make content_moderation use this field type) » Provide a Workflow FieldType that references a workflow entity and tracks the current state of an entity
Status: Needs work » Needs review
FileSize
15.64 KB
905 bytes

Fixed those test fails.

geek-merlin’s picture

Code 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.

+++ b/core/modules/workflows/src/WorkflowStateItemInterface.php
@@ -0,0 +1,81 @@
+  /**
+   * Gets the current state ID.
+   *
+   * @return string
+   *   The current state ID.
+   */
+  public function getId();
+
+  /**
+   * Gets the label of the current state.
+   *
+   * @return string
+   *   The label of the current state.
+   */
+  public function getLabel();
+
+  /**
+   * Gets the allowed transitions for the current state.
+   *
+   * @return \Drupal\workflows\TransitionInterface[]
+   *   The allowed transitions, keyed by transition ID.
+   */
+  public function getTransitions();

w

amateescu’s picture

@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() and getLabel() to include State in their name. Note that I left getTransitions() as-is because there's no concept of transitions within the entity/field API.

geek-merlin’s picture

@amateescu
Yes, the reasoning and the patch are totally convincing to me.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

SocialNicheGuru’s picture

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
FileSize
4.56 KB

The 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.

Akhil Yadav’s picture

Added patch against #54 in 10.1 version

Bhanu951’s picture

Status: Needs work » Needs review

Setting as need review for tests to run.

Status: Needs review » Needs work

The last submitted patch, 62: 2835545-62.patch, failed testing. View results

Bhanu951’s picture

core/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

apaderno’s picture

@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.

Bhanu951’s picture

Bhanu951’s picture

Bhanu951’s picture

Adopted code for commit 77a051e0- Fix tests from the below module.

https://www.drupal.org/project/workflows_field

Bhanu951’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative, +Needs change record, +Needs issue summary update

This 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.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.