Problem/Motivation

The default content system added with the drush content:export command (Drupal\Core\DefaultContent\Exporter / Importer, #3532694: Add a command-line utility to export content in YAML format) cannot round-trip a field of type map:

  • Export drops the data. Exporter::exportFieldItem() iterates $item->getProperties(). A map field item (MapItem) defines no static property definitions — propertyDefinitions() returns [] — so getProperties() is empty and the field exports as - { } (an empty map), losing all stored data.
  • Import throws. Importer::setFieldValues() treats each key of a delta as a typed-data property and calls $item->get($property_name). For a map item every property name is unknown, so import aborts with InvalidArgumentException: Property <key> is unknown.

There is no way for a site or module to make a populated map field survive content:export + import. The export side has an extension point (PreExportEvent::setCallback()), but the import side has no field-type callback at all, so even a custom export format cannot be read back in.

This affects any content entity with a populated map field / base field — for example ai_context's ai_context_item.scope, and other modules that use MapItem for arbitrary serialized data.

Steps to reproduce

  1. On a standard install, take any content entity type with a map field (or add one). Store keyed data in it, e.g. ['use_case' => ['working_with_media']].
  2. Export it: drush content:export <entity_type> <id> --dir=… (or call Exporter::export()). Inspect the YAML — the map field is - { }; the data is gone.
  3. Hand-author the real map value into the YAML default section and import it (Importer::importContent()). Import aborts with Property <key> is unknown.

Reproduced on core 11.3.14.

Proposed resolution

Special-case map fields in both directions, since a map item's value is the whole array rather than a set of named properties:

  • Exporter::exportFieldItem() — when the field type is map, return $item->getValue() (the whole stored array) instead of walking properties.
  • Importer::setFieldValues() — when the field type is map, call $item->setValue($item_value) for the whole delta and skip the per-property loop.

The two sides are symmetric: the exporter writes the delta as the map array, and the importer reads that same shape straight back with setValue().

// Exporter::exportFieldItem(), before the getProperties() loop:
if ($item->getFieldDefinition()->getType() === 'map') {
  return $item->getValue();
}

// Importer::setFieldValues(), right after $item = …->get($delta):
if ($item->getFieldDefinition()->getType() === 'map') {
  $item->setValue($item_value);
  continue;
}

Remaining tasks

  • Review the approach: a type check on 'map' vs. a broader "field item exposes no properties" and check for all-computed-property fields.
  • Add test coverage: a kernel test that exports and re-imports an entity with a populated map field and asserts the value survives (export is non-empty, import does not throw, stored value matches).
  • Confirm behaviour for empty map values (should export - { } and import to an empty value without error.

User interface changes

None.

Introduced terminology

API changes

None. Behavioural fix only: map fields that previously exported empty and could not be imported now round-trip their stored value. No signatures change.

Data model changes

Release notes snippet

The default content system (drush content:export and the DefaultContent importer) now correctly exports and imports map field values, which were previously dropped on export and rejected on import.

CommentFileSizeAuthor
#2 3617512-2.patch1.6 KBjibran

Issue fork drupal-3617512

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

jibran created an issue. See original summary.

jibran’s picture

Status: Active » Needs review
StatusFileSize
new1.6 KB

Uploading a patch for now. This isn't a proper fix, but it gets the job done.

jibran’s picture

jibran’s picture