AutoMapper 10.0 : Le mapping haute performance prêt pour le futur
C’est une étape majeure pour la librairie : AutoMapper passe en version 10.0.
Si notre promesse reste inchangée — transformer vos données d’un format à un autre le plus vite possible — cette version marque une rupture technologique. Nous avons profité de cette version majeure pour moderniser le cœur du réacteur et s’aligner sur les derniers standards de Symfony et bien plus encore !
Section intitulée sous-le-capot-l-arrivee-de-symfony-type-infoSous le capot : L’arrivée de symfony/type-info
C’est le changement invisible le plus impactant. Je travaille sur Jane et AutoMapper depuis longtemps, et je suis parti d’un constat simple : il manquait un outil capable de récupérer les métadonnées de façon avancée. À l’époque, le composant PropertyInfo de Symfony avait un support limité des unions et ne gérait ni les intersections, ni les génériques.
J’avais initialement mis en place l’extracteur PHPStan dans PropertyInfo pour tenter de combler ces manques, mais je me suis vite rendu compte que le système restait limité par la conception même du composant. C’est suite à des discussions avec Mathias Arlaud que nous avons décidé de nous mettre ensemble pour créer et sortir le composant TypeInfo.
C’est pourquoi TypeInfo (introduit dans Symfony 7.1) est aujourd’hui le nouveau standard pour obtenir des définitions de types encore plus détaillées. Avec la v10, AutoMapper bascule sur ce composant. Plus la définition des types est précise, plus le processus de mapping peut être effectué de manière fiable et optimale. C’est une étape essentielle pour garantir une extraction beaucoup plus fidèle de vos données.
Section intitulée la-nouveaute-le-typage-forceLa nouveauté : Le typage forcé
Parfois, l’inférence automatique ne suffit pas ou vous souhaitez transformer une donnée vers un format précis qui diffère du type PHP de la propriété source. La v10 permet de forcer le type cible directement via l’attribut #[MapTo].
Exemple :
Ici, on demande explicitement au mapper de transformer la propriété $number en un entier dans la cible, même si la source est une string.
class Entity {
#[MapTo(targetPropertyType: 'int')]
public string $number;
}
Section intitulée interoperabilite-support-de-symfony-objectmapperInteropérabilité : Support de Symfony ObjectMapper
Un peu comme l’interface native d’AutoMapper, l’ObjectMapperInterface permet de transformer un objet source en un objet cible via une méthode unique. La force de cette signature réside dans le paramètre $target, qui accepte soit le nom d’une classe (pour créer une nouvelle instance), soit un objet existant (pour l’hydrater ou le mettre à jour).
interface ObjectMapperInterface
{
public function map(object $source, object|string|null $target = null): object;
}
Et c’est ici que AutoMapper fait la différence : là où l’implémentation native de Symfony s’appuie principalement sur l’API Reflection qui peut être coûteuse, AutoMapper génère du code PHP optimisé. En activant ce support, vous remplacez le mécanisme par défaut par une solution taillée pour la performance, beaucoup plus rapide à l’exécution.
Pour activer cette fonctionnalité et remplacer l’ObjectMapper par défaut de Symfony par celui de l’AutoMapper, il suffit d’une ligne dans la configuration du bundle :
automapper:
object_mapper: true
Pour rendre cela possible et efficace, nous avons dû implémenter une fonctionnalité très attendue : le Nesting. Cela permet d’aller lire ou écrire des valeurs profondément imbriquées dans vos objets, simplifiant drastiquement le passage de DTOs « à plat » vers des entités riches.
Exemple :
On mappe ici un UserDto plat vers un User qui contient un objet Address. Grâce à la notation address.street, AutoMapper sait qu’il doit hydrater le sous-objet.
class UserDto {
#[MapTo(property: 'address.street')]
public string $streetAddress;
#[MapTo(property: 'address.city')]
public string $cityAddress;
public string $name;
}
class User {
public Address $address;
public string $name;
public function __construct()
{
$this->address = new Address();
}
}
class Address {
public string $street;
public string $city;
}
// À l'utilisation, le sous-objet Address est automatiquement peuplé
$mapper->map(new UserDto(
streetAddress: '123 Main St',
cityAddress: 'Springfield',
name: 'John Doe'
), User::class);
Section intitulée polymorphisme-une-gestion-des-discriminants-repenseePolymorphisme : Une gestion des discriminants repensée
Jusqu’ici, gérer le polymorphisme reposait sur une dépendance au Serializer de Symfony. Il était limité par la nécessité de spécifier une propriété de discrimination. La v10 améliore cela en permettant de définir la logique de discrimination directement au niveau de la classe via l’attribut #[Mapper] et permet de définir un mapping d’objets sans avoir à définir une propriété pour discriminer les entités.
Exemple :
Vous définissez ici comment mapper les enfants de la classe abstraite Pet en fonction du type de DTO entrant.
#[Mapper(discriminator: new Discriminator(
mapping: [
DogDto::class => Dog::class,
CatDto::class => Cat::class,
]
))]
abstract class Pet {
/** @var string */
public $name;
/** @var PetOwner */
public $owner;
}
Section intitulée un-nouveau-profiler-pour-y-voir-clairUn nouveau Profiler pour y voir clair
Le mapping est souvent une « boîte noire ». Quand une donnée ressort mal formée, comprendre pourquoi peut être complexe. Nous avons revu l’intégration dans le Profiler Symfony. Fini le temps où vous ne saviez pas si AutoMapper avait réellement travaillé. Désormais, le panneau dédié vous permet de :
- Lister tous les mappings effectués durant la requête ;
- Voir la classe Source et la classe Cible ;
- Inspecter le contexte passé au mapper.
C’est un outil indispensable pour debugger vos transformations complexes sans devoir placer des points d’arrêt partout.
Section intitulée le-mot-de-la-finLe mot de la fin
Cette version 10 est l’aboutissement de beaucoup de travail pour moderniser et pérenniser la librairie. Un immense merci à tous les contributeurs qui ont participé à cette release, avec une mention spéciale à Joel Wurtz pour son investissement colossal sur cette version majeure.
Pour aller plus loin, tout se passe ici :
- 📖 La documentation : https://automapper.jolicode.com/
- 🐙 Le dépôt GitHub : https://github.com/jolicode/automapper
Assurez-vous que votre environnement tourne sous PHP 8.4 ou supérieur et lancez :
composer require jolicode/automapper ^10.0
Commentaires et discussions
Ces clients ont profité de notre expertise
Nous avons construit un extranet afin de de simplifier les tâches quotidiennes de gestion, que ce soit pour les utilisateurs (départements, associations, mandataires, accueillants et accueillis) et l’équipe de Cettefamille. Le socle technique utilisé est Symfony, PostgreSQL, Webpack, VanillaJS. L’emploi de ces technologies modernes permet aujourd’hui…
Au fil de notre collaboration avec Deezer, nous avons été impliqués dans plusieurs initiatives visant à optimiser les performances de leur plateforme. Notre engagement initial s’est concentré sur le soutien et le conseil à l’équipe « Product Features » lors de leur projet de migration en cours. Nous avons apporté notre expertise pour résoudre…
JoliCode a formé l’équipe de développement d’Evaneos aux bonnes pratiques pour l’écriture de tests unitaires efficaces et utiles. Nous en avons également profité pour mettre en place une plateforme d’intégration continue pour accompagner l’évolution de la plateforme.
