From a46c46194d2998f3f6a5c09d387512cc98c7c25c Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Mon, 18 Jun 2018 09:28:31 +0100
Subject: [PATCH] Issue #2935738 by samuel.mortenson, Wim Leers, Berdir: Entity
 reference field subclasses (such as file and image fields) lose the
 non-default properties upon denormalization, in both hal_json and json

---
 .../EntityReferenceItemNormalizer.php         |  2 +-
 .../Functional/FileUploadResourceTestBase.php |  4 --
 .../EntityReferenceFieldItemNormalizer.php    |  2 +-
 ...EntityReferenceFieldItemNormalizerTest.php | 40 +++++++++++++++++++
 4 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
index de9fdc73610a..a9fc7e6b3b58 100644
--- a/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
+++ b/core/modules/hal/src/Normalizer/EntityReferenceItemNormalizer.php
@@ -149,7 +149,7 @@ protected function constructValue($data, $context) {
     $target_type = $field_definition->getSetting('target_type');
     $id = $this->entityResolver->resolve($this, $data, $target_type);
     if (isset($id)) {
-      return ['target_id' => $id];
+      return ['target_id' => $id] + array_intersect_key($data, $field_item->getProperties());
     }
     return NULL;
   }
diff --git a/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php b/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php
index 05aa5ea58657..42c7b2c50a83 100644
--- a/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php
+++ b/core/modules/rest/tests/src/Functional/FileUploadResourceTestBase.php
@@ -199,10 +199,6 @@ public function testPostFileUpload() {
     $response = $this->request('POST', $entity_test_post_url, $request_options);
     $this->assertResourceResponse(201, FALSE, $response);
     $this->assertTrue($this->fileStorage->loadUnchanged(1)->isPermanent());
-    // @todo Remove this early return in https://www.drupal.org/project/drupal/issues/2935738.
-    if (static::$format === 'hal_json') {
-      return;
-    }
     $this->assertSame([
       [
         'target_id' => '1',
diff --git a/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php b/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
index 2d3c6f012b89..4865c909795f 100644
--- a/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
+++ b/core/modules/serialization/src/Normalizer/EntityReferenceFieldItemNormalizer.php
@@ -78,7 +78,7 @@ protected function constructValue($data, $context) {
         throw new UnexpectedValueException(sprintf('The field "%s" property "target_type" must be set to "%s" or omitted.', $field_item->getFieldDefinition()->getName(), $target_type));
       }
       if ($entity = $this->entityRepository->loadEntityByUuid($target_type, $data['target_uuid'])) {
-        return ['target_id' => $entity->id()];
+        return ['target_id' => $entity->id()] + array_intersect_key($data, $field_item->getProperties());
       }
       else {
         // Unable to load entity by uuid.
diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
index 9320d17ba27f..96274a675fdf 100644
--- a/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
+++ b/core/modules/serialization/tests/src/Unit/Normalizer/EntityReferenceFieldItemNormalizerTest.php
@@ -4,12 +4,14 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\TypedData\Type\IntegerInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\Entity\EntityRepositoryInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\FieldItemInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\locale\StringInterface;
 use Drupal\serialization\Normalizer\EntityReferenceFieldItemNormalizer;
 use Drupal\Tests\UnitTestCase;
 use Prophecy\Argument;
@@ -237,6 +239,9 @@ public function testDenormalizeWithTypeAndUuid() {
       ->willReturn($entity)
       ->shouldBeCalled();
 
+    $this->fieldItem->getProperties()->willReturn([
+      'target_id' => $this->prophesize(IntegerInterface::class),
+    ]);
     $this->fieldItem->setValue(['target_id' => 'test'])->shouldBeCalled();
 
     $this->assertDenormalize($data);
@@ -260,6 +265,9 @@ public function testDenormalizeWithUuidWithoutType() {
       ->willReturn($entity)
       ->shouldBeCalled();
 
+    $this->fieldItem->getProperties()->willReturn([
+      'target_id' => $this->prophesize(IntegerInterface::class),
+    ]);
     $this->fieldItem->setValue(['target_id' => 'test'])->shouldBeCalled();
 
     $this->assertDenormalize($data);
@@ -361,4 +369,36 @@ protected function assertDenormalize(array $data) {
     $this->assertSame($context['target_instance'], $denormalized);
   }
 
+  /**
+   * @covers ::constructValue
+   */
+  public function testConstructValueProperties() {
+    $data = [
+      'target_id' => 'test',
+      'target_type' => 'test_type',
+      'target_uuid' => '080e3add-f9d5-41ac-9821-eea55b7b42fb',
+      'extra_property' => 'extra_value',
+    ];
+
+    $entity = $this->prophesize(FieldableEntityInterface::class);
+    $entity->id()
+      ->willReturn('test')
+      ->shouldBeCalled();
+    $this->entityRepository
+      ->loadEntityByUuid($data['target_type'], $data['target_uuid'])
+      ->willReturn($entity)
+      ->shouldBeCalled();
+
+    $this->fieldItem->getProperties()->willReturn([
+      'target_id' => $this->prophesize(IntegerInterface::class),
+      'extra_property' => $this->prophesize(StringInterface::class),
+    ]);
+    $this->fieldItem->setValue([
+      'target_id' => 'test',
+      'extra_property' => 'extra_value',
+    ])->shouldBeCalled();
+
+    $this->assertDenormalize($data);
+  }
+
 }
-- 
GitLab