.../EntityTest/EntityTestDatetimeTest.php | 6 +++--- .../EntityTest/EntityTestDateRangeTest.php | 2 +- .../src/Normalizer/DateTimeIso8601Normalizer.php | 15 ++++++++++++++- .../Unit/Normalizer/DateTimeIso8601NormalizerTest.php | 19 +++++++++++++++++-- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/core/modules/datetime/tests/src/Functional/EntityResource/EntityTest/EntityTestDatetimeTest.php b/core/modules/datetime/tests/src/Functional/EntityResource/EntityTest/EntityTestDatetimeTest.php index 51c36bf..4c92213 100644 --- a/core/modules/datetime/tests/src/Functional/EntityResource/EntityTest/EntityTestDatetimeTest.php +++ b/core/modules/datetime/tests/src/Functional/EntityResource/EntityTest/EntityTestDatetimeTest.php @@ -154,7 +154,7 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format); $response = $this->request($method, $url, $request_options); - $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601)."; + $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601), \"Y-m-d\\TH:i:s\" (backward compatibility — deprecated)."; $this->assertResourceErrorResponse(422, $message, $response); // DX: 422 when date format is incorrect. @@ -164,7 +164,7 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format); $response = $this->request($method, $url, $request_options); - $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601)."; + $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601), \"Y-m-d\\TH:i:s\" (backward compatibility — deprecated)."; $this->assertResourceErrorResponse(422, $message, $response); // DX: 422 when date value is invalid. @@ -174,7 +174,7 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format); $response = $this->request($method, $url, $request_options); - $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601)."; + $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601), \"Y-m-d\\TH:i:s\" (backward compatibility — deprecated)."; $this->assertResourceErrorResponse(422, $message, $response); } } diff --git a/core/modules/datetime_range/tests/src/Functional/EntityResource/EntityTest/EntityTestDateRangeTest.php b/core/modules/datetime_range/tests/src/Functional/EntityResource/EntityTest/EntityTestDateRangeTest.php index e83ca38..e669a22 100644 --- a/core/modules/datetime_range/tests/src/Functional/EntityResource/EntityTest/EntityTestDateRangeTest.php +++ b/core/modules/datetime_range/tests/src/Functional/EntityResource/EntityTest/EntityTestDateRangeTest.php @@ -154,7 +154,7 @@ protected function assertNormalizationEdgeCases($method, Url $url, array $reques $request_options[RequestOptions::BODY] = $this->serializer->encode($normalization, static::$format); $response = $this->request($method, $url, $request_options); - $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601)."; + $message = "The specified date \"$value\" is not in an accepted format: \"Y-m-d\\TH:i:sP\" (RFC 3339), \"Y-m-d\\TH:i:sO\" (ISO 8601), \"Y-m-d\\TH:i:s\" (backward compatibility — deprecated)."; $this->assertResourceErrorResponse(422, $message, $response); // @todo Expand in https://www.drupal.org/project/drupal/issues/2847041. diff --git a/core/modules/serialization/src/Normalizer/DateTimeIso8601Normalizer.php b/core/modules/serialization/src/Normalizer/DateTimeIso8601Normalizer.php index 343a258..c8c9a6b 100644 --- a/core/modules/serialization/src/Normalizer/DateTimeIso8601Normalizer.php +++ b/core/modules/serialization/src/Normalizer/DateTimeIso8601Normalizer.php @@ -71,11 +71,24 @@ public function denormalize($data, $class, $format = NULL, array $context = []) } else { $context['datetime_allowed_formats'] = array_diff_key($this->allowedFormats, ['date-only' => TRUE]); - $datetime = parent::denormalize($data, $class, $format, $context); + try { + $datetime = parent::denormalize($data, $class, $format, $context); + } + catch (\UnexpectedValueException $e) { + // If denormalization didn't work using any of the actively supported + // formats, try again with the BC format too. Explicitly label it as + // being deprecated and trigger a deprecation error. + $using_deprecated_format = TRUE; + $context['datetime_allowed_formats']['backward compatibility — deprecated'] = DateTimeItemInterface::DATETIME_STORAGE_FORMAT; + $datetime = parent::denormalize($data, $class, $format, $context); + } unset($context['datetime_allowed_formats']); if (!$datetime instanceof \DateTime) { return $datetime; } + if (isset($using_deprecated_format)) { + @trigger_error('The provided datetime string format (Y-m-d\\TH:i:s) is deprecated and will be removed before Drupal 9.0.0. Use the RFC3339 format instead (Y-m-d\\TH:i:sP).', E_USER_DEPRECATED); + } $datetime->setTimezone(new \DateTimeZone(DateTimeItemInterface::STORAGE_TIMEZONE)); return $datetime->format(DateTimeItemInterface::DATETIME_STORAGE_FORMAT); } diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php index ec8c352..1b80b3d 100644 --- a/core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php +++ b/core/modules/serialization/tests/src/Unit/Normalizer/DateTimeIso8601NormalizerTest.php @@ -213,6 +213,21 @@ public function providerTestDenormalizeValidFormats() { } /** + * Tests the denormalize function with the date+time deprecated format. + * + * @covers ::denormalize + * @group legacy + * @expectedDeprecation The provided datetime string format (Y-m-d\TH:i:s) is deprecated and will be removed before Drupal 9.0.0. Use the RFC3339 format instead (Y-m-d\TH:i:sP). + */ + public function testDenormalizeDateAndTimeDeprecatedFormat() { + $normalized = '2016-11-06T08:00:00'; + + $field_definition = $this->prophesize(FieldDefinitionInterface::class); + $field_definition->getSetting('datetime_type')->willReturn(DateTimeItem::DATETIME_TYPE_DATETIME); + $this->normalizer->denormalize($normalized, DateTimeIso8601::class, NULL, ['field_definition' => $field_definition->reveal()]); + } + + /** * Tests the denormalize function with bad data for the date-only case. * * @covers ::denormalize @@ -233,9 +248,9 @@ public function testDenormalizeDateOnlyException() { * @covers ::denormalize */ public function testDenormalizeDateAndTimeException() { - $this->setExpectedException(UnexpectedValueException::class, 'The specified date "2016-11-06T08:00:00" is not in an accepted format: "Y-m-d\TH:i:sP" (RFC 3339), "Y-m-d\TH:i:sO" (ISO 8601).'); + $this->setExpectedException(UnexpectedValueException::class, 'The specified date "on a rainy day" is not in an accepted format: "Y-m-d\TH:i:sP" (RFC 3339), "Y-m-d\TH:i:sO" (ISO 8601), "Y-m-d\TH:i:s" (backward compatibility — deprecated).'); - $normalized = '2016-11-06T08:00:00'; + $normalized = 'on a rainy day'; $field_definition = $this->prophesize(FieldDefinitionInterface::class); $field_definition->getSetting('datetime_type')->willReturn(DateTimeItem::DATETIME_TYPE_DATETIME);