Skip to content

Commit a72d997

Browse files
committed
[Serializer] Support specifying format for DateTimeNormalizer::denormalize
1 parent 69e8654 commit a72d997

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php

+38
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,26 @@ public function supportsNormalization($data, $format = null)
6868
*/
6969
public function denormalize($data, $class, $format = null, array $context = array())
7070
{
71+
$dateTimeFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : null;
72+
73+
if (null !== $dateTimeFormat) {
74+
$object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data);
75+
76+
if (false !== $object) {
77+
return $object;
78+
}
79+
80+
$dateTimeErrors = \DateTime::class === $class ? \DateTime::getLastErrors() : \DateTimeImmutable::getLastErrors();
81+
82+
throw new UnexpectedValueException(sprintf(
83+
'Parsing datetime string "%s" using format "%s" resulted in %d errors:'."\n".'%s',
84+
$data,
85+
$dateTimeFormat,
86+
$dateTimeErrors['error_count'],
87+
implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors']))
88+
));
89+
}
90+
7191
try {
7292
return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data);
7393
} catch (\Exception $e) {
@@ -88,4 +108,22 @@ public function supportsDenormalization($data, $type, $format = null)
88108

89109
return isset($supportedTypes[$type]);
90110
}
111+
112+
/**
113+
* Formats datetime errors.
114+
*
115+
* @param array $errors
116+
*
117+
* @return string[]
118+
*/
119+
private function formatDateTimeErrors(array $errors)
120+
{
121+
$formattedErrors = array();
122+
123+
foreach ($errors as $pos => $message) {
124+
$formattedErrors[] = sprintf('at position %d: %s', $pos, $message);
125+
}
126+
127+
return $formattedErrors;
128+
}
91129
}

src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeNormalizerTest.php

+14-6
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ protected function setUp()
2828
$this->normalizer = new DateTimeNormalizer();
2929
}
3030

31-
public function testSupportNormalization()
31+
public function testSupportsNormalization()
3232
{
3333
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTime()));
3434
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeImmutable()));
@@ -41,12 +41,12 @@ public function testNormalize()
4141
$this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC'))));
4242
}
4343

44-
public function testContextFormat()
44+
public function testNormalizeUsingFormatPassedInContext()
4545
{
4646
$this->assertEquals('2016', $this->normalizer->normalize(new \DateTime('2016/01/01'), null, array(DateTimeNormalizer::FORMAT_KEY => 'Y')));
4747
}
4848

49-
public function testConstructorFormat()
49+
public function testNormalizeUsingFormatPassedInConstructor()
5050
{
5151
$this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC'))));
5252
}
@@ -55,12 +55,12 @@ public function testConstructorFormat()
5555
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
5656
* @expectedExceptionMessage The object must implement the "\DateTimeInterface".
5757
*/
58-
public function testInvalidDataThrowException()
58+
public function testNormalizeInvalidObjectThrowsException()
5959
{
6060
$this->normalizer->normalize(new \stdClass());
6161
}
6262

63-
public function testSupportDenormalization()
63+
public function testSupportsDenormalization()
6464
{
6565
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTimeInterface::class));
6666
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTime::class));
@@ -75,11 +75,19 @@ public function testDenormalize()
7575
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class));
7676
}
7777

78+
public function testDenormalizeUsingFormatPassedInContext()
79+
{
80+
$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|')));
81+
$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|')));
82+
$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|')));
83+
}
84+
7885
/**
7986
* @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException
8087
*/
81-
public function testInvalidDateThrowException()
88+
public function testDenormalizeInvalidDataThrowsException()
8289
{
8390
$this->normalizer->denormalize('invalid date', \DateTimeInterface::class);
91+
$this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeInterface::class, null, array(DateTimeNormalizer::FORMAT_KEY => 'Y-m-d|'));
8492
}
8593
}

0 commit comments

Comments
 (0)