Problem/Motivation
Unexpected behaviour occurs when attempting to create a new "draft" revision of a node that has already been published within a workflow that includes users with different permitted transitions.
Steps to recreate
- Create a workflow with at least 4 transition states, e.g. 'In draft', 'For review', 'To publish' and 'Live'.
- For the purposes of this example, create two user roles: 'author' and 'moderator'. Configure workflow transitions:
- Grant 'moderator' the ability to perform all transitions.
- Grant 'author' the ability to perform (at least) the following transitions:
- (creation) -> 'In draft'
- 'In draft' -> 'For review'
- 'Live' -> 'In draft'
- Add a workflow flow field to a content type and configure the available states to be displayed as a list of radio buttons.
- Configure the publishing options for the same content type as follows:
- Not published - unchecked
- Create new revision - checked
- New revision in draft, pending moderation - checked
- New revision in draft: Create new revision: Every time revision content is updated, even when saving content in draft/pending moderation - checked
- As a 'moderator', create a new node and publish it, i.e. set the workflow state to 'Live'.
- As an 'author', edit the published node and change the target state from 'Live' to 'In draft' and save the revision.
- Continuing as an 'author', edit the new revision and change the target state from 'In draft' to 'For review' and save.
- Also as an 'author', edit the latest revision and check the options for target state: 'Live' and 'In draft' will be displayed again with 'Live' selected, rather than 'In draft' and 'For review' with 'For review' selected.
At this point, 'authors' get stuck in a loop, as it's not possible to transition a revision from 'In draft' to 'For review' without it seemingly reverting to the 'Live' state.
Notes
I've created a module that implements hook_workflow() to try and do some debugging. At the point of changing the workflow state from 'In draft' to 'For review', the transition object indicated that the current state ID (2 - 'In draft') and the target state ID (3 - 'For review') were as expected. However, two errors were produced during the process of saving:
Attempt to go to nonexistent transition (from 5 to 3)
User matt_author not allowed to go from state 5 to 3
The transition from 5 to 3 ('Live' to 'For review') does exist in the configuration of transitions, but only for users with the 'moderator' role. The second error message is correct as 'authors' aren't able to perform this transition. I don't know why the 'Live' to 'For review' transition is in the mix, as it's nothing to do with the transition I was attempting to perform!
Has anyone experienced anything similar to this?! Any advice or suggestions would be greatly appreciated!
Comments
Comment #1
Anonymous (not verified) CreditAttribution: Anonymous commentedComment #2
johnv- Please try latest dev (or version 2.5 when it is available already). It has some corrections for working with revisions.
- Setting this to normal, since this seems a special use case including a 3rd module. (Editing revisions is not a standard permission, and provided by the Revisioning module).
- The Revisioning module is developed with Workflow Node in mind (Workflow version 1.2). Do you use Workflow Field or Workflow Node?
Comment #3
Anonymous (not verified) CreditAttribution: Anonymous commentedThanks for your reply, and my apologies for taking a while to respond. Unfortunately, I've been able to recreate the problem in version 2.5, but I'm using Workflow Field. I'll try using Workflow Node to see if that plays better with revisions and report back.
Comment #4
Anonymous (not verified) CreditAttribution: Anonymous commentedI changed my configuration to use Workflow Node instead of Workflow Field but I didn't get very far unfortunately. After saving a node of a content type with an associated workflow, I got a nasty EntityMetadataWrapperException, which pretty much ended my exploration of that option!
I've updated the module to version 2.5, but the problem I described in my original post is still occurring. I'm keen to find a solution to this, as Workflow combined with Revisioning and Rules has the potential to produce a great content authoring experience. I've done a bit more digging, and I've identified something that might be related to the cause of the problem. If I describe my findings, hopefully someone who knows the module a little better than me will be able to suggest a solution.
I decided to start by looking at the widget provided by Workflow Field first. I assumed that the problem is being caused by incorrect entity information (i.e. not using the correct/latest revision for state transitions), so I added a watchdog call to dump out the contents of $entity in the constructor of the WorkflowD7Base class at various points during the workflow. I've included a summary of the contents of $entity at the various stages below:
1. (creation) -> 'For review' (Skipped the 'In draft' state to get to the problem faster!)
2. 'For review' -> 'Live'
3. 'Live' -> 'In draft'
At this point, the error occurs. From what I can see, the contents of
[original]
in step 3 is incorrect.[old_vid]
refers to the correct revision (vid = 2), but the previous revision is included in[original]
- vid = 1. The value of[field_workflow]
is therefore 'for review' rather than 'live', and attempting to transition from 'for review' to 'in draft' is not permitted and results in the error.(NB: The configuration of transition states have changed from my original post, and rules were disabled for this test so the node never actually gets published, which is why
[status] => 0
.)Any thoughts? Thanks for your help!
Comment #5
Anonymous (not verified) CreditAttribution: Anonymous commentedPostponed while I investigate if the Revisioning module is having any effect on the contents of
[original]
.Comment #6
Anonymous (not verified) CreditAttribution: Anonymous commentedI've discovered that the source of the problem I've been experiencing is within the
workflow_node_previous_state
function inworkflow.module
. It isn't a bug, as without the Revisioning module in the mix, the functionality provided by the Workflow module works as expected.Due to the way the Revisioning module manages revisions, there is no guarantee that the contents of
$entity->original
is the latest revision. Depending on how revisioning is configured, and based on the testing I've done,$entity->original
appears to contain the current revision, i.e. the revision that is currently published. This means that using$entity->original
to retrieve the previous workflow state will cause the error I described above when using the Revisioning module.In order to get things working (and in an attempt to get back on track with my sprint!), I've implemented a hacky fix which simply provides an alter hook before
$sid
is returned (approx. line 1015):I've implemented the hook in a custom module, which will then check for the latest revision, and change the value of
$sid
. Not very pretty to say the least, but it'll let me get on with what I need to do for the time being!Unfortunately, I don't know the module well enough to answer this question: could there be a more elegant solution for this issue?
Thanks!
Comment #7
johnv"$entity->original appears to contain the current revision, i.e. the revision that is currently published."
This seems like a bug in Revisioning: suppose I have 4 versionswith vid 1-4, and I edit the unpublished version vid=2, I'd expect $entity->original to have the value vid=2. Instead, it contains vid=4.
Am i right?
Comment #8
Anonymous (not verified) CreditAttribution: Anonymous commentedThanks for your reply. I'm not sure if that behaviour is necessarily a bug in the Revisioning module. I think the value of
$entity->original
varies depending on exactly how revisions are configured - I'll need to do more exploring to confirm that and possibly post a question in the issue queue for the Revisioning module, so I'll postpone this issue again for the time being.Comment #9
johnvPerhaps it is possible to rewrite workflow_node_previous_state(), without using the original.
Comment #10
Anonymous (not verified) CreditAttribution: Anonymous commentedWould using entries stored in the
workflow_node_history
table be feasible for rewritingworkflow_node_previous_state()
? I assume an entry is written to the table after a state transition is successfully completed, and as thenid
andrevision_id
is stored, it looks as though all the information needed to determine the previous state is available in that table. If that's the case, I'm happy to have a go at making a patch.Comment #11
johnvYes, It would.
Be careful: there are always 2 different options: if Fieldname is empty, the WorkflowNode is used, else WorkflowField is used.
A big issue in that function is when the function is called during update. In the update, you have a phase before DB-change, and one after DB-change. That's why the 'original' was so ideal, (and it does not need an extra DB-read.)
Perhaps an exception should be inserted if the VID's are in some state?
Comment #12
sujith.nara CreditAttribution: sujith.nara as a volunteer and commentedBeware!! Workflow tab is not syncing with node's revision.
See this http://www.ionsden.com/article/problems-workflow-and-revisioning-drupal (applicable to Drupal 7)
Comment #13
ShaxA CreditAttribution: ShaxA at FFW commentedSo i have been struggling with the same issue a whole day. Finally i found how to fix it. We have two case scenarios. The first is when we publish a new version then we have to get the old revision by old_vid which always contains the right vid. This we must do only if we are not publishing an old revision.
The second is when we are publishing an old revision then we must get the sid from the entity->original which contains the previous published revision and the old_vid will contain the new revision.
Comment #14
johnv@ShaxA, is your patch really workfing OK? It has a type here:
if (!empty($wrrapper)) {
Comment #15
ShaxA CreditAttribution: ShaxA at FFW commentedI am really sorry i forgot to send the last patch with this fix. Yes it is working after you correct this typo. Thanks for reminding me.
Comment #17
johnvThanks. This is now fixed.
There is no D8-port of Revisioning module, yet. I'll add a reminder D8-task.
Comment #19
johnvThe committed fix is different from your patch, since the code has been changed. Please test the new version and give some feed-back.
Comment #21
ShaxA CreditAttribution: ShaxA at FFW commentedHi johnv, I will have a look as soon as i can. Thanks.
Comment #22
carstenG CreditAttribution: carstenG at FFW commentedHey.
Patch is working fine as long as a new revision is created on every save.
But when you chose the other option "Only when saving page content that is not already in draft/pending moderation" the problem still remains.
It is taking the
$entity->original
I have noticed that
workflow_node_previous_state()
function we have a entity in place where ne correct workflow status of the previous node is available.$entity->field_workflow['und'][0]['workflow]['workflow_entity']
So changing this
into
What do you think?
As this is already committed I have added this small patch.
Comment #23
carstenG CreditAttribution: carstenG at FFW commentedComment #24
daxelrod CreditAttribution: daxelrod commentedThe issue remains as carstenG describes. The patch in #22 works.
A couple other options besides the above patch:
$node->revision
flag when the above option is selected. It could set$node->old_vid
which would allow the existing code to work.$entity->revision_moderation
and$entity->is_pending
to identify revisions instead.Comment #26
johnvThanks.