Skip to content

[Bug]: Discarding a draft does not revert the workflow place with the state_table marking store (changePublishedState: save_version) #456

Description

@cancan101

Affected capability

Core

Feature description

Affected packages

  • pimcore/pimcore (2026.x, reproduces on the current maintenance branches as well)

Originally reported as pimcore/pimcore#18653. Fix proposed in pimcore/pimcore#19434.

Related, but independent: #455 (Studio applies transitions to the published element instead of the latest draft).

Summary

With the default state_table marking store, a transition configured with changePublishedState: save_version writes the new place to element_workflow_state immediately, while the element's content is only saved as a draft (version). The place is therefore committed although the content is not: the published element already reports the new place, and discarding the draft deletes the version but leaves the state row untouched, so the element stays in the new place.

The attribute based marking stores (single_state, multiple_state, data_object_multiple_state, data_object_splitted_state) keep the place in a field of the element, so for them the place is part of the draft and discarding the draft reverts it. The two store families behave differently for the same transition configuration.

Steps to reproduce

Workflow config (applies to every data object class, default state_table store):

yaml pimcore: workflows: review: supports: [Pimcore\Model\DataObject\Concrete] places: draft: {} review: {} transitions: submit: from: draft to: review options: label: Submit for review changePublishedState: save_version ​

  1. Open a published data object and apply Submit for review. The transition saves a draft version, the element is not published.
  2. Open the object again: the workflow shows the place review. The published object (frontend, element_workflow_state, workflow reports) also reports review already.
  3. Discard the draft.

Actual: the draft's content changes are gone, but the element stays in place review.

Expected: the element returns to place draft, i.e. the place change is discarded together with the draft. This is what happens with single_state, where the place lives in a field of the element.

Compare with marking_store: { type: single_state, arguments: [workflowState] } on a class with a workflowState select field: same steps, the place reverts on discard.

Where it happens

  • lib/Workflow/MarkingStore/StateTableMarkingStore.php, setMarking(): writes the WorkflowState row right away, inside Workflow::apply(), independent of how the subject is saved afterwards.
  • lib/Workflow/Manager.php, applyWithAdditionalData(): for save_version transitions calls saveVersion() on the subject after apply(). Nothing connects the state row to that version.
  • The admin UIs' discard-draft action ends in Version::delete(), which only removes the version and dispatches the version events. Nothing knows the workflow place needs reverting, and the previous place was never recorded anywhere.
  • Workflow: roll back marking when post-transition save fails pimcore#19137 (rollback when the post-transition save throws) covers the sibling case where the save fails; it does not cover a save that succeeds as a draft only.

Proposed fix (implemented in pimcore/pimcore#19434)

Make state_table follow the transition's declared persistence for save_version transitions, so it behaves like the attribute based stores:

  • New Pimcore\Workflow\MarkingStore\PendingMarkingStoreInterface: a marking store that persists independently of the subject can keep a marking pending on the subject when told that the subject is only going to be saved as a version. StateTableMarkingStore implements it.
  • Manager::applyWithAdditionalData() passes a CONTEXT_SAVE_VERSION context flag into apply() when the subject is saved by the manager and the transition uses save_version. Every other transition type, global actions, and direct $workflow->apply() calls keep persisting the place immediately.
  • AbstractElement carries the pending markings (@internal accessors). The property is part of version dumps, so a draft carries it and discarding the draft drops it; it is excluded from the cache.
  • WorkflowManagementListener persists pending markings on the element's post-update / post-add events, skipping version-only saves. Publishing a draft is a full save, so that is when the place reaches element_workflow_state.
  • Docs: marking store docs, changePublishedState config comment, upgrade note.

Consumers reading element_workflow_state directly (workflow reports, the search index workflow filter, Studio's "elements in place" listing) then see the state of the published element while such a draft exists, consistent with the attribute based stores.

Notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Fields

    Affected capability

    None yet

    Galaxy

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions