diff --git a/core/modules/hal/src/Normalizer/FieldItemNormalizer.php b/core/modules/hal/src/Normalizer/FieldItemNormalizer.php index 0c2ee9ed4d..72c28a3383 100644 --- a/core/modules/hal/src/Normalizer/FieldItemNormalizer.php +++ b/core/modules/hal/src/Normalizer/FieldItemNormalizer.php @@ -2,6 +2,7 @@ namespace Drupal\hal\Normalizer; +use Drupal\Core\Entity\FieldableEntityInterface; use Drupal\Core\Field\FieldItemInterface; use Symfony\Component\Serializer\Exception\InvalidArgumentException; @@ -127,9 +128,43 @@ protected function createTranslatedInstance(FieldItemInterface $item, $langcode) // Instead, create a new item for the entity in the requested language. $entity = $item->getEntity(); - $entity_translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $entity->addTranslation($langcode); + // Get the translated entity, or create it if it does not exist. + $entity_translation = $entity->hasTranslation($langcode) ? $entity->getTranslation($langcode) : $this->createTranslatedEntity($entity, $langcode); $field_name = $item->getFieldDefinition()->getName(); - return $entity_translation->get($field_name)->appendItem(); + $field = $entity_translation->get($field_name); + + // Append an item only if the item list is empty or allows multiple values. + if (!count($field) || $item->getFieldDefinition()->getFieldStorageDefinition()->isMultiple()) { + return $field->appendItem(); + } + return $field->first(); + } + + /** + * Create an empty entity translation to fill with field data. + * + * @param \Drupal\Core\Entity\FieldableEntityInterface $entity + * The untranslated entity. + * @param string $langcode + * The langcode. + * + * @return \Drupal\Core\Entity\FieldableEntityInterface + * The translated entity. + */ + protected function createTranslatedEntity(FieldableEntityInterface $entity, $langcode) { + // Create a new translation. + /** @var \Drupal\Core\TypedData\TranslatableInterface $entity */ + /** @var \Drupal\Core\Entity\FieldableEntityInterface $entity_translation */ + $entity_translation = $entity->addTranslation($langcode); + + // Remove all default values, except for the langcode. + $translated_fields = $entity_translation->getTranslatableFields(FALSE); + unset($translated_fields['langcode']); + foreach ($translated_fields as $field) { + $field->setValue([]); + } + + return $entity_translation; } } diff --git a/core/modules/hal/tests/src/Kernel/TranslationNormalizeTest.php b/core/modules/hal/tests/src/Kernel/TranslationNormalizeTest.php new file mode 100644 index 0000000000..bb0eb5276d --- /dev/null +++ b/core/modules/hal/tests/src/Kernel/TranslationNormalizeTest.php @@ -0,0 +1,49 @@ +installEntitySchema('entity_test_mul_changed'); + + } + + /** + * Tests normalizing and denormalizing an entity. + */ + public function testTranslationNormalize() { + $target_entity = EntityTestMulChanged::create((['langcode' => 'en', 'field_test_entity_reference' => NULL])); + $target_entity->save(); + + $target_entity->addTranslation('de', $target_entity->toArray()); + + $this->assertEquals(1, count($target_entity->changed)); + $this->assertEquals(1, count($target_entity->getTranslation('en')->changed)); + $this->assertEquals(1, count($target_entity->getTranslation('de')->changed)); + + $data = $this->serializer->normalize($target_entity, 'hal_json'); + $denormalized_entity = $this->serializer->denormalize($data, $this->entityClass, 'hal_json'); + + $this->assertEquals(1, count($denormalized_entity->changed)); + $this->assertEquals(1, count($target_entity->getTranslation('en')->changed)); + $this->assertEquals(1, count($denormalized_entity->getTranslation('de')->changed)); + } + +}