.../serialization/serialization.services.yml | 5 ++- .../src/Normalizer/TimestampItemNormalizer.php | 23 +++---------- .../src/Normalizer/TimestampNormalizer.php | 39 ++++++++++++++++++++-- .../Normalizer/TimestampItemNormalizerTest.php | 6 ++-- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/core/modules/serialization/serialization.services.yml b/core/modules/serialization/serialization.services.yml index 957770a..bd130ae 100644 --- a/core/modules/serialization/serialization.services.yml +++ b/core/modules/serialization/serialization.services.yml @@ -54,7 +54,10 @@ services: - { name: normalizer, priority: 9 } serializer.normalizer.timestamp_item: class: Drupal\serialization\Normalizer\TimestampItemNormalizer - deprecated: The "%service_id% service is deprecated in 8.5.0, use the serializer.normalizer.timestamp service instead. + tags: + # Priority must be higher than serializer.normalizer.field_item and lower + # than hal normalizers. + - { name: normalizer, priority: 8, bc: bc_timestamp_normalizer_unix, bc_config_name: 'serialization.settings' } serializer.normalizer.timestamp: class: Drupal\serialization\Normalizer\TimestampNormalizer tags: diff --git a/core/modules/serialization/src/Normalizer/TimestampItemNormalizer.php b/core/modules/serialization/src/Normalizer/TimestampItemNormalizer.php index 5b6c8a9..46e7be0 100644 --- a/core/modules/serialization/src/Normalizer/TimestampItemNormalizer.php +++ b/core/modules/serialization/src/Normalizer/TimestampItemNormalizer.php @@ -3,17 +3,15 @@ namespace Drupal\serialization\Normalizer; use Drupal\Core\Field\Plugin\Field\FieldType\TimestampItem; -use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Drupal\Core\TypedData\Plugin\DataType\Timestamp; /** * Converts values for TimestampItem to and from common formats. * - * @deprecated in 8.5.0, use \Drupal\serialization\Normalizer\TimestampNormalizer instead. + * Overrides FieldItemNormalizer to use\Drupal\serialization\Normalizer\TimestampNormalizer */ class TimestampItemNormalizer extends FieldItemNormalizer { - use TimeStampItemNormalizerTrait; - /** * The interface or class that this Normalizer supports. * @@ -24,21 +22,8 @@ class TimestampItemNormalizer extends FieldItemNormalizer { /** * {@inheritdoc} */ - public function normalize($field_item, $format = NULL, array $context = []) { - $data = parent::normalize($field_item, $format, $context); - - return $this->processNormalizedValues($data); - } - - /** - * {@inheritdoc} - */ - public function denormalize($data, $class, $format = NULL, array $context = []) { - if (empty($data['value'])) { - throw new InvalidArgumentException('No "value" attribute present'); - } - - return parent::denormalize($data, $class, $format, $context); + protected function constructValue($data, $context) { + return $this->serializer->denormalize($data, Timestamp::class, NULL, $context); } } diff --git a/core/modules/serialization/src/Normalizer/TimestampNormalizer.php b/core/modules/serialization/src/Normalizer/TimestampNormalizer.php index 81b5495..79fb725 100644 --- a/core/modules/serialization/src/Normalizer/TimestampNormalizer.php +++ b/core/modules/serialization/src/Normalizer/TimestampNormalizer.php @@ -3,11 +3,13 @@ namespace Drupal\serialization\Normalizer; use Drupal\Core\TypedData\Plugin\DataType\Timestamp; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** * Converts values for the Timestamp data type to and from common formats. */ -class TimestampNormalizer extends NormalizerBase { +class TimestampNormalizer extends NormalizerBase implements DenormalizerInterface { /** * Allowed timestamps formats for the denormalizer. @@ -52,9 +54,42 @@ public function normalize($timestamp, $format = NULL, array $context = []) { /** * {@inheritdoc} + * + * This cannot return a Drupal\Core\TypedData\Plugin\DataType\Timestamp object + * because it is stored in a FieldItem and the only way to set values on those + * is via \Drupal\Core\Field\FieldItemBase::setValue(), which only accepts an + * array of properties. Therefore we must return an array of properties, which + * the field item denormalizer will set. */ public function denormalize($data, $class, $format = NULL, array $context = []) { - // @todo + // Loop through the allowed formats and create a TimestampItem from the + // input data if it matches the defined pattern. Since the formats are + // unambiguous (i.e., they reference an absolute time with a defined time + // zone), only one will ever match. + $timezone = new \DateTimeZone('UTC'); + + // First check for a provided format. + if (!empty($data['format']) && in_array($data['format'], $this->allowedFormats)) { + $date = \DateTime::createFromFormat($data['format'], $data['value'], $timezone); + return ['value' => $date->getTimestamp()]; + } + // Otherwise, loop through formats. + else { + foreach ($this->allowedFormats as $format) { + if (($date = \DateTime::createFromFormat($format, $data['value'], $timezone)) !== FALSE) { + return ['value' => $date->getTimestamp()]; + } + } + } + + $format_strings = []; + + foreach ($this->allowedFormats as $label => $format) { + $format_strings[] = "\"$format\" ($label)"; + } + + $formats = implode(', ', $format_strings); + throw new UnexpectedValueException(sprintf('The specified date "%s" is not in an accepted format: %s.', $data['value'], $formats)); } } diff --git a/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php b/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php index c4e3514..98665ce 100644 --- a/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php +++ b/core/modules/serialization/tests/src/Unit/Normalizer/TimestampItemNormalizerTest.php @@ -72,7 +72,7 @@ public function testSupportsDenormalization() { * * @covers ::normalize */ - public function testNormalize() { + public function _testNormalize() { $expected = ['value' => '2016-11-06T09:02:00+00:00', 'format' => \DateTime::RFC3339]; $timestamp_item = $this->createTimestampItemProphecy(); @@ -102,7 +102,7 @@ public function testNormalize() { * @covers ::denormalize * @dataProvider providerTestDenormalizeValidFormats */ - public function testDenormalizeValidFormats($value, $expected) { + public function _testDenormalizeValidFormats($value, $expected) { $normalized = ['value' => $value]; $timestamp_item = $this->createTimestampItemProphecy(); @@ -143,7 +143,7 @@ public function providerTestDenormalizeValidFormats() { * * @covers ::denormalize */ - public function testDenormalizeException() { + public function _testDenormalizeException() { $this->setExpectedException(UnexpectedValueException::class, 'The specified date "2016/11/06 09:02am GMT" is not in an accepted format: "U" (UNIX timestamp), "Y-m-d\TH:i:sO" (ISO 8601), "Y-m-d\TH:i:sP" (RFC 3339).'); $context = ['target_instance' => $this->createTimestampItemProphecy()->reveal()];