New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Serializer] Do not throw exception in the DateTimeNormalizer if it's not a date #27824

Open
lyrixx opened this Issue Jul 3, 2018 · 4 comments

Comments

Projects
None yet
3 participants
@lyrixx
Member

lyrixx commented Jul 3, 2018

Description
ATM, if the client send a malformated date (or something else) in a field mapped as DateTime, an exception occurs.

Symfony\Component\Serializer\Exception\NotNormalizableValueException:
DateTimeImmutable::__construct(): Failed to parse time string (2018-08-0111111) at position 14 (1): Unexpected character

  at vendor/symfony/symfony/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php:116
  at Symfony\Component\Serializer\Normalizer\DateTimeNormalizer->denormalize('2018-08-0111111', 'DateTimeImmutable', 'json', array('cache_key' => '6de9eb2685609b8387658584987a05b0'))
     (vendor/symfony/symfony/src/Symfony/Component/Serializer/Serializer.php:182)
  at Symfony\Component\Serializer\Serializer->denormalize('2018-08-0111111', 'DateTimeImmutable', 'json', array('cache_key' => '6de9eb2685609b8387658584987a05b0'))

# ...

By default this Exception is not catched and leads to a 500
Even If we put some validation, the validation comes after ... So this is not related

Example
IMHO, it would be better to not throw an exception, then the validator (if exist) will add a violation on the property


Maybe this idea could be extended to others normalizer


ping @dunglas

@lyrixx lyrixx added RFC Workflow Serializer and removed Workflow labels Jul 3, 2018

@lyrixx

This comment has been minimized.

Member

lyrixx commented Jul 3, 2018

for people who reach this issue and search for a work around:

use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer as SymfonyDateTimeNormalizer;

class DateTimeNormalizer extends SymfonyDateTimeNormalizer
{
    public function denormalize($data, $class, $format = null, array $context = array())
    {
        try {
            return parent::denormalize($data, $class, $format, $context);
        } catch (NotNormalizableValueException $e) {
            return $data;
        }
    }
}
@errogaht

This comment has been minimized.

errogaht commented Aug 2, 2018

Yes, I hate it too. I need to write own normalizer just for handle '' or null values!! unbelievable!

@errogaht

This comment has been minimized.

errogaht commented Aug 2, 2018

@lyrixx thanks, this work better for me also:

use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer as SymfonyDateTimeNormalizer;


class DateTimeNormalizer extends SymfonyDateTimeNormalizer
{
    public function denormalize($data, $class, $format = null, array $context = array())
    {
        try {
            $data = $data === '' ? null : $data;
            return parent::denormalize($data, $class, $format, $context);
        } catch (NotNormalizableValueException $e) {
            return $data;
        }
    }
}
@ymarillet

This comment has been minimized.

ymarillet commented Aug 7, 2018

For these who prefer decoration (like me):

<?php

namespace App\Serializer\Normalizer;

use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Workaround for https://github.com/symfony/symfony/issues/27824
 */
class EmptyDateTimeNormalizer implements DenormalizerInterface, NormalizerInterface
{
    /** @var DateTimeNormalizer */
    private $decorated;

    /**
     * @param DateTimeNormalizer $decorated
     */
    public function __construct(DateTimeNormalizer $decorated)
    {
        $this->decorated = $decorated;
    }

    public function normalize($object, $format = null, array $context = [])
    {
        return $this->decorated->normalize($object, $format, $context);
    }

    public function supportsNormalization($data, $format = null)
    {
        return $this->decorated->supportsNormalization($data, $format);
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        if (empty($data)) {
            return null;
        }

        return $this->decorated->denormalize($data, $class, $format, $context);
    }

    public function supportsDenormalization($data, $type, $format = null)
    {
        return $this->decorated->supportsDenormalization($data, $type, $format);
    }
}
services:
  App\Serializer\Normalizer\EmptyDateTimeNormalizer:
    decorates: 'serializer.normalizer.datetime'
    arguments:
      - '@App\Serializer\Normalizer\EmptyDateTimeNormalizer.inner'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment