Problem/Motivation

A subfield type can store extra properties in sibling columns named <subfield>__<suffix>. Several data types write those columns as a side effect of their own setValue(). Core's Map::setValue() then re-syncs every
already-instantiated property object from the values array it was handed, so an extra property missing from that array is reset to NULL.

Whether the property object already exists at that moment depends on what else in the request has touched a field item of the same type, so the loss is ordering-dependent. Any code path that sets the same field item more than once with a nested value — for example an entity edited and re-set within one request — therefore loses the extras.

(#3620797: Viewsfield display not being saved ) added getExtraPropertyNames() and extractExtraPropertyValues() to CustomFieldTypeInterface and used them to complete the values array for viewfield, which was the only type broken on the form path. The same override closes this path for the remaining types.

Affected types and measurements

Measured with an identical kernel probe on 5.0.1 and on 5.0.2, three scenarios:
a nested value set once, a nested value set twice, and the form shape.

Type Extras Set twice from code Status
link __title, __options lost pre-existing; see note below
datetime __timezone lost pre-existing, identical on 5.0.1 and 5.0.2
daterange __end, __timezone lost pre-existing, identical on both
time_range __end lost pre-existing, identical on both
image __alt, __title lost pre-existing, identical on both

None of these is a 5.0.2 regression. The form path is unaffected for all of them: the promotion in CustomWidgetBase::massageFormValues() supplies the flat keys because their submitted keys already equal their column suffixes. A paragraph-form test covering datetime, daterange, time_range and image (SiblingTypesParagraphsTest) passes, and link is covered by ParagraphsIntegrationTest.

Note on link. An earlier investigation reported link as a 5.0.2 regression. That was wrong. The eager-instantiating constructors removed in 5.0.2 only ran for the first instance of a given property prototype in a request —
TypedDataManager::getPropertyInstance() builds a prototype once per key and clones it thereafter — so 5.0.1 was non-deterministic, keeping the extras only for whichever field was touched first. Reversing the order of two link fields in one test process flips which one keeps its data. This also explains why link extras were not saving inside paragraphs on 5.0.1, which 7093ffc fixed.

Steps to reproduce

  1. Create a custom field with a `link` subfield (any of the types above works).
  2. From code:
    $values = [['lnk' => [
         'uri' => 'https://example.com',
         'title' => 'Example',
         'options' => ['attributes' => ['target' => '_blank']],
       ]]];
       $node->get('field_x')->setValue($values);
       $node->validate();
       $node->get('field_x')->setValue($values);
       $node->save();
  3. Reload the node. `lnk__title` and `lnk__options` are `NULL`.

Proposed resolution

Override extractExtraPropertyValues() on each type plugin, copying that type's
own setValue() guard verbatim so stored values do not change:

  • LinkTypeisset() on title and options; options only when it is an array.
  • ImageTypeisset() on alt and title only. Do not include width/height` CustomItem::preSave() re-derives them from the file, so adding them would change what is stored.
  • DateTimeTypeisset() on timezone.
  • DateRangeTypeend and timezone, but only when the main value is non-empty, matching CustomFieldDateRange::setValue().
  • TimeRangeTypeend only when both the start and the end are non-empty (Time::isEmpty()), matching CustomFieldTimeRange::setValue().

Each needs a stored-value data provider like viewfield's 13-case one, run green before and after, plus a repeated- setValue() regression test. The guards differ per type (isset() versus !empty() versus conditional), and getting one wrong changes clearing semantics — so no shared default until the wider refactor.

Comments

apmsooner created an issue. See original summary.

apmsooner’s picture

Issue summary: View changes
apmsooner’s picture

Issue summary: View changes