.../Core/Field/Plugin/Field/FieldType/MapItem.php | 9 ++++-- .../EntityResource/EntityResourceTestBase.php | 5 ++-- .../EntityTest/EntityTestMapItemNormalizerTest.php | 10 ++----- .../serialization/serialization.services.yml | 10 +++++-- .../src/Normalizer/MapItemNormalizer.php | 35 ++++++++++++++++++++++ ...ormalizer.php => PropertylessMapNormalizer.php} | 12 ++++++-- 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php index e15fe84..87a787c 100644 --- a/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php +++ b/core/lib/Drupal/Core/Field/Plugin/Field/FieldType/MapItem.php @@ -4,6 +4,7 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\FieldItemBase; +use Drupal\Core\TypedData\MapDataDefinition; /** * Defines the 'map' entity field type. @@ -22,8 +23,12 @@ class MapItem extends FieldItemBase { * {@inheritdoc} */ public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) { - // The properties are dynamic and can not be defined statically. - return []; + return [ + // All map fields store their data in a single 'value' property, but this + // itself expands to an arbitrary map. + // @see \Drupal\Core\TypedData\Plugin\DataType\Map + 'value' => MapDataDefinition::create()->setLabel(t('Serialized array of values')), + ]; } /** diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php index 669382d..a3436fa 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceTestBase.php @@ -914,8 +914,7 @@ public function testPost() { if ($created_entity->hasField($field_name)) { // Subset, not same, because we can e.g. send just the target_id for the // bundle in a POST request; the response will include more properties. - $this->assertArraySubset(static::castToString($field_normalization), $created_entity->get($field_name) - ->getValue(), TRUE); + $this->assertArraySubset(static::castToString($field_normalization), $created_entity_normalization[$field_name], TRUE); } } } @@ -1175,7 +1174,7 @@ public function testPatch() { if ($updated_entity->hasField($field_name)) { // Subset, not same, because we can e.g. send just the target_id for the // bundle in a PATCH request; the response will include more properties. - $this->assertArraySubset(static::castToString($field_normalization), $updated_entity->get($field_name)->getValue(), TRUE); + $this->assertArraySubset(static::castToString($field_normalization), $updated_entity_normalization[$field_name], TRUE); } } // Ensure that fields do not get deleted if they're not present in the PATCH diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityTest/EntityTestMapItemNormalizerTest.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityTest/EntityTestMapItemNormalizerTest.php index a8ed859..194bce3 100644 --- a/core/modules/rest/tests/src/Functional/EntityResource/EntityTest/EntityTestMapItemNormalizerTest.php +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityTest/EntityTestMapItemNormalizerTest.php @@ -44,9 +44,7 @@ protected function getExpectedNormalizedEntity() { // normalization because setExposed(TRUE) was not called for this property. // @see \Drupal\entity_test\Plugin\Field\FieldType\ExposedPropertyTestFieldItem::propertyDefinitions $expected['field_map'] = [ - [ - 'value' => static::$mapValue, - ], + static::$mapValue ]; return $expected; } @@ -59,7 +57,7 @@ protected function createEntity() { FieldStorageConfig::create([ 'entity_type' => 'entity_test', 'field_name' => 'field_map', - 'type' => 'map_test', + 'type' => 'map', 'cardinality' => 1, 'translatable' => FALSE, ])->save(); @@ -85,9 +83,7 @@ protected function createEntity() { protected function getNormalizedPostEntity() { return parent::getNormalizedPostEntity() + [ 'field_map' => [ - [ - 'value' => static::$mapValue, - ], + static::$mapValue, ], ]; } diff --git a/core/modules/serialization/serialization.services.yml b/core/modules/serialization/serialization.services.yml index 4da7dab..c374043 100644 --- a/core/modules/serialization/serialization.services.yml +++ b/core/modules/serialization/serialization.services.yml @@ -52,6 +52,12 @@ services: # Priority must be higher than serialization.normalizer.field but less # than hal field normalizer. - { name: normalizer, priority: 9 } + serializer.normalizer.map_item: + class: Drupal\serialization\Normalizer\MapItemNormalizer + tags: + # Priority must be higher than serializer.normalizer.field_item and lower + # than hal normalizers. + - { name: normalizer, priority: 8 } serializer.normalizer.timestamp_item: class: Drupal\serialization\Normalizer\TimestampItemNormalizer tags: @@ -71,8 +77,8 @@ services: class: Drupal\serialization\Normalizer\TypedDataNormalizer tags: - { name: normalizer } - serializer.normalizer.map: - class: Drupal\serialization\Normalizer\MapNormalizer + serializer.normalizer.map.propertyless: + class: Drupal\serialization\Normalizer\PropertylessMapNormalizer tags: # This normalizer must be higher than serializer.normalizer.complex_data so # that serializer.normalizer.complex_data is not used for Map objects that diff --git a/core/modules/serialization/src/Normalizer/MapItemNormalizer.php b/core/modules/serialization/src/Normalizer/MapItemNormalizer.php new file mode 100644 index 0000000..0c501d6 --- /dev/null +++ b/core/modules/serialization/src/Normalizer/MapItemNormalizer.php @@ -0,0 +1,35 @@ + $data]; + } + +} diff --git a/core/modules/serialization/src/Normalizer/MapNormalizer.php b/core/modules/serialization/src/Normalizer/PropertylessMapNormalizer.php similarity index 60% rename from core/modules/serialization/src/Normalizer/MapNormalizer.php rename to core/modules/serialization/src/Normalizer/PropertylessMapNormalizer.php index 24c1a76..7309794 100644 --- a/core/modules/serialization/src/Normalizer/MapNormalizer.php +++ b/core/modules/serialization/src/Normalizer/PropertylessMapNormalizer.php @@ -6,12 +6,12 @@ use Drupal\Core\TypedData\Plugin\DataType\Map; /** - * Converts Map objects into arrays. + * Converts propertyless Map objects into arrays. * * This normalizer only supports Map objects that do not have have property * definitions. */ -class MapNormalizer extends TypedDataNormalizer { +class PropertylessMapNormalizer extends TypedDataNormalizer { /** * {@inheritdoc} @@ -26,8 +26,16 @@ public function supportsNormalization($data, $format = NULL) { if (parent::supportsNormalization($data, $format)) { $definition = $data->getDataDefinition(); if ($definition instanceof ComplexDataDefinitionInterface && empty($definition->getPropertyDefinitions())) { + // Map objects without properties defined must be treated specially: the + // top-level keys stored must be considered the properties during + // normalization. The parent ::normalize() method does this. return TRUE; } + else { + // Map objects with properties defined can be handled by + // \Drupal\serialization\Normalizer\ComplexDataNormalizer::normalize(). + return FALSE; + } } return FALSE; }