[Serializer] Support specifying format for DateTimeNormalizer::denormalize

This commit is contained in:
Teoh Han Hui 2016-10-14 16:04:25 +08:00
parent 69e86547d4
commit ff2392423b
No known key found for this signature in database
GPG Key ID: 729783C96A30C9B8
2 changed files with 59 additions and 6 deletions

View File

@ -68,6 +68,26 @@ class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
*/ */
public function denormalize($data, $class, $format = null, array $context = array()) 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 { try {
return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data); return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data);
} catch (\Exception $e) { } catch (\Exception $e) {
@ -88,4 +108,22 @@ class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
return isset($supportedTypes[$type]); 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;
}
} }

View File

@ -28,7 +28,7 @@ class DateTimeNormalizerTest extends \PHPUnit_Framework_TestCase
$this->normalizer = new DateTimeNormalizer(); $this->normalizer = new DateTimeNormalizer();
} }
public function testSupportNormalization() public function testSupportsNormalization()
{ {
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTime())); $this->assertTrue($this->normalizer->supportsNormalization(new \DateTime()));
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeImmutable())); $this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeImmutable()));
@ -41,12 +41,12 @@ class DateTimeNormalizerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')))); $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'))); $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')))); $this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC'))));
} }
@ -55,12 +55,12 @@ class DateTimeNormalizerTest extends \PHPUnit_Framework_TestCase
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
* @expectedExceptionMessage The object must implement the "\DateTimeInterface". * @expectedExceptionMessage The object must implement the "\DateTimeInterface".
*/ */
public function testInvalidDataThrowException() public function testNormalizeInvalidObjectThrowsException()
{ {
$this->normalizer->normalize(new \stdClass()); $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', \DateTimeInterface::class));
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTime::class)); $this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTime::class));
@ -75,11 +75,26 @@ class DateTimeNormalizerTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class)); $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 * @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException
*/ */
public function testInvalidDateThrowException() public function testDenormalizeInvalidDataThrowsException()
{ {
$this->normalizer->denormalize('invalid date', \DateTimeInterface::class); $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|'));
}
} }