Attention Nous avons décidé d'arrêter la maintenance de ce package.
Pensez à migrer vers spatie/laravel-data ou cuyz/valinor.
N'hésitez pas à forker notre code et à l'adapter à vos besoins.
Vous pouvez installer le package via composer :
le compositeur nécessite un objet spatie/data-transfer-object
Remarque : la v3 de ce package ne prend en charge que php:^8.0
. Si vous recherchez l'ancienne version, consultez la v2.
Nous investissons beaucoup de ressources dans la création des meilleurs packages open source de leur catégorie. Vous pouvez nous soutenir en achetant l'un de nos produits payants.
Nous apprécions grandement que vous nous envoyiez une carte postale de votre ville natale, mentionnant le(s) forfait(s) que vous utilisez. Vous trouverez notre adresse sur notre page contact. Nous publions toutes les cartes postales reçues sur notre mur virtuel de cartes postales.
Le but de ce package est de rendre la construction d'objets à partir de tableaux de données (sérialisées) aussi simple que possible. Voici à quoi ressemble un DTO :
utiliser SpatieDataTransferObjectAttributesMapFrom; utiliser SpatieDataTransferObjectDataTransferObject; la classe MyDTO étend DataTransferObject {public AutreDTO $autreDTO ; public OtherDTOCollection $collection; #[CastWith(ComplexObjectCaster::class)]public ComplexObject $complexObject; public ComplexObjectWithCast $complexObjectWithCast ; #[NumberBetween(1, 100)]public int $a; #[MapFrom('address.city')]public string $city; }
Vous pouvez construire ce DTO comme ceci :
$dto = nouveau MonDTO( une: 5, collection: [ ['identifiant' => 1], ['identifiant' => 2], ['identifiant' => 3], ], complexObject : ['nom' => 'test', ], complexObjectWithCast : ['name' => 'test', ], autreDTO : ['id' => 5], );
Discutons de toutes les possibilités une par une.
La construction d'un DTO peut être effectuée avec des arguments nommés. Il est également possible de continuer à utiliser l'ancienne notation de tableau. Cet exemple est équivalent à celui ci-dessus.
$dto = nouveau MonDTO(['a' => 5,'collection' => [ ['identifiant' => 1], ['identifiant' => 2], ['identifiant' => 3], ],'complexObject' => ['name' => 'test', ],'complexObjectWithCast' => ['nom' => 'test', ],'autreDTO' => ['id' => 5], ]);
Si un DTO a une propriété qui est un autre DTO ou une collection de DTO, le package se chargera de convertir automatiquement les tableaux de données vers ces DTO :
$dto = nouveau MonDTO( collection: [ // Cela deviendra un objet de classe OtherDTOCollection['id' => 1], ['id' => 2], // Chaque élément sera une instance de OtherDTO['id' => 3], ], otherDTO : ['id' => 5], // Ces données seront converties en OtherDTO);
Vous pouvez créer vos propres classes de lanceurs de sorts, qui prendront toutes les entrées qui leur seront fournies et convertiront ces entrées en résultat souhaité.
Jetez un œil au ComplexObject
:
classe ComplexObject {chaîne publique $nom ; }
Et son lanceur ComplexObjectCaster
:
utiliser SpatieDataTransferObjectCaster ; la classe ComplexObjectCaster implémente Caster {/** * @param array|mixed $value * * @return Mixed */public function cast(mixed $value): ComplexObject{return new ComplexObject( nom : $valeur['nom'] ); } }
Au lieu de spécifier quel lanceur doit être utilisé pour chaque propriété, vous pouvez également définir ce lanceur sur la classe cible elle-même :
la classe MyDTO étend DataTransferObject {public ComplexObjectWithCast $complexObjectWithCast ; }
#[CastWith(ComplexObjectWithCastCaster::class)]class ComplexObjectWithCast {chaîne publique $nom ; }
Il est possible de définir des roulettes par défaut sur une classe DTO elle-même. Ces roulettes seront utilisées chaque fois qu'une propriété avec un type donné est rencontrée dans la classe DTO.
#[ DefaultCast (DateTimeImmutable :: classe, DateTimeImmutableCaster :: classe), DefaultCast (MyEnum :: classe, EnumCaster :: classe), ]la classe abstraite BaseDataTransferObject étend DataTransferObject {public MyEnum $statut ; // EnumCaster sera utilisépublic DateTimeImmutable $date; // DateTimeImmutableCaster sera utilisé}
N'importe quel lanceur de sorts peut recevoir des arguments personnalisés, l'implémentation intégrée ArrayCaster
est un bon exemple de la façon dont cela peut être utilisé.
L'utilisation d'arguments nommés lors de la transmission d'une entrée à votre lanceur aidera à rendre votre code plus clair, mais ils ne sont pas obligatoires.
Par exemple:
/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionWithNamedArguments; /** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, Foo::class)]public array $collectionWithoutNamedArguments;
Notez que le premier argument transmis au constructeur caster est toujours le tableau avec le(s) type(s) de la valeur en cours de conversion. Tous les autres arguments seront ceux transmis comme arguments supplémentaires dans l'attribut CastWith
.
Ce package n'offre aucune fonctionnalité de validation spécifique, mais il vous permet de créer vos propres attributs de validation. Par exemple, NumberBetween
est un attribut de validation implémenté par l'utilisateur :
la classe MyDTO étend DataTransferObject { #[NumberBetween(1, 100)]public int $a; }
Cela fonctionne comme ceci sous le capot :
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]class NumberBetween implémente le validateur {fonction publique __construct(private int $min,private int $max) { }public function validate(mixed $value): ValidationResult{if ($value < $this->min) {return ValidationResult::invalid("La valeur doit être supérieure ou égale à {$this->min}"); }if ($value > $this->max) {return ValidationResult::invalid("La valeur doit être inférieure ou égale à {$this->max}"); }return ValidationResult::valid(); } }
Vous pouvez mapper une propriété DTO à partir d'une propriété source portant un nom différent à l'aide de l'attribut #[MapFrom]
.
Cela fonctionne avec un nom de propriété de notation "point" ou un index.
la classe PostDTO étend DataTransferObject { #[MapFrom('postTitle')]public string $title; #[MapFrom('user.name')]public string $author; }$dto = new PostDTO(['postTitle' => 'Bonjour tout le monde','user' => ['name' => 'John Doe'] ]);
la classe UserDTO étend DataTransferObject { #[MapFrom(0)]chaîne publique $firstName; #[MapFrom(1)]chaîne publique $lastName; }$dto = new UserDTO(['John', 'Doe']);
Parfois, vous souhaitez également les mapper lors de la transformation en Array. Un cas d'utilisation typique serait la transformation d'un étui à chameau en un étui à serpent. Pour cela, vous pouvez utiliser l'attribut #[MapTo]
.
la classe UserDTO étend DataTransferObject { #[CarteDe(0)] #[MapTo('first_name')]public string $firstName; #[CarteDe(1)] #[MapTo('last_name')]public string $lastName; }$dto = new UserDTO(['John', 'Doe']);$dto->toArray() // ['first_name' => 'John', 'last_name'=> 'Doe'];$dto- >only('first_name')->toArray() // ['first_name' => 'John'];
La version précédente de ce package ajoutait la classe FlexibleDataTransferObject
qui vous permettait d'ignorer les propriétés qui n'existaient pas sur le DTO. Ce comportement a été modifié, tous les DTO sont désormais flexibles par défaut, mais vous pouvez les rendre stricts en utilisant l'attribut #[Strict]
:
la classe NonStrictDto étend DataTransferObject {chaîne publique $nom ; }// Cela fonctionne nouveau NonStrictDto ( nom : 'nom', inconnu : 'inconnu');
utilisez SpatieDataTransferObjectAttributesStrict ; #[Strict]class StrictDto étend DataTransferObject {chaîne publique $nom ; }// Cela génère une exception SpatieDataTransferObjectExceptionsUnknownPropertiesnew StrictDto( nom : 'nom', inconnu : 'inconnu');
Certaines fonctions d'assistance sont également fournies pour travailler avec plusieurs propriétés à la fois.
$postData->all();$postData->only('titre', 'corps') ->toArray(); $postData->sauf('auteur') ->toArray();
Notez que all()
renverra simplement toutes les propriétés, tandis que toArray()
convertira également les DTO imbriqués en tableaux.
Vous pouvez enchaîner les méthodes except()
et only()
:
$postData->sauf('titre') ->sauf('corps') ->toArray();
Il est important de noter que except()
et only()
sont immuables, ils ne modifieront pas l'objet de transfert de données d'origine.
Ce package ne force pas les objets immuables puisque PHP ne les prend pas en charge, mais vous êtes toujours encouragé à garder vos DTO immuables. Pour vous aider, il existe une méthode clone
sur chaque DTO qui accepte les données à remplacer :
$clone = $original->clone(autre : ['nom' => 'a']);
Notez qu'aucune donnée dans $original
n'est modifiée.
Cette version supprime la classe DataTransferObjectCollection
. Au lieu de cela, vous pouvez utiliser de simples roulettes et vos propres classes de collection.
Voici un exemple de conversion d'une collection de DTO en un tableau de DTO :
la classe Bar étend DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(FooArrayCaster::class)]public array $collectionOfFoo; }class Foo étend DataTransferObject {chaîne publique $nom ; }
la classe FooArrayCaster implémente Caster {public function cast(mixed $value): array{if (! is_array($value)) {throw new Exception("Peut uniquement convertir des tableaux en Foo"); }return array_map(fn (array $data) => new Foo(...$data),$value); } }
Si vous ne voulez pas d'indication de type redondante ou si vous souhaitez une fonctionnalité de collection étendue ; vous pouvez créer vos propres classes de collection en utilisant n'importe quelle implémentation de collection. Dans cet exemple, nous utilisons celui de Laravel :
la classe Bar étend DataTransferObject { #[CastWith(FooCollectionCaster::class)]public CollectionOfFoo $collectionOfFoo; }class Foo étend DataTransferObject {chaîne publique $nom ; }
utiliser IlluminateSupportCollection ; la classe CollectionOfFoo étend la collection {// Ajoutez ici le type de retour correct pour que les analyseurs statiques sachent de quel type de tableau il s'agit. public function offsetGet($key): Foo{return parent::offsetGet($key); } }
la classe FooCollectionCaster implémente Caster {public function cast(mixed $value) : CollectionOfFoo{return new CollectionOfFoo(array_map(fn (array $data) => new Foo(...$data),$value)); } }
Pour un simple tableau de DTO ou un objet qui implémente ArrayAccess
intégré à PHP, envisagez d'utiliser ArrayCaster
qui nécessite la fourniture d'un type d'élément :
la classe Bar étend DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionOfFoo; }
test de compositeur
Veuillez consulter CHANGELOG pour plus d'informations sur ce qui a changé récemment.
Veuillez consulter CONTRIBUER pour plus de détails.
Si vous avez trouvé un bug concernant la sécurité, veuillez envoyer un mail à [email protected] au lieu d'utiliser le suivi des problèmes.
Vous êtes libre d'utiliser ce package, mais s'il parvient à votre environnement de production, nous apprécions grandement que vous nous envoyiez une carte postale de votre ville natale, mentionnant lequel de nos packages vous utilisez.
Notre adresse est : Spatie, Kruikstraat 22, 2018 Anvers, Belgique.
Nous publions toutes les cartes postales reçues sur le site Internet de notre entreprise.
json2dto : une interface graphique pour convertir des objets JSON en classes DTO (avec prise en charge de l'imbrication). Fournit également un outil CLI pour une utilisation locale.
Data Transfer Object Factory : génère intelligemment une instance DTO en utilisant le contenu correct pour vos propriétés en fonction de son nom et de son type.
Brent Roose
Tous les contributeurs
Notre classe Arr
contient des fonctions copiées de l'assistant Laravels Arr
.
La licence MIT (MIT). Veuillez consulter le fichier de licence pour plus d'informations.