Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Serializer\Normalizer; Chris@0: Chris@0: use Symfony\Component\Serializer\Exception\InvalidArgumentException; Chris@0: use Symfony\Component\Serializer\Exception\UnexpectedValueException; Chris@0: Chris@0: /** Chris@0: * Normalizes an object implementing the {@see \DateTimeInterface} to a date string. Chris@0: * Denormalizes a date string to an instance of {@see \DateTime} or {@see \DateTimeImmutable}. Chris@0: * Chris@0: * @author Kévin Dunglas Chris@0: */ Chris@0: class DateTimeNormalizer implements NormalizerInterface, DenormalizerInterface Chris@0: { Chris@0: const FORMAT_KEY = 'datetime_format'; Chris@0: Chris@0: /** Chris@0: * @var string Chris@0: */ Chris@0: private $format; Chris@0: Chris@0: /** Chris@0: * @param string $format Chris@0: */ Chris@0: public function __construct($format = \DateTime::RFC3339) Chris@0: { Chris@0: $this->format = $format; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: * Chris@0: * @throws InvalidArgumentException Chris@0: */ Chris@0: public function normalize($object, $format = null, array $context = array()) Chris@0: { Chris@0: if (!$object instanceof \DateTimeInterface) { Chris@0: throw new InvalidArgumentException('The object must implement the "\DateTimeInterface".'); Chris@0: } Chris@0: Chris@0: $format = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : $this->format; Chris@0: Chris@0: return $object->format($format); Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function supportsNormalization($data, $format = null) Chris@0: { Chris@0: return $data instanceof \DateTimeInterface; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: * Chris@0: * @throws UnexpectedValueException Chris@0: */ Chris@0: public function denormalize($data, $class, $format = null, array $context = array()) Chris@0: { Chris@0: $dateTimeFormat = isset($context[self::FORMAT_KEY]) ? $context[self::FORMAT_KEY] : null; Chris@0: Chris@0: if (null !== $dateTimeFormat) { Chris@0: $object = \DateTime::class === $class ? \DateTime::createFromFormat($dateTimeFormat, $data) : \DateTimeImmutable::createFromFormat($dateTimeFormat, $data); Chris@0: Chris@0: if (false !== $object) { Chris@0: return $object; Chris@0: } Chris@0: Chris@0: $dateTimeErrors = \DateTime::class === $class ? \DateTime::getLastErrors() : \DateTimeImmutable::getLastErrors(); Chris@0: Chris@0: throw new UnexpectedValueException(sprintf( Chris@0: 'Parsing datetime string "%s" using format "%s" resulted in %d errors:'."\n".'%s', Chris@0: $data, Chris@0: $dateTimeFormat, Chris@0: $dateTimeErrors['error_count'], Chris@0: implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])) Chris@0: )); Chris@0: } Chris@0: Chris@0: try { Chris@0: return \DateTime::class === $class ? new \DateTime($data) : new \DateTimeImmutable($data); Chris@0: } catch (\Exception $e) { Chris@0: throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function supportsDenormalization($data, $type, $format = null) Chris@0: { Chris@0: $supportedTypes = array( Chris@0: \DateTimeInterface::class => true, Chris@0: \DateTimeImmutable::class => true, Chris@0: \DateTime::class => true, Chris@0: ); Chris@0: Chris@0: return isset($supportedTypes[$type]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Formats datetime errors. Chris@0: * Chris@0: * @param array $errors Chris@0: * Chris@0: * @return string[] Chris@0: */ Chris@0: private function formatDateTimeErrors(array $errors) Chris@0: { Chris@0: $formattedErrors = array(); Chris@0: Chris@0: foreach ($errors as $pos => $message) { Chris@0: $formattedErrors[] = sprintf('at position %d: %s', $pos, $message); Chris@0: } Chris@0: Chris@0: return $formattedErrors; Chris@0: } Chris@0: }