Api Platform DateTimeNormalizer not allowing null

Viewed 1551

Because I prefer stackoverflow then github for such things, I am moving this issue conversation here.

For instance, you may have a user with deletedAt field. For some business reasons user is deleted but because of other reasons, you may want to activate him back by setting deletedAt field to be null. If you try to do it with API Platform, you are going to get this error:

The data is either an empty string or null, you should pass a string that can be parsed with the passed format or a valid DateTime string.

The question is, what is the best way to handle it?

2 Answers

Here is how I have handled it.

I extended API Platform DateTimeNormalizer:

namespace App\Normalizer;

use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer as APIPlatformDateTimeNormalizer;

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

        return parent::denormalize($data, $type, $format, $context);
    }
}

And define it as a service with the same name as the parent normalizer which in reality overridden it (api/config/services.yml):

services:
    serializer.normalizer.datetime:
            class: App\Normalizer\DateTimeNormalizer
            tags:
                - { name: serializer.normalizer }

Here's a slightly tweaked version which limits itself strictly to the mentioned issue.

It does not replace the original DateTimeNormalizer but instead registers itself with a higher priority and only handles incoming $data if it is empty and the original DateTimeNormalizer supports denormalization.

The src/Normalizer/NullableDateTimeDenormalizer.php:

declare(strict_types=1);

namespace App\Normalizer;

use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

final class NullableDateTimeDenormalizer implements DenormalizerInterface
{
    public function __construct(
        private DenormalizerInterface $dateTimeNormalizer
    ) {
    }

    public function denormalize($data, string $type, string $format = null, array $context = [])
    {
        return null;
    }

    public function supportsDenormalization($data, string $type, string $format = null)
    {
        if ($data === '' || $data === null) {
            return $this->dateTimeNormalizer->supportsDenormalization($data, $type, $format);
        }

        return false;
    }
}

The config/services.yaml:

services:
    App\Normalizer\NullableDateTimeDenormalizer:
        arguments:
            $dateTimeNormalizer: '@serializer.normalizer.datetime'
        tags:
            -
                name: serializer.normalizer
                priority: 100
Related