C’est carrément sympa quand on a pas besoin de transformer une ligne de données SQL en objet PHP par un mapping un peu dégeu.
les données brutes
J’écris mon test pour savoir ce que je veux transformer et en quoi :
<?php
namespace App\Tests\Dto;
use PHPUnit\Framework\TestCase;
use App\Dto\StudentDto;
use App\Serializer\StudentDenormalizer;
class DtoTest extends TestCase
{
public function testDenormalizeStudentDto()
{
$studentData = [
'code' => '123456',
'name' => 'Doe',
'surname' => 'John',
"birthdate" => "01-01-1990",
'email' => 'john@yopmail.com',
];
$studentDenormalizer = new StudentDenormalizer();
$studentDto = $studentDenormalizer->denormalize(
$studentData,
StudentDto::class
);
// Assert that the properties are correctly mapped to the StudentDto object
$this->assertEquals('123456', $studentDto->code);
$this->assertEquals('Doe', $studentDto->name);
$this->assertEquals('John', $studentDto->surname);
$this->assertEquals('john@yopmail.com', $studentDto->email);
// Dto transform birthdate to the correct format
$this->assertEquals('1990-01-01T00:00:00', $studentDto->birthdate);
// You can also assert that the object is an instance of StudentDto
$this->assertInstanceOf(StudentDto::class, $studentDto);
}
}
Le concept de Normalisation
le normalisation c’est quand on cherche à transformer un objet en tableau
Donc ce que je voulais faire étant l’inverse, ça s’appelle de la dénormalisation
Documentation symfony : https://symfony.com/doc/current/components/serializer.html
<?php
namespace App\Dto;
use Symfony\Component\Serializer\Annotation\SerializedName;
class StudentDto
{
#[SerializedName('code')]
public ?int $code = null;
#[SerializedName('name')]
public ?string $name = null;
#[SerializedName('surname')]
public ?string $surname = null;
#[SerializedName('email')]
public ?string $email = null;
#[SerializedName('birthdate')]
public ?string $birthdate = null;
}
Créer un Denormalizer
On utilise les outils basiques array et object pour faire la transition. mais j’ai créé un outil personnalisé qui me permet de formater la date par exemple et de renvoyé une instance de classe StudentDto à partir d’un tableau de données.
<?php
namespace App\Serializer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use App\Dto\StudentDto;
class StudentDenormalizer implements DenormalizerInterface
{
private $serializer;
public function __construct()
{
$denormalizer = new ArrayDenormalizer();
$normalizer = new ObjectNormalizer();
$this->serializer = new Serializer([$denormalizer, $normalizer]);
}
// transform birthdate besfore calling denormalize
public function denormalize($data, string $type, string $format = null, array $context = [])
{
if (isset($data['birthdate']) && is_string($data['birthdate'])) {
$dateTime = new \DateTime($data['birthdate']);
$wellFormattedBirthDate = $dateTime->format('Y-m-d\TH:i:s');
$data['birthdate'] = $wellFormattedBirthDate;
}
return $this->serializer->denormalize(
$data,
StudentDto::class
);
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return $type === StudentDto::class;
}
}
Conclusion sur le dénormaliser
je n’ai surement pas besoin d’utiliser DenormalizerInterface, ni supportsDenormalization car je renvoie l’objet entier.
Mais bon vous avez l’idée, le sérializer a besoin de ses 2 correspondances pour faire le boulot et vous pouvez modifier ce qu’il se passe entre les 2 !