Problem/Motivation
Entity reference revisions currently is the key tool to maintain composite entities and their reference integrity.
Core is limited that it does not define anything like a composite entity.
If we introduce the new concept, we need to be clear, maintain all related problems and limit all complexity.
Proposed resolution
If something is a composite, the parent relationship needs to be maintained by ERR.
See #2585447-14: Entity Access does not check host entity
This means that the entity host is immutable and due to the field API design it's needed to resolve the parent relationship from the item. And the access check by paragraphs is needed and thus (with knowing that there is only one parent) simple.
We still want to see integrity management delegated as much as possible to entity reference revisions:
ERR introduces the concept of a composite entity. It will support parent_type/parent_id keys in the annotation of the target entity that define the parent entity type and id field name. ERR will then make sure that the IDs are persisted on creation, and also will delete child items.
See also deletion: #2429335: Deletion of referenced entities
We also need to introduce an extension point to notify a module like paragraphs that builds on top of us so it can take action.
Remaining tasks
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #35 | interdiff-2641824-32-35.txt | 1.65 KB | johnchque |
| #35 | maintain_composite-2641824-35.patch | 8 KB | johnchque |
| #32 | interdiff-2641824-26-32.txt | 3.88 KB | johnchque |
| #32 | maintain_composite-2641824-32.patch | 8.02 KB | johnchque |
| #26 | interdiff-2641824-26-no-entity-keys.txt | 4.42 KB | johnchque |
Comments
Comment #2
miro_dietikerComment #3
johnchqueOverriding PostSave function to assign id and parent type on creation.
Comment #5
johnchqueTests fixed, it was a trivial fix, after commit this we can continue on paragraphs module.
Comment #6
miro_dietikerUh, this leads to a double save. This should happen much earlier and no explicit save call ever (remember the TMGMT preview issue...).
Comment #7
berdirNo, a save is needed. But it's the $entity that has to be set and saved, not $this.
Comment #8
johnchqueChanges made. Should be Ok now.
Comment #9
berdirAs discussed, lets add some test coverage to make sure that this actually works.
Comment #10
johnchqueTests added. A lot of changes. Should work now.
Comment #11
berdirThis needs comments to explain what we are doing here. Explain the concept and the different checks and why they are necessary.
Might also be easier to read if you have a $parent_type_key variable, then those lines will get a lot shorter.
Given that this is about revisionable entities, we might want to ensure that no new revision is saved when updating this.
this seems unrelated, same for the one below?
remove this
we no longer need this.
same.
first part repeats the class documentation. maybe we can make the more specific second line a bit shorter so it fits on a single line and can be the only documentation here?
lets pick a separate name for he field as the entity_type, this will be easier to understand then. composite_reference, maybe?
I don't think we need to test this. I still want to find a way to not make them required and NULL by default.
the description doesn't seem very useful. You don't need to repeat the value. I'd just leave it out.
Comment #12
johnchqueChanges made based on comment #11 about the second point I made those changes to make the test pass. It seems something has changed because the previous test fails where caused because of that space change. (See https://www.drupal.org/pift-ci-job/164228)
Comment #14
johnchqueI have checked and this seems to cause the test fail. Should we keep it like entity_test_composite?
Comment #15
johnchqueSo sorry, I should have updated the reference everywhere. Should work now.
Comment #16
miro_dietikerDiscussed with Berdir, since a new paragraph temporarily needs to be temporarily saved without any parent value at all (and the connection happens later in the save cycle), NULL should be a valid value and no pseudo "unknown" value should be needed. He will investigate the problem.
Comment #17
johnchqueDiscussed with @Berdir, the field parent_name has been added. Also fixed the variable names a bit and the comments.
Comment #18
berdirI think the key should be more specific, parent_field_name. Just name doesn't explain what it is.
Also, parent_field_name should be optional. It should be possible for an entity type to only have parent_type and parent_id. so check parent_name additional, within.
that will make this a bit complicated, since we do not want to trigger this if there was no change and there is no parent_field_name.
You need a combined || $parent_name_key && .. the check) condition, which will make this very long. Maybe split out the different checks all into variables and then combine it ($parent_type_changed || $parent_id_changed || ...
Comment #19
johnchqueChanges made, now it seems easier to understand.
Comment #20
berdirOh. That's not exactly what I was thinking about but actually, I like this approach.
except, when you do it like this, a single variable is enough.. I'd use $needs_save = FALSE;
You also shouldn't set it to the return value of $entity->set, you should explicitly/separately set it to TRUE in the if.
Comment #21
johnchqueThat is totally right, it should be better in that way. Interdiff added.
Comment #22
miro_dietikerI think an early exit flattens the method much down if no entity and parent entity can not be loaded.
Formally there is no real transactional guarantee this load succeeds.
Comment #23
berdir1. You could do a combined if ($this->entity && parent_type && parent_id) and return early, that would save two nested if's, yes.
2. getEntity() is not a load. It is the entity the item is attached to. And this happens during saving, which absolutely requires an entity. So yes, I'd say you can rely on this.
Comment #24
johnchque1. Wouldnt make that the if too long?, actually I think it should stay like that especially because we get the entity_type after get the entity.
Otherwise it would be something like
Comment #25
berdirI think we can live with that. The idea is that you would make it a negative check.
That should make it easier to read the code as you have two nested if's less.
Also, I like using single empty lines between different parts of the code, that helps to visually group them.
Comment #26
johnchqueAdded two different patches, the first one is based on comment #25 and the second is not using entity_keys anymore (no-entity-keys.patch), both work in the same way. With these patches we can decide if we will use entity keys and set a default value to them or not using entity keys at all.
Comment #27
miro_dietikerNote that for real cases such as paragraphs we will need an index defined that is (parent_type, parent_id, parent_field_name)
See example in \Drupal\node\NodeStorageSchema::getEntitySchema
More review pending.
Comment #28
miro_dietikerAnd yeah, core forces NOT NULL for entity keys and we don't want that. Thus we want to go for the non-entity-keys approach.
Comment #29
berdirHow the comments in the patch refer to the field names now could possibly be slightly improved now. I'd suggest to use "parent type" and refer to it as a concept and not a key or variable name (instead of parent_type, or parent_type_key and similar things that are used right now. For example "If parent_field_name_key has changed then set it.", we don't *set* the key, the key just tells us the field name for which we want to set the value. If you write "parent field name" instead, then that makes perfect sense.
Miro can probably do this on commit.
Otherwise this looks good to me.
Comment #30
miro_dietikerI was fixing the comments and then ended up with this commit killer:
The parent field name should contain the field name that represents the reference to the composite entity.
That has absolutely nothing to do with the entity / node label.
Comment #31
miro_dietikerI would also like to see the references checked as parent_type, parent_id, parent_field_name
Comment #32
johnchquePatch added based on comments above, continuing with the non entity keys branch. Should work now.
Comment #33
miro_dietikerNitpick to make it ready:
Should be hardcoded here as "composite_reference".
Comment #34
miro_dietikerAh, language...
It's not "neither... nor" it's if "any of... missing"
Comment #35
johnchqueChanges made. :)
Comment #36
miro_dietikerYay! Looks nice, committing.
Now let's fix all the previously blocked things such as delete and access check... :-)