I can't for the life of me figure out how to handle a regular deserialization. I've read dozens of SO questions and also the official doc and it seems to be easy. Seems.
I've got a simple JSON, like:
[{"id":"00112063002463454431","first_name":"John","last_name":"Doe","date_of_birth":"2006-09-28"}]
Now I'd like to map it to my class Person. No matter what I've tried, it always complains about date_of_birth to be string. It is expected to be DateTimeInterface when the routine internally calls setDateOfBirth(?DateTimeInterface $dateOfBirth)
inside the Person class. But in my understanding DateTimeNormalizer's denormalize() should've already converted it to a DateTime object before it hydrates the Person object, shouldn't it?
Inside my class the field is defined as follows:
#[ORM\Column(type: Types::DATE_MUTABLE)]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
private ?DateTimeInterface $dateOfBirth = null;
Deserializing process:
$serializer = new Serializer(
[new DateTimeNormalizer(), new GetSetMethodNormalizer(), new ArrayDenormalizer()],
[new JsonEncoder()]
);
$personsFromJson = $serializer->deserialize($requestContent, 'App\Entity\Person[]', 'json');
Is there anything else to do?!
Edit
One-class example:
<?php
namespace App\Controller;
use DateTimeInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Annotation\Context;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Serializer;
class TestController extends AbstractController
{
#[Route(path: '/test', name: 'app_test')]
public function index(): Response
{
$json = '{"dateOfBirth":"2023-01-31"}';
$serializer = new Serializer(
[new DateTimeNormalizer(), new GetSetMethodNormalizer()],
[new JsonEncoder()]
);
$testPersonFromJson = $serializer->deserialize($json, TestPerson::class, 'json');
return $this->json($testPersonFromJson);
}
}
class TestPerson {
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
private ?DateTimeInterface $dateOfBirth = null;
public function getDateOfBirth(): ?DateTimeInterface {
return $this->dateOfBirth;
}
public function setDateOfBirth(?DateTimeInterface $dateOfBirth): self {
$this->dateOfBirth = $dateOfBirth;
return $this;
}
}
App\Controller\TestPerson::setDateOfBirth(): Argument #1 ($dateOfBirth) must be of type ?DateTimeInterface, string given, called in [...]\vendor\symfony\serializer\Normalizer\GetSetMethodNormalizer.php on line 163
The DateTimeNormalizer() gets instantiated, but indeed, denormalize() gets never called.
CodePudding user response:
I had to add a ReflectionExtractor to my ObjectNormalizer. I didn't notice this anywhere.
new ObjectNormalizer(null, null, null, new ReflectionExtractor())
https://symfony.com/doc/current/components/property_info.html#reflectionextractor
Found via the comments after my 18567th search at: Symfony Serialize Entity with Datetime / Deserialize fails