Problem/Motivation
Consider the following situation, a node type "page" exists with 1 field, "field_text".
When using a workspace to create a new page (nid = 1) the following happens:
2 revisions are created in the node_revision table:
||nid||vid||revision_default||
|1|2|0|
|1|1|1|
In the node base table, the node is referenced with vid 1 and has a status of unpublished.
In the node__field_text an entry is made with entity_id = 1, and revision_id = 1.
When we publish the node using the Workspace Publisher, the following happens.
The node base table, and node field table point to vid = 2. The node__field_text however is not updated and still points to revision_id = 1.
This mismatch occurs because we are trying to save a revision as the default revision. So the base, data and revision tables are updated correctly. However, the dedicated tables are not updated correctly.
This is because of the following statement in Drupal\Core\Entity\Sql\SqlContentEntityStorage:
// When updating an existing revision, keep the existing records if the
// field values did not change.
if (!$entity->isNewRevision() && $original && !$this->hasFieldValueChanged($field_definition, $entity, $original)) {
continue;
}
Here, the field value has not changed, and we are not creating a new revision. Thus the field tables are not updated correctly.
Proposed resolution
Add a property to ContentEntityBase which forces the update of the dedicated tables. The property can be set using a public method on the ContentEntityBase so that we can force the update of data tables from the WorkspacePublisher.
The changes in short are this:
- Added new property "forceStorageUpdate", with a setter and getter on the Drupal\Core\EntityContentEntityBase class.
/**
* Settings this property will force the storage to update on entity save.
*
* @var bool
*/
protected $forceStorageUpdate = FALSE;
/**
* {@inheritdoc}
*/
public function forceStorageUpdate() {
return $this->forceStorageUpdate;
}
/**
* {@inheritdoc}
*/
public function enforceStorageUpdate($enforce = TRUE) {
$this->forceStorageUpdate = $enforce;
return $this;
}
- Checked in the SqlContentStorage if the save to the dedicated tables was forced.
// When updating an existing revision, keep the existing records if the
// field values did not change.
// If the entity is set to force storage update, proceed with updating.
if (!$entity->forceStorageUpdate() && !$entity->isNewRevision() && $original && !$this->hasFieldValueChanged($field_definition, $entity, $original)) {
continue;
}
Issues to discuss
- Are we a fan of this approach or does it open Pandora's box?
- I think the location where the new property and methods are added, are open for discussion.
- This fix can be used outside of workspaces so perhaps the component is not correct.
Similar issue
https://www.drupal.org/project/drupal/issues/2859042
This is basically the same issue, but my approach is different
| Comment | File | Size | Author |
|---|---|---|---|
| #8 | 3152820-8.patch | 4.17 KB | mheip |
| #3 | 3152820-3.patch | 3.38 KB | mheip |
Comments
Comment #2
mheip commentedComment #3
mheip commentedComment #4
mheip commentedComment #5
mheip commentedComment #6
mheip commentedComment #8
mheip commentedComment #9
mheip commentedPatch 8 applied, I had forgotten to add the new property to the translation and clone functions.
Comment #10
matsbla commentedIf it is the same issue it means this is a duplicate.
Maybe you should publish the alternative solution in the referred issue?
#2859042: Impossible to update an entity revision if the field value you are updating matches the default revision.
Comment #14
amateescu commentedI agree with #10, marking this as a duplicate of #2859042: Impossible to update an entity revision if the field value you are updating matches the default revision.. @mheip thanks for commenting in that issue to let people know that the Workspace module is also affected. Like @matsbla, I also think you should post your patch in that issue as well.