Skip to content

Commit

Permalink
[Serializer] Add a new DateTime normalizer
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Jan 22, 2016
1 parent caae21c commit 6749a70
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 0 deletions.
91 changes: 91 additions & 0 deletions src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php
@@ -0,0 +1,91 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Normalizer;

use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;

/**
* Normalizes an object implementing the {@see \DateTimeInterface} to a date string.
* Denormalizes a date string to an instance of {@see \DateTime} or {@see \DateTimeImmutable}.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface
{
const FORMAT_KEY = 'datetime_format';

/**
* @var string
*/
private $format;

/**
* @param string $format
*/
public function __construct($format = \DateTime::RFC3339)
{
$this->format = $format;
}

/**
* {@inheritdoc}
*
* @throws InvalidArgumentException
*/
public function normalize($object, $format = null, array $context = array())
{
if (!$object instanceof \DateTimeInterface) {
throw new InvalidArgumentException('The object must implement the "\DateTimeInterface".');
}

$format = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format;

return $object->format($format);
}

/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = null)
{
return $data instanceof \DateTimeInterface;
}

/**
* {@inheritdoc}
*
* @throws UnexpectedValueException
*/
public function denormalize($data, $class, $format = null, array $context = array())
{
try {
return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data);
} catch (\Exception $e) {
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
}
}

/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = null)
{
$supportedTypes = array(
\DateTimeInterface::class => true,
\DateTimeImmutable::class => true,
\DateTime::class => true,
);

return isset($supportedTypes[$type]);
}
}
@@ -0,0 +1,85 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Serializer\Tests\Normalizer;

use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;

/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DateTimeNormalizerTest extends \PHPUnit_Framework_TestCase
{
/**
* @var DateTimeNormalizer
*/
private $normalizer;

public function setUp()
{
$this->normalizer = new DateTimeNormalizer();
}

public function testSupportNormalization()
{
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTime()));
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeImmutable()));
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
}

public function testNormalize()
{
$this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTime('2016/01/01')));
$this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTimeImmutable('2016/01/01')));
}

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

public function testConstructorFormat()
{
$this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01')));
}

/**
* @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException
* @expectedExceptionMessage The object must implement the "\DateTimeInterface".
*/
public function testInvalidDataThrowException()
{
$this->normalizer->normalize(new \stdClass());
}

public function testSupportDenormalization()
{
$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', \DateTimeImmutable::class));
$this->assertFalse($this->normalizer->supportsDenormalization('foo', 'Bar'));
}

public function testDenormalize()
{
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeInterface::class));
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeImmutable::class));
$this->assertEquals(new \DateTime('2016/01/01'), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class));
}

/**
* @expectedException \Symfony\Component\Serializer\Exception\UnexpectedValueException
*/
public function testInvalidDateThrowException()
{
$this->normalizer->denormalize('invalid date', \DateTimeInterface::class);
}
}

0 comments on commit 6749a70

Please sign in to comment.