Problem/Motivation
While trying to add a MapItem field to a content entity, a bug becomes evident that loading and saving the entity results in the value of the map becoming NULL.
berdir found the root cause in ContentEntityDatabaseStorage::mapToStorageRecord which hard-codes $entity->$name->value even though the "value" property of a field is not supposed to have a special meaning.
Proposed resolution
use the getMainPropertyName() method of the field definition to find which property to use, or whether (as for MapItem) all properties should be saved.
Remaining tasks
Add tests demonstrating the bug and fix.
API changes
none
Comments
Comment #1
pwolanin commentedHere's a 1st patch, largely the work of berdir from the menu links sandbox.
Comment #2
andypostLooks good, just a question
Maybe supposed "first value"
Comment #3
fagoPatch looks good, just one remark:
That seems weird, why not just $entity->$name->$main_property ?
If we go with methods we should probably do for $name and $main_property.
Comment #4
fagoThat seems a bit weird but I guess it's required for the MapItem to work. Should we add a @todo to resolve this as part of #2232427: Allow field types to control how properties are mapped to and from storage?
Comment #5
berdirI prefer to use get() because PhpStorm always adds those hints if you just do $name :) We have no method for ->$main_property that would do the same... would have to call getValue() then.
Adding a todo sounds good, but it's not enough, as we also need that special case for no main property. For example, compare MapItem and LinkItem, both need the serialization, but on a different level. We can combine it with better explaining what we are doing there to solve #1.
Comment #6
pwolanin commentedAs suggested by berdir, here's a small addition to the shortcut test that loads saves and re-loads a content entity that has a MapItem.
I get fails - the values don't match. This patch resolves the fails. The increment is the test-only patch.
Setting back to CNR to let the tests run. I'm not totally clear from #4 and 5 what kind of todo or other code doc is needed?
Comment #8
berdirSomething like this I think.
Comment #9
yched commentedMinor :
I know the method is named ->getValue() (wasn't there an issue to rename it to toArray() BTW ?), but
"If there is no main property, get all *s/values/properties/*" would be clearer IMO.
Also, that whole mapToStorageRecord() method only knows how to store single-values fields anyway, so it would be a bit clearer if we started with an unconditional
$item = $entity->get($name)->first();, and then do "this or that", rather than having comments in each if () branch explain that they both happen to restrict to the first item.Other than that, looks good. I guess most of this "reasoning on the shape of the schema" will be moot anyway when schemas for base tables get auto-generated ?
+ Posted some thoughts about the notion of "main property", on which we attach more and more behavior, but that remains worringly vague IMO : #2269599: Clarify the notion of "main property" for a Field Type
Comment #10
pwolanin commentedOk, I think this has all the changes yched suggests.
Comment #11
yched commentedThanks. Works for me if still green.
Comment #12
yesct commentedI came by here catching up on #2227441: New plan, Phase 1:Review the architecture and overall implementation proposal for menu links as plugins and read through the whole patch. I noticed two tiny things (no : in @todo https://drupal.org/node/1354#todo and a sentence missing a period)
This should still be rtbc.
Comment #13
yesct commentedI think the toArray() issue @yched was looking for is #2225943: Use toArray() instead of getValue() where applicable for field items and lists of field items
Comment #14
berdirThanks, clean-up looks good.
Comment #15
fagoYep, this looks good now. RTBC+1.
Comment #16
catchCommitted/pushed to 8.x, thanks!
Comment #19
catchMissed that this was retesting, reverting for now.
Comment #20
catch12: 2267753-12.patch queued for re-testing.
Comment #22
berdir12: 2267753-12.patch queued for re-testing.
Comment #25
amateescu commentedRerolled after #2190313: Add $EntityType::load() and loadMultiple() to simplify loading entities.
Comment #26
amateescu commentedMore reroll :)
Comment #28
berdirThanks, re-roll looks good, bad timing.
Comment #29
catchCommitted/pushed to 8.x, thanks!
Comment #30
pwolanin commentedThanks!