Advertencia Hemos decidido dejar de mantener este paquete.
Considere migrar a spatie/laravel-data o cuyz/valinor.
No dudes en bifurcar nuestro código y adaptarlo a tus necesidades.
Puede instalar el paquete a través del compositor:
El compositor requiere espacio/objeto de transferencia de datos.
Nota : la versión 3 de este paquete solo admite php:^8.0
. Si está buscando la versión anterior, consulte la v2.
Invertimos muchos recursos en la creación de los mejores paquetes de código abierto. Puedes apoyarnos comprando uno de nuestros productos pagos.
Apreciamos mucho que nos envíe una postal desde su ciudad natal, mencionando cuál de nuestros paquetes está utilizando. Encontrarás nuestra dirección en nuestra página de contacto. Publicamos todas las postales recibidas en nuestro muro virtual de postales.
El objetivo de este paquete es hacer que la construcción de objetos a partir de matrices de datos (serializados) sea lo más fácil posible. Así es como se ve un DTO:
utilizar SpatieDataTransferObjectAttributesMapFrom; utilizar SpatieDataTransferObjectDataTransferObject; la clase MyDTO extiende DataTransferObject {público OtroDTO $otroDTO; público OtroDTOCollection $colección; #[CastWith(ComplexObjectCaster::clase)]public ComplexObject $complexObject; público ComplexObjectWithCast $complexObjectWithCast; #[NúmeroEntre(1, 100)]público int $a; #[MapFrom('address.city')]cadena pública $ciudad; }
Podrías construir este DTO así:
$dto = nuevo MiDTO( R: 5, recopilación: [ ['identificación' => 1], ['identificación' => 2], ['identificación' => 3], ], objeto complejo: ['nombre' => 'prueba', ], complexObjectWithCast: ['nombre' => 'prueba', ], otroDTO: ['id' => 5], );
Analicemos todas las posibilidades una por una.
La construcción de un DTO se puede realizar con argumentos con nombre. También es posible seguir utilizando la antigua notación de matriz. Este ejemplo es equivalente al anterior.
$dto = nuevo MiDTO(['a' => 5,'colección' => [ ['identificación' => 1], ['identificación' => 2], ['identificación' => 3], ],'complexObject' => ['nombre' => 'prueba', ],'complexObjectWithCast' => ['nombre' => 'prueba', ],'otroDTO' => ['id' => 5], ]);
Si un DTO tiene una propiedad que es otro DTO o una colección de DTO, el paquete se encargará de enviar automáticamente matrices de datos a esos DTO:
$dto = nuevo MiDTO( colección: [ // Esto se convertirá en un objeto de clase OtherDTOCollection['id' => 1], ['id' => 2], // Cada elemento será una instancia de OtherDTO['id' => 3], ], otherDTO: ['id' => 5], // Estos datos se enviarán a OtherDTO);
Puede crear sus propias clases de lanzador, que tomarán cualquier información que se les proporcione y la transmitirán al resultado deseado.
Eche un vistazo al ComplexObject
:
clase Objeto Complejo {cadena pública $nombre; }
Y su lanzador ComplexObjectCaster
:
utilizar SpatieDataTransferObjectCaster; la clase ComplexObjectCaster implementa Caster {/** * @param array|valor $mixto * * @return mixto */función pública cast(valor $mixto): ComplexObject{return new ComplexObject( nombre: $valor['nombre'] ); } }
En lugar de especificar qué lanzador debe usarse para cada propiedad, también puede definir ese lanzador en la propia clase de destino:
clase MyDTO extiende DataTransferObject {público ComplexObjectWithCast $complexObjectWithCast; }
#[CastWith(ComplexObjectWithCaster::clase)]clase ComplexObjectWithCaster {cadena pública $nombre; }
Es posible definir ruedas predeterminadas en una clase DTO. Estas ruedas se utilizarán siempre que se encuentre una propiedad con un tipo determinado dentro de la clase DTO.
#[ DefaultCast(DateTimeImmutable::clase, DateTimeImmutableCaster::clase), DefaultCast(MyEnum::clase, EnumCaster::clase), ]La clase abstracta BaseDataTransferObject extiende DataTransferObject {public MyEnum $estado; // Se utilizará EnumCasterpublic DateTimeImmutable $date; // Se utilizará DateTimeImmutableCaster}
A cualquier lanzador se le pueden pasar argumentos personalizados; la implementación incorporada ArrayCaster
es un buen ejemplo de cómo se puede usar esto.
El uso de argumentos con nombre al pasar información a su lanzador ayudará a que su código sea más claro, pero no son obligatorios.
Por ejemplo:
/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionWithNamedArguments; /** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, Foo::class)]public array $collectionWithoutNamedArguments;
Tenga en cuenta que el primer argumento pasado al constructor del lanzador es siempre la matriz con los tipos del valor que se está convirtiendo. Todos los demás argumentos serán los que se pasen como argumentos adicionales en el atributo CastWith
.
Este paquete no ofrece ninguna funcionalidad de validación específica, pero le brinda una manera de crear sus propios atributos de validación. Por ejemplo, NumberBetween
es un atributo de validación implementado por el usuario:
clase MyDTO extiende DataTransferObject { #[NúmeroEntre(1, 100)]público int $a; }
Funciona así debajo del capó:
#[Atributo(Atributo::TARGET_PROPERTY | Atributo::IS_REPEATABLE)]Número de clase Entre implementos Validador {función pública __construct(int privado $min,int privado $max) { }función pública validar(valor $mixto): ValidationResult{if ($valor < $this->min) {return ValidationResult::invalid("El valor debe ser mayor o igual a {$this->min}"); }if ($valor > $this->max) {return ValidationResult::invalid("El valor debe ser menor o igual a {$this->max}"); }return ResultadoValidación::válido(); } }
Puede asignar una propiedad DTO desde una propiedad de origen con un nombre diferente utilizando el atributo #[MapFrom]
.
Funciona con un nombre de propiedad en notación "punto" o un índice.
la clase PostDTO extiende DataTransferObject { #[MapFrom('postTitle')]cadena pública $título; #[MapFrom('user.name')]cadena pública $autor; }$dto = new PostDTO(['postTitle' => 'Hola mundo','usuario' => ['nombre' => 'John Doe'] ]);
clase UserDTO extiende DataTransferObject { #[MapFrom(0)]cadena pública $firstName; #[MapFrom(1)]cadena pública $apellido; }$dto = nuevo UsuarioDTO(['John', 'Doe']);
A veces también deseas asignarlos durante la transformación a Array. Un caso de uso típico sería la transformación de un caso de camello a un caso de serpiente. Para eso puedes usar el atributo #[MapTo]
.
clase UserDTO extiende DataTransferObject { #[MapaDe(0)] #[MapTo('first_name')]cadena pública $firstName; #[MapaDe(1)] #[MapTo('last_name')]cadena pública $apellido; }$dto = new UserDTO(['John', 'Doe']);$dto->toArray() // ['first_name' => 'John', 'last_name'=> 'Doe'];$dto- >only('first_name')->toArray() // ['first_name' => 'John'];
La versión anterior de este paquete agregaba la clase FlexibleDataTransferObject
que le permitía ignorar propiedades que no existían en el DTO. Este comportamiento ha cambiado, todos los DTO ahora son flexibles de forma predeterminada, pero puedes hacerlos estrictos usando el atributo #[Strict]
:
clase NonStrictDto extiende DataTransferObject {cadena pública $nombre; }// Esto funcionanew NonStrictDto( nombre: 'nombre', desconocido: 'desconocido');
utilice SpatieDataTransferObjectAttributesStrict; #[Estricta]clase StrictDto extiende DataTransferObject {cadena pública $nombre; }// Esto genera una excepción SpatieDataTransferObjectExceptionsUnknownPropertiesnew StrictDto( nombre: 'nombre', desconocido: 'desconocido');
También se proporcionan algunas funciones auxiliares para trabajar con varias propiedades a la vez.
$postData->all();$postData->only('título', 'cuerpo') ->toArray(); $postData->except('autor') ->toArray();
Tenga en cuenta que all()
simplemente devolverá todas las propiedades, mientras que toArray()
también convertirá DTO anidados en matrices.
Puedes encadenar los métodos except()
y only()
:
$postData->except('título') ->excepto('cuerpo') ->toArray();
Es importante tener en cuenta que except()
y only()
son inmutables, no cambiarán el objeto de transferencia de datos original.
Este paquete no fuerza objetos inmutables ya que PHP no los admite, pero siempre se le recomienda mantener sus DTO inmutables. Para ayudarle, existe un método clone
en cada DTO que acepta datos para anular:
$clon = $original->clon(otro: ['nombre' => 'a']);
Tenga en cuenta que no se modifica ningún dato en $original
.
Esta versión elimina la clase DataTransferObjectCollection
. En su lugar, puedes utilizar ruedas simples y tus propias clases de colección.
A continuación se muestra un ejemplo de conversión de una colección de DTO a una serie de DTO:
La barra de clases extiende DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(FooArrayCaster::class)]matriz pública $collectionOfFoo; }clase Foo extiende DataTransferObject {cadena pública $nombre; }
clase FooArrayCaster implementa Caster {función pública cast(mixed $value): array{if (! is_array($value)) {throw new Exception("Solo se pueden convertir matrices a Foo"); }return array_map(fn (matriz $datos) => new Foo(...$datos),$valor); } }
Si no desea la sugerencia de tipografía redundante o desea una funcionalidad de recopilación extendida; podrías crear tus propias clases de colección usando cualquier implementación de colección. En este ejemplo, usamos Laravel:
La barra de clases extiende DataTransferObject { #[CastWith(FooCollectionCaster::clase)]public CollectionOfFoo $collectionOfFoo; }clase Foo extiende DataTransferObject {cadena pública $nombre; }
utilice IlluminateSupportCollection; la clase CollectionOfFoo extiende la colección {// Agregue aquí el tipo de retorno correcto para que los analizadores estáticos sepan qué tipo de matriz es esta función pública offsetGet($key): Foo{return parent::offsetGet($key); } }
clase FooCollectionCaster implementa Caster {función pública emitida (valor $ mixto): CollectionOfFoo{return new CollectionOfFoo(array_map(fn (array $data) => new Foo(...$data),$value)); } }
Para una matriz simple de DTO, o un objeto que implemente ArrayAccess
integrado de PHP, considere usar ArrayCaster
, que requiere que se proporcione un tipo de elemento:
La barra de clases extiende DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionOfFoo; }
prueba de compositor
Consulte CHANGELOG para obtener más información sobre los cambios recientes.
Consulte CONTRIBUCIÓN para obtener más detalles.
Si encuentra un error relacionado con la seguridad, envíe un correo electrónico a [email protected] en lugar de utilizar el rastreador de problemas.
Eres libre de utilizar este paquete, pero si llega a tu entorno de producción, te agradeceremos mucho que nos envíes una postal desde tu ciudad natal, mencionando cuál de nuestros paquetes estás utilizando.
Nuestra dirección es: Spatie, Kruikstraat 22, 2018 Amberes, Bélgica.
Publicamos todas las postales recibidas en el sitio web de nuestra empresa.
json2dto: una GUI para convertir objetos JSON en clases DTO (con soporte de anidamiento). También proporciona una herramienta CLI para uso local.
Data Transfer Object Factory: genera de forma inteligente una instancia DTO utilizando el contenido correcto para sus propiedades según su nombre y tipo.
Brent Roose
Todos los contribuyentes
Nuestra clase Arr
contiene funciones copiadas del ayudante Arr
de Laravels.
La Licencia MIT (MIT). Consulte el archivo de licencia para obtener más información.