From ff2392423b049467f475e5b3899f3be810065931 Mon Sep 17 00:00:00 2001 From: Teoh Han Hui Date: Fri, 14 Oct 2016 16:04:25 +0800 Subject: [PATCH] [Serializer] Support specifying format for DateTimeNormalizer::denormalize --- .../Normalizer/DateTimeNormalizer.php | 38 +++++++++++++++++++ .../Normalizer/DateTimeNormalizerTest.php | 27 ++++++++++--- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php index 3935810b76c2c..5958aab0679bd 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php @@ -68,6 +68,26 @@ public function supportsNormalization($data, $format = null) */ public function denormalize($data, $class, $format = null, array $context = array()) { + $dateTimeFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : null; + + if (null !== $dateTimeFormat) { + $object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data); + + if (false !== $object) { + return $object; + } + + $dateTimeErrors = \DateTime::class === $class ? \DateTime::getLastErrors() : \DateTimeImmutable::getLastErrors(); + + throw new UnexpectedValueException(sprintf( + 'Parsing datetime string "%s" using format "%s" resulted in %d errors:'."\n".'%s', + $data, + $dateTimeFormat, + $dateTimeErrors['error_count'], + implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])) + )); + } + try { return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data); } catch (\Exception $e) { @@ -88,4 +108,22 @@ public function supportsDenormalization($data, $type, $format = null) return isset($supportedTypes[$type]); } + + /** + * Formats datetime errors. + * + * @param array $errors + * + * @return string[] + */ + private function formatDateTimeErrors(array $errors) + { + $formattedErrors = array(); + + foreach ($errors as $pos => $message) { + $formattedErrors[] = sprintf('at position %d: %s', $pos, $message); + } + + return $formattedErrors; + } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php index 7638d5023833e..e68dfe335eb29 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php @@ -28,7 +28,7 @@ protected function setUp() $this->normalizer = new DateTimeNormalizer(); } - public function testSupportNormalization() + public function testSupportsNormalization() { $this->assertTrue($this->normalizer->supportsNormalization(new \DateTime())); $this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeImmutable())); @@ -41,12 +41,12 @@ public function testNormalize() $this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')))); } - public function testContextFormat() + public function testNormalizeUsingFormatPassedInContext() { $this->assertEquals('2016', $this->normalizer->normalize(new \DateTime('2016/01/01'), null, array(DateTimeNormalizer::FORMAT_KEY => 'Y'))); } - public function testConstructorFormat() + public function testNormalizeUsingFormatPassedInConstructor() { $this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC')))); } @@ -55,12 +55,12 @@ public function testConstructorFormat() * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException * @expectedExceptionMessage The object must implement the "\DateTimeInterface". */ - public function testInvalidDataThrowException() + public function testNormalizeInvalidObjectThrowsException() { $this->normalizer->normalize(new \stdClass()); } - public function testSupportDenormalization() + public function testSupportsDenormalization() { $this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTimeInterface::class)); $this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTime::class)); @@ -75,11 +75,26 @@ public function testDenormalize() $this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class)); } + public function testDenormalizeUsingFormatPassedInContext() + { + $this->assertEquals(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016.01.01', \DateTimeInterface::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|'))); + $this->assertEquals(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016.01.01', \DateTimeImmutable::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|'))); + $this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016.01.01', \DateTime::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|'))); + } + /** * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException */ - public function testInvalidDateThrowException() + public function testDenormalizeInvalidDataThrowsException() { $this->normalizer->denormalize('invalid date', \DateTimeInterface::class); } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException + */ + public function testDenormalizeFormatMismatchThrowsException() + { + $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeInterface::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y-m-d|')); + } }