Problem/Motivation
We currently store information about a paragraph's parent entity in basefields:
$fields['parent_id'] = BaseFieldDefinition::create('string')
->setLabel(t('Parent ID'))
->setDescription(t('The ID of the parent entity of which this entity is referenced.'))
->setSetting('is_ascii', TRUE);
$fields['parent_type'] = BaseFieldDefinition::create('string')
->setLabel(t('Parent type'))
->setDescription(t('The entity parent type to which this entity is referenced.'))
->setSetting('is_ascii', TRUE)
->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH);
$fields['parent_field_name'] = BaseFieldDefinition::create('string')
->setLabel(t('Parent field name'))
->setDescription(t('The entity parent field name to which this entity is referenced.'))
->setSetting('is_ascii', TRUE)
->setSetting('max_length', FieldStorageConfig::NAME_MAX_LENGTH);
However the current implementation falls short if we want to fully support revisioning scenarios, because we are currently not storing the parent entity's vid. This leads to issues described in #3090200: Paragraph view access check using incorrect revision of its parent, leading to issues viewing paragraphs when reverted host entities or content moderation is used and #3084934: Paragraph access check via parent entity incorrectly uses the default revision of the parent instead of the latest where the paragraph access control check is buggy because it uses the parent's default revision for access checks instead of the correct one.
Proposed resolution
- Make all parent-related basefields revisionable (DONE in #2904231: Parent fields are not revisionable)
- Create a new basefield to store the parent's vid
- Implement an upgrade path to migrate the data of existing sites
Comments
Comment #2
miro_dietiker:-) It is.
Comment #3
miro_dietikerI think the proper parent is this.
Comment #4
jstollerI just ran into this bug and am wondering if there's any hope on the horizon.
I've got a "Logo Grid" paragraph with a nested paragraphs field containing any number of "Logo" paragraphs. Fields on the parent Logo Grid are supposed to effect the display of the individual Logos. I use getParentEntity() in a preprocess function to retrieve the values of those fields when the Logos are rendered. I just discovered that, when saving draft revisions, getParentEntity() always returns the default revision of the paragraph's parent, rather than the parent revision that references the current revision of the child paragraph. So changes to a Logo Grid are not reflected when viewing a draft node, but take effect once the draft is published. This kinda defeats the purpose of having drafts.
Comment #5
miro_dietikerWe have been hit by this multiple times, but in most cases the limitations were (unexpectedly) not critical.
So yes, i hope to summarise it correctly:
Nested child Paragraphs can not really have a dependency on the parent data as that wll always represent the default revision in a draft context. However, in our real world scenarios, we almost never have such a data situation.
What we are lacking here is a description of the impact of this limitation.
@jstoller:
Could you help us to define such common real world scenarios?
And then best would be to write a test to show how a common situation would fail.
I don't get exactly what you are doing. Rendering usually happens top down and then the right revision is loaded and rendered. How / when are you exactly calling getParentEntity?
Comment #6
jstollerI was using getParentEntity() in a preprocess function so I could set classes on child paragraph items based on field values set on their parent paragraph. For instance my Logo Grid paragraph has a size field that was intended to set a class on child Logo paragraphs, controlling how they're rendered. It worked fine once a node was published, but my users were changing the logo size and saving drafts, then getting frustrated because they didn't see anything change. Because the draft was still pulling the size value from the published revision, instead of from the latest revision.
In this case I was able to find a CSS workaround, but not without compromises. And I can easily see myself wanting to change aspects of the child paragraph that cannot be managed with CSS. Like, what if I wanted to change the image source, or the actual structure of the markup? What if I have fields on the child paragraph that should be rendered conditionally, based on the field values of it's parent?
I think it's reasonable for a paragraph to know the revision id of its parent, in addition to the entity id. Maybe we need a getParentRevision() method.
Comment #7
rgpublic@miro_dietiker: Perhaps see #2944653 (paragraphs_edit) for a real-world scenario where solving this bug matters. Currently we have to patch this to prevent this error from occurring. Obviously not an ideal situation.
Comment #8
eric_a commentedComment #9
bkosborneThis is blocking #3090200: Paragraph view access check using incorrect revision of its parent, leading to issues viewing paragraphs when reverted host entities or content moderation is used
Comment #10
dalinAnother place this pops up:
1. Use
getParentEntity()somewhere.2. View a non-default revision of the node. `getParentEntity()` is always returning the default revision of the parent, so you see something broken.
If the parent is a node there's awkward ways to work around this by getting the route object. But if the parent is another paragraph, you're screwed.
Comment #11
twodYeah, this really bites sometimes.
We've got a use case doing a lot of programmatic edits to individual paragraphs and had to come up with a helper like this instead of calling
getParentEntity()directly:The extra logging is there because we've hit all those cases with existing content which previously just called
getParentEntity()and assumed it "did the right thing".Comment #12
amateescu commentedJust closed #2949412: Nested paragraphs automatically publish, even if the parent is a draft as a duplicate of this issue, updating the parent of this one.
Comment #13
abyss commentedHi @amateescu, this is a bit strange, if you think that there is a duplicate problem here, then shouldn't you close this issue (child) instead of the parent issue which is described in #2807371: META Support Content Moderation module?
Comment #14
berliner commented@twod You forgot the
getFlatParagraphTreemethod in your code example.Comment #15
rp7 commentedJust posting here to point out that this would be incompatible with what's being discussed in #3267490: Allow composite entities to opt out of creating duplicate revisions. That would make it possible for a single paragraph revision to belong to multiple parent revisions.