Problem/Motivation
Entity::getTypedData()
instantiates and caches a typed data adapter wrapping the entity object. However ContentEntityBase
introduces the concept of entity translation object, but still relies on the parent to instantiate a typed data adapter. This implies that the first translation object on which ::getTypedData()
is called populates cache and field items no longer can retrieve the translation object they are actually attached to. This breaks the Entity Translation API badly.
Proposed resolution
Reset typed-data cache when instantiating a new translation object.
Remaining tasks
- Validate the proposed solution
- Write a patch
- Review it
User interface changes
None
API changes
None
Comment | File | Size | Author |
---|---|---|---|
#27 | et-adapters-2414721-27.patch | 2.41 KB | plach |
#27 | et-adapters-2414721-27-test.patch | 1.65 KB | plach |
Comments
Comment #1
plachThis feels critical to me but I'll leave it to major until @fago and/or @yched have seen this.
Comment #2
yched CreditAttribution: yched commentedSounds bad indeed - just feels a bit weird that no test currently catch this ?
Is it possible to narrow down a simple code snippet that breaks ?
Comment #3
Gábor HojtsyDefinitely needs tests.
Comment #4
rpayanmComment #5
fagoouch. Agreed this needs tests and feels like a critical. But then, it has no implications right now so maybe major is enough?
>Is it possible to narrow down a simple code snippet that breaks ?
Yep, was about to ask that as well.
Comment #6
BerdirComment #7
jespermb CreditAttribution: jespermb commentedHi,
I created a patch for ContentEntityBase based on the specification in this issue.
Hope it helps.
Comment #8
jespermb CreditAttribution: jespermb commentedSet status to needs review.
Comment #10
Berdir$this->typedDataByLangcode or so might be a better name?
You will also need to unset it if changes happen, search for places where typedData is currently set to NULL.
Comment #11
plachWould it make sense to use the existing class member, although it's defined differently? Maybe we can redeclare it in
ContentEntityBase
?Comment #12
jespermb CreditAttribution: jespermb commentedUpdated the name to typedDataByLangcode and added resets.
It would properly make sence to keep the typedData name but one could argue that using a different name makes it more clear what to expect and could prevent confusion.
Comment #13
Gábor Hojtsy@plach and @fago both said critical, so let's update the priority then.
Comment #14
BerdirThe question is, can we rewrite this to use $this->language()->getId()? If so, then we could possibly move this implementation up into Entity.
Then we could use $this->typedData (or rename that to byLangcode, I don't care), but we'd only have one property and one place to unset them.
As a matter of fact, even though the implementation is in Entity, it only works for content entities at the moment anyway, because we have no adapter that works for config entities.
Comment #15
BerdirSee my last comment in #2416923: Does not translate when is an anonymous user. @plach said there that this might fix the problem mentioned there, but I can no longer reproduce that bug on HEAD in my contrib module.
Given that, I think we are still lacking an actual problem caused by this that would qualify this being critical?
Comment #16
larowlanComment #17
yched CreditAttribution: yched commented+1 for not having two separate properties in Entity and ContentEntityBase.
Comment #18
BerdirYeah, agreed, but I think we should either try to only have one implementation of getTypedData() then, or if that is not possible for some reason (it should be), then we should keep the structure consistent and make them both an array, with a hardcoded language key in the base class?
Comment #19
yched CreditAttribution: yched commented+1 to #18 too :-)
Comment #20
BerdirSetting to needs work then.
Comment #21
jespermb CreditAttribution: jespermb commentedI reworked the patch so Entity->getTypedData now uses a keyed array instead.
Comment #22
BerdirWe try use something like \Drupal\Core\TypedData\ComplexDataInterface[] whenever we know what the array contains.
And we usually don't shorten variable names like that, I'd suggest $language_code instead. ($langcode is also pretty common and kind of violates what I just said)
Comment #23
plachI think I can provide a failing test: I found this while manually testing a field-based view of translated nodes as an anonymous user.
$langcode
is the only form we use (or should use) in core.Comment #24
jespermb CreditAttribution: jespermb commentedI made the changes you suggested.
If you could provide a failing test, I will have a look at it. :)
Comment #25
plachSure, I will try later tonight. Thanks for working on this :)
Comment #26
BerdirSetting to needs work for tests :)
Comment #27
plachI found a better way to fix this, I think.
Tests attached.
Comment #28
plachComment #35
plachThat failure is unrelated, tests are green locally.
Comment #37
plachComment #38
yched CreditAttribution: yched commentedLatest approach seems right indeed - since the translated entities are cloned, no need to keep arrays of TypedDataadapters keyed by language in each of them.
Looks RTBC to me
Comment #39
alexpottWhat is the relationship between this and
in ContentEntityBase... I noticed this hunk in #2227227: FieldTypePluginManager cannot instantiate FieldType plugins, good thing TypedDataManager can instantiate just about anything
Comment #40
plachThat is covering the case where the entity object is deep-cloned, it's not related with instantiating a translation object, which is instead just an alternative wrapper around the same field objects. However, since in both cases we end-up having a different entity object, in both cases we need a new adapter.
Comment #41
alexpottThis issue addresses a critical bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 42083a1 and pushed to 8.0.x. Thanks!
Comment #43
plachAwesome, thanks
Comment #44
Gábor HojtsyYay, thanks all!