diff --git a/core/modules/hal/config/install/hal.settings.yml b/core/modules/hal/config/install/hal.settings.yml index 67107af00d..1c895c1718 100644 --- a/core/modules/hal/config/install/hal.settings.yml +++ b/core/modules/hal/config/install/hal.settings.yml @@ -1,3 +1,4 @@ # Set the domain for HAL type and relation links. # If left blank, the site's domain will be used. link_domain: ~ +bc_file_uri_as_url_normalizer: false diff --git a/core/modules/hal/config/schema/hal.schema.yml b/core/modules/hal/config/schema/hal.schema.yml index 3192d67580..b70f47eaff 100644 --- a/core/modules/hal/config/schema/hal.schema.yml +++ b/core/modules/hal/config/schema/hal.schema.yml @@ -6,3 +6,6 @@ hal.settings: link_domain: type: string label: 'Domain of the relation' + bc_file_uri_as_url_normalizer: + type: boolean + label: 'Whether to retain pre Drupal 8.5 behavior of normalizing file URI values as a full URL.' diff --git a/core/modules/hal/hal.install b/core/modules/hal/hal.install index 78810e37f5..77e932f74f 100644 --- a/core/modules/hal/hal.install +++ b/core/modules/hal/hal.install @@ -31,3 +31,15 @@ function hal_update_8301() { $hal_settings->set('link_domain', $link_domain); $hal_settings->save(TRUE); } + +/** + * Add hal.settings::bc_file_uri_as_url_normalizer configuration. + */ +function hal_update_8501() { + $config_factory = \Drupal::configFactory(); + $config_factory->getEditable('hal.settings') + ->set('bc_file_uri_as_url_normalizer', FALSE) + ->save(TRUE); + + return t('The REST API will no longer return the full URL for file entity URI values. It will return the URI value itself, with an additional URL property providing a root relative file path. If your site depends on these value being strings, read the change record to learn how to enable the BC mode.'); +} diff --git a/core/modules/hal/hal.services.yml b/core/modules/hal/hal.services.yml index ca28f522b4..faf3fc101f 100644 --- a/core/modules/hal/hal.services.yml +++ b/core/modules/hal/hal.services.yml @@ -12,6 +12,11 @@ services: class: Drupal\hal\Normalizer\FieldNormalizer tags: - { name: normalizer, priority: 10 } + serializer.normalizer.file_entity.hal: + class: Drupal\hal\Normalizer\FileEntityNormalizer + arguments: ['@entity.manager', '@http_client', '@hal.link_manager', '@module_handler', '@config.factory'] + tags: + - { name: normalizer, priority: 20 } serializer.normalizer.timestamp_item.hal: class: Drupal\hal\Normalizer\TimestampItemNormalizer tags: diff --git a/core/modules/hal/src/Normalizer/FileEntityNormalizer.php b/core/modules/hal/src/Normalizer/FileEntityNormalizer.php new file mode 100644 index 0000000000..31a0f53f0e --- /dev/null +++ b/core/modules/hal/src/Normalizer/FileEntityNormalizer.php @@ -0,0 +1,84 @@ +httpClient = $http_client; + $this->config = $config_facotry->get('hal.settings'); + } + + /** + * {@inheritdoc} + */ + public function normalize($entity, $format = NULL, array $context = []) { + $data = parent::normalize($entity, $format, $context); + + if ($this->config->get('bc_file_uri_as_url_normalizer')) { + // Replace the file url with a full url for the file. + $data['uri'][0]['value'] = $this->getEntityUri($entity); + } + + return $data; + } + + /** + * {@inheritdoc} + */ + public function denormalize($data, $class, $format = NULL, array $context = []) { + $file_data = (string) $this->httpClient->get($data['uri'][0]['value'])->getBody(); + + $path = 'temporary://' . drupal_basename($data['uri'][0]['value']); + $data['uri'] = file_unmanaged_save_data($file_data, $path); + + return $this->entityManager->getStorage('file')->create($data); + } + +} diff --git a/core/modules/hal/tests/src/Functional/FileDenormalizeTest.php b/core/modules/hal/tests/src/Functional/FileDenormalizeTest.php new file mode 100644 index 0000000000..dbb708f8ca --- /dev/null +++ b/core/modules/hal/tests/src/Functional/FileDenormalizeTest.php @@ -0,0 +1,86 @@ +getEditable('hal.settings') + ->set('bc_file_uri_as_url_normalizer', TRUE) + ->save(TRUE); + } + + /** + * Tests file entity denormalization. + */ + public function testFileDenormalize() { + $file_params = [ + 'filename' => 'test_1.txt', + 'uri' => 'public://test_1.txt', + 'filemime' => 'text/plain', + 'status' => FILE_STATUS_PERMANENT, + ]; + // Create a new file entity. + $file = File::create($file_params); + file_put_contents($file->getFileUri(), 'hello world'); + $file->save(); + + $serializer = \Drupal::service('serializer'); + $normalized_data = $serializer->normalize($file, 'hal_json'); + $denormalized = $serializer->denormalize($normalized_data, 'Drupal\file\Entity\File', 'hal_json'); + + $this->assertTrue($denormalized instanceof File, 'A File instance was created.'); + + $this->assertIdentical('temporary://' . $file->getFilename(), $denormalized->getFileUri(), 'The expected file URI was found.'); + $this->assertTrue(file_exists($denormalized->getFileUri()), 'The temporary file was found.'); + + $this->assertIdentical($file->uuid(), $denormalized->uuid(), 'The expected UUID was found'); + $this->assertIdentical($file->getMimeType(), $denormalized->getMimeType(), 'The expected MIME type was found.'); + $this->assertIdentical($file->getFilename(), $denormalized->getFilename(), 'The expected filename was found.'); + $this->assertTrue($denormalized->isPermanent(), 'The file has a permanent status.'); + + // Try to denormalize with the file uri only. + $file_name = 'test_2.txt'; + $file_path = 'public://' . $file_name; + + file_put_contents($file_path, 'hello world'); + $file_uri = file_create_url($file_path); + + $data = [ + 'uri' => [ + ['value' => $file_uri], + ], + ]; + + $denormalized = $serializer->denormalize($data, 'Drupal\file\Entity\File', 'hal_json'); + + $this->assertIdentical('temporary://' . $file_name, $denormalized->getFileUri(), 'The expected file URI was found.'); + $this->assertTrue(file_exists($denormalized->getFileUri()), 'The temporary file was found.'); + + $this->assertIdentical('text/plain', $denormalized->getMimeType(), 'The expected MIME type was found.'); + $this->assertIdentical($file_name, $denormalized->getFilename(), 'The expected filename was found.'); + $this->assertFalse($denormalized->isPermanent(), 'The file has a permanent status.'); + } + +}