Found out in #2164601-48: Stop auto-creating FieldItems on mere reading of $entity->field[N] :
On an EntityRefItem :
- $item->entity = $existing_entity populates $item->target_id with $existing_entity->id() :
\Drupal\Core\Entity\Plugin\DataType\EntityReference::setValue() calls \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem::onChange(), which assigns the target_id property
- but $item->setValue(array('entity' => $existing_entity)) does not assign the $item->target_id,
which triggers lots of interesting fails.
Not sure exactly where this needs to be fixed yet.
Major, because code will work or break depending on the syntax you use to populate your item.
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | 2386559-test-only.patch | 2.05 KB | jibran |
| #21 | d8_er_item.patch | 3.9 KB | fago |
Comments
Comment #1
yched commentedComment #2
yched commentedSince the assignment of the target_id is taken care of by EntityReferenceItem::onChange(), which isn't triggered by Item::setValue(), maybe there should also be some special code in EntityReferenceItem::setValue() to populate the 'target_id' if the 'entity' property was part of the passed value ?
Comment #3
yched commentedAs a proof-of-concept fail in "drush php" :
Comment #4
yched commentedAttached patch seems to fix this - this would really need to be approved by @fago though, because the sync between 'target_id' and 'entity' goes through a notify dance that loses me a bit :-).
Also, this will need tests, once the fix is agreed.
Comment #5
amateescu commentedWould this be enough for testing?
Comment #6
yched commentedYep, the tests look great, thanks @amateescu :-)
Comment #8
yched commentedPatch from #4 + tests from #5
Comment #9
amateescu commentedI felt like we're missing something here (and in the test coverage too) but it took me a few good minutes to put my finger on it:
What happens if we assign both 'target_id' and 'entity' at the same time, but with "unsynced" values (e.g. 'target_id' => 1 and 'entity' => $entity_for_which_the_id_is_not_1)?
My guess is that we should also take care of this case and throw an InvalidArgumentException. This might even be a potential security issue I suppose :)
Comment #10
yched commentedIndeed - even with current patch :
Comment #11
amateescu commentedThat's hilarious :) Good thing we found it while just poking around this code and not after 8.0.0.
Comment #12
yched commentedAlso, looks like LanguageItem will need the same fixes, it is likely to have the same issues for its 'value' and 'language' properties.
Comment #13
fagoYeah, in general you have to pass a valid $item array in setValue() if you pass an array. However, the case for the synced reference items is a bit special and I agree that it should take care of both cases with only one of both properties being passed in.
Yep, language reference item has the same flow and should be fixed as well. However, I'd propose a fix that re-uses existing onChange() logic instead of re-inventing in setValue(). So instead is another patch, which keeps tests of #8 only.
Comment #15
fagoDiscussed the best code-flow with yched. Attached patch implements an idea to improve it for ERI, but doesn't update LanguageItem yet. Looked through the onChange() methods to unify them, but that's not really related to this issue. (didn't look at test fails yet either).
Comment #16
fagoMoved the unrelated changes to its existing issue: #2137309: Typed data does not handle set() and onChange() consistently
Comment #18
yched commentedYay, that approach looks way easier to follow :-)
We should comment this better IMO :
Also, we should raise an exception if $values contain both 'entity' and 'target_id' that contradict each other. That could go in that if / elsif group ? We'd still call parent::setValue() for nothing, but that's not too important ?
Nitpick : "Synchronizes the values of the 'target_id' and 'entity' properties" ?
nitpick : double space
Comment #19
plachThis is blocking a critical issue.
Comment #20
plachPlans changed: this is now postponed on #2232477: Fatal when adding new fields with NOT NULL constraints in a base table that contains existing entities.
Comment #21
fagoUpdated the patch based on #2137309: Typed data does not handle set() and onChange() consistently / HEAD. This shuold be fine for the ER item, but does not account for the language item yet. We should add test coverage for any language item changes as well though imo.
Setting for needs review so the bot can give it a try.
Comment #22
fagoComment #23
plach#2232477: Fatal when adding new fields with NOT NULL constraints in a base table that contains existing entities is hard to get right now. Let's get this done first...
Comment #24
plachIt seems in this case we are setting nothing.
Comment #25
jibranPatch looks good to me over all. Here is a test only patch.
Comment #26
plachForget #24, now I get it.
Comment #28
plachAwesome, patch to commit is in #21.
Comment #29
jibranRTBC +1
Comment #30
effulgentsia commentedTagging to reflect that #2232477: Fatal when adding new fields with NOT NULL constraints in a base table that contains existing entities is postponed on this, per #23.
Comment #31
webchickCommitted and pushed #21 to 8.0.x. Thanks!
Looks like we need a child issue for LanguageItem. Can someone take care of that quickly?
Comment #34
jibranDo we still need a follow up for LanguageItem?
Comment #35
plachAFAIK, yes, at least I didn't create one