symfonyserializationdenormalization

How to denormalize a DateTime-Array to DateTime-Object with Symfony Serializer


I need to denormalize this data with symfony 6

array:4 [
  "createdAt" => array:3 [
    "date" => "2024-01-09 17:04:37.209330"
    "timezone_type" => 3
    "timezone" => "Europe/Paris"
  ]
  "utilisateur" => "phpunit"
  "type" => "CREATION"
  "texte" => "creation de la demande"
]

to this object

class Historique
{
    public \DateTime $createdAt;

    public function __construct(public readonly string $utilisateur, public readonly string $type, public readonly ?string $texte)
    {
        $this->createdAt = new \DateTime();
    }

    public function getTypeLabel(): string
    {
        return HistoriqueTypeEnum::getLabelName($this->type);
    }
}

I have use this code, but I have a problem to denormalize the DateTime object.

$normalizers = [
    new DateTimeNormalizer(),
    new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
    new BackedEnumNormalizer(),
];
$serializer = new Serializer($normalizers, [new JsonEncoder()]);
$serializer->denormalize($historique, Historique::class, 'json', [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d H:i:s',]);

I get this error:

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

If I change the order of normalizers like this:

$normalizers = [
    new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
    new BackedEnumNormalizer(),
    new DateTimeNormalizer(),
];

I get this error:

Cannot create an instance of "DateTimeZone" from serialized data because its constructor requires the following parameters to be present : "$timezone".")


Solution

  • The DateTimeNormalizer class needs a valid DateTime string. Instead to ignore the DateTime object, you can change the data array and set the createdAt key to the date string and set the timezone with DateTimeNormalizer::TIMEZONE_KEY

    $historique = [
      "createdAt" => [
        "date" => "2024-01-09 17:04:37.209330",
        "timezone_type" => 3,
        "timezone" => "Europe/Paris"
      ],
      "utilisateur" => "phpunit",
      "type" => "CREATION",
      "texte" => "creation de la demande",
    ];
    
    $createdAt = $historique['createdAt'];
    $historique['createdAt'] = $createdAt['date'];
    
    $normalizers = [
        new DateTimeNormalizer(),
        new ObjectNormalizer(null, null, null, new ReflectionExtractor()),
        new BackedEnumNormalizer(),
    ];
    $serializer = new Serializer($normalizers, [new JsonEncoder()]);
    $object = $serializer->denormalize(
        $historique, 
        Historique::class, 
        'json', 
        [
            DateTimeNormalizer::TIMEZONE_KEY => $createdAt['timezone'],
        ]
    );
    dump($object);
    
    // Result:
    // ^ Historique^ {#114
    //   +createdAt: DateTime @1704816277 {#104
    //     date: 2024-01-09 17:04:37.209330 Europe/Paris (+01:00)
    //   }
    //   +utilisateur: "phpunit"
    //   +type: "CREATION"
    //   +texte: "creation de la demande"
    // }