- Issue created by @tobiasb
- 🇩🇪Germany jurgenhaas Gottmadingen
Haven't tried to reproduce this yet, but
\Drupal\eca_workflow\HookHandler::transition
gets triggered by the hook implementationeca_workflow_entity_update
which receives the entity from Drupal core. That entity must be the latest revision already, isn't it? Because that's the one that got updated and will be transitioned from some state to published. If I misunderstood, could you please explain in a bit more detail, please? - 🇩🇪Germany tobiasb Berlin
The entity is fine. I changed the title I hope the makes it more clear.
- 🇩🇪Germany jurgenhaas Gottmadingen
Should that be "... the default state" instead of revision?
- 🇩🇪Germany tobiasb Berlin
original is set via \Drupal\Core\Entity\EntityStorageBase::doPreSave, but the load in \Drupal\Core\Entity\EntityStorageBase::loadUnchanged loads the default entity revision.
Which means the from_state is not the state from the revision before you change it.
For Nodes this works:
$from_state = NULL; /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */ $storage = \Drupal::entityTypeManager() ->getStorage($entity->getEntityTypeId()); $revision_ids = $storage->revisionIds($entity); if ($revision_ids) { // We need to remove the revision_id which is same as from the entity. array_pop($revision_ids); $last_revision_id = end($revision_ids); if ($entity->getRevisionId() != $last_revision_id) { $last_revision = $storage->loadRevision($last_revision_id); $from_state = $last_revision->get('moderation_state') ->getString(); } }
- 🇩🇪Germany jurgenhaas Gottmadingen
OK, here is how this can be reproduced:
- New Drupal site with content moderation enabled and configured
- Create new node in draft
- Transition that node from draft to published: from state is draft and to state is published, as expected
- Edit node, creates new revision, save in draft state
- Transition that node from draft to published again: from state is published and to state is published, here is the error
I will next try to reproduce this without ECA being installed and see if this is still the same. If so, I'd presume this to be a core issue.
- 🇩🇪Germany jurgenhaas Gottmadingen
Confirmed, this is the same when just working with plain Drupal 10, fresh installation.
So, the update hook from core provides the content entity including its original as well. Our expectation is that this original contains the entity revision from right before updating the given entity. Instead, origin contains the latest published revision, i.e. the default revision.
If I go that right, this seems to be a core bug, and we should report that upstream rather than trying to build a workaround.
- 🇩🇪Germany tobiasb Berlin
I do not believe this is a core issue. The fact is just that original is set via load not loadRevision as you can read in entity.api.php.
This would be more a feature-request that drupal provides the revision before it creates/saves the new revision.
- 🇩🇪Germany jurgenhaas Gottmadingen
I tend to disagree on that judgement. The
hook_entity_update
states this: "Get the original entity object from $entity->original."What else should a developer expect than finding the entity's version prior to being updated?
Getting the "wrong" original has far bigger impact, e.g. when we want to find out if a field value has changed, we also compare the field value from the entity to the field value from the original. That will also provide wrong results in such scenarios. I'm pretty sure that other use cases of this hook will have fallen into the same trap.
Maybe this hasn't been recognized before, because the revisions are not the problem - this only ever happens when content moderation is being used. I'll ask that question in Slack to see what other think about this, so we get a better view whether my expectation is the issue or if it's really a core issue.
- 🇩🇪Germany jurgenhaas Gottmadingen
Here is the thread in Slack: https://drupal.slack.com/archives/C1BMUQ9U6/p1677844022810869
Only last week, @catch committed a similar looking fix, which was just about 6 years old, to Drupal 10.1 in 🐛 Impossible to update an entity revision if the field value you are updating matches the default revision. Fixed and published this change record → .
Unfortunately, this was the right thing to do, but it doesn't cover the use case in
\Drupal\Core\Entity\EntityStorageBase::doPreSave
which then affects the usage oforiginal
inhook_entity_update
. To also resolve that, the following change is required in that method:// Load the original entity, if any. if ($id_exists && !isset($entity->original)) { - $entity->original = $this->loadUnchanged($id); + $entity->original = $this->loadRevision($entity->getLoadedRevisionId()); }
That resolves the issue and has been tested. We don't know yet if and when this also goes into Drupal core, but we should hold off with our decision what to do until we know how this will be handled.
- Status changed to Closed: works as designed
about 2 years ago 12:16pm 27 March 2023 - 🇩🇪Germany jurgenhaas Gottmadingen
Closing this as "Works as designed" as we've identified this as a core bug and hope to push this over the finish line in the referenced issue.
- First commit to issue fork.