Aviso Decidimos parar de manter este pacote.
Considere migrar para spatie/laravel-data ou cuyz/valinor.
Sinta-se à vontade para fazer um fork de nosso código e adaptá-lo às suas necessidades.
Você pode instalar o pacote via compositor:
compositor requer espaço/objeto de transferência de dados
Nota : v3 deste pacote suporta apenas php:^8.0
. Se você está procurando a versão mais antiga, confira a v2.
Investimos muitos recursos na criação dos melhores pacotes de código aberto. Você pode nos apoiar comprando um de nossos produtos pagos.
Agradecemos muito que você nos envie um cartão postal de sua cidade natal, mencionando qual(is) de nossos pacotes você está usando. Você encontrará nosso endereço em nossa página de contato. Publicamos todos os cartões postais recebidos em nosso mural virtual de cartões postais.
O objetivo deste pacote é tornar a construção de objetos a partir de matrizes de dados (serializados) o mais fácil possível. Esta é a aparência de um DTO:
use SpatieDataTransferObjectAttributesMapFrom;use SpatieDataTransferObjectDataTransferObject;classe MyDTO estende DataTransferObject {public OtherDTO $otherDTO; public OtherDTOCollection $coleção; #[CastWith(ComplexObjectCaster::class)]public ComplexObject $complexObject; public ComplexObjectWithCast $complexObjectWithCast; #[NumberBetween(1, 100)]public int $a; #[MapFrom('address.city')]public string $cidade; }
Você poderia construir este DTO assim:
$dto = new MeuDTO( um: 5, coleção: [ ['id' => 1], ['id' => 2], ['id' => 3], ], complexObject: ['nome' => 'teste', ], complexObjectWithCast: ['nome' => 'teste', ], outroDTO: ['id' => 5], );
Vamos discutir todas as possibilidades, uma por uma.
A construção de um DTO pode ser feita com argumentos nomeados. Também é possível ainda usar a antiga notação de array. Este exemplo é equivalente ao acima.
$dto = new MeuDTO(['a' => 5,'coleção' => [ ['id' => 1], ['id' => 2], ['id' => 3], ],'complexObject' => ['nome' => 'teste', ],'complexObjectWithCast' => ['nome' => 'teste', ],'outroDTO' => ['id' => 5], ]);
Se um DTO tiver uma propriedade que seja outro DTO ou uma coleção de DTO, o pacote se encarregará de lançar automaticamente matrizes de dados para esses DTOs:
$dto = new MeuDTO( coleção: [ // Isso se tornará um objeto da classe OtherDTOCollection['id' => 1], ['id' => 2], // Cada item será uma instância de OtherDTO['id' => 3], ], otherDTO: ['id' => 5], // Esses dados serão convertidos para OtherDTO);
Você pode construir suas próprias classes de caster, que receberão qualquer entrada fornecida e converterão essa entrada no resultado desejado.
Dê uma olhada no ComplexObject
:
classe ComplexObject {string pública $nome; }
E seu lançador ComplexObjectCaster
:
usar SpatieDataTransferObjectCaster;class ComplexObjectCaster implementa Caster {/** * @param array|valor $misto * * @return misto */função pública cast(valor $misto): ComplexObject{return new ComplexObject( nome: $valor['nome'] ); } }
Em vez de especificar qual caster deve ser usado para cada propriedade, você também pode definir esse caster na própria classe alvo:
classe MyDTO estende DataTransferObject {public ComplexObjectWithCast $complexObjectWithCast; }
#[CastWith(ComplexObjectWithCastCaster::class)]class ComplexObjectWithCast {string pública $nome; }
É possível definir rodízios padrão na própria classe DTO. Esses rodízios serão usados sempre que uma propriedade com um determinado tipo for encontrada na classe DTO.
#[ DefaultCast(DateTimeImmutable::class, DateTimeImmutableCaster::class), DefaultCast(MyEnum::class, EnumCaster::class), ] classe abstrata BaseDataTransferObject estende DataTransferObject {public MyEnum $status; // EnumCaster será usadopublic DateTimeImmutable $date; // DateTimeImmutableCaster será usado}
Qualquer caster pode receber argumentos personalizados, a implementação interna ArrayCaster
é um bom exemplo de como isso pode ser usado.
Usar argumentos nomeados ao passar a entrada para o seu caster ajudará a tornar seu código mais claro, mas eles não são obrigatórios.
Por exemplo:
/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionWithNamedArguments; /** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, Foo::class)]public array $collectionWithoutNamedArguments;
Observe que o primeiro argumento passado para o construtor caster é sempre o array com os tipos do valor que está sendo convertido. Todos os outros argumentos serão aqueles passados como argumentos extras no atributo CastWith
.
Este pacote não oferece nenhuma funcionalidade de validação específica, mas oferece uma maneira de construir seus próprios atributos de validação. Por exemplo, NumberBetween
é um atributo de validação implementado pelo usuário:
classe MyDTO estende DataTransferObject { #[NumberBetween(1, 100)]public int $a; }
Funciona assim nos bastidores:
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]class NumberBetween implementa Validador {função pública __construct(private int $min,private int $max) { }public function activate($value misto): ValidationResult{if ($value < $this->min) {return ValidationResult::invalid("O valor deve ser maior ou igual a {$this->min}"); }if ($value > $this->max) {return ValidationResult::invalid("O valor deve ser menor ou igual a {$this->max}"); }return ValidationResult::valid(); } }
Você pode mapear uma propriedade DTO de uma propriedade de origem com um nome diferente usando o atributo #[MapFrom]
.
Funciona com um nome de propriedade de notação de "ponto" ou um índice.
classe PostDTO estende DataTransferObject { #[MapFrom('postTitle')]public string $title; #[MapFrom('user.name')]public string $author; }$dto = new PostDTO(['postTitle' => 'Olá mundo','user' => ['nome' => 'John Doe'] ]);
classe UserDTO estende DataTransferObject { #[MapFrom(0)]public string $firstName; #[MapFrom(1)]public string $sobrenome; }$dto = new UserDTO(['John', 'Doe']);
Às vezes você também deseja mapeá-los durante a transformação para Array. Um caso de uso típico seria a transformação de uma caixa de camelo em uma caixa de cobra. Para isso você pode usar o atributo #[MapTo]
.
classe UserDTO estende DataTransferObject { #[MapaDe(0)] #[MapTo('first_name')]public string $firstName; #[MapaDe(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'];
A versão anterior deste pacote adicionou a classe FlexibleDataTransferObject
que permitia ignorar propriedades que não existiam no DTO. Este comportamento foi alterado, todos os DTOs agora são flexíveis por padrão, mas você pode torná-los rígidos usando o atributo #[Strict]
:
classe NonStrictDto estende DataTransferObject {string pública $nome; }// Isso funcionanew NonStrictDto( nome: 'nome', desconhecido: 'desconhecido');
usar SpatieDataTransferObjectAttributesStrict; #[Strict]class StrictDto estende DataTransferObject {string pública $nome; }// Isso lança uma exceção SpatieDataTransferObjectExceptionsUnknownPropertiesnew StrictDto( nome: 'nome', desconhecido: 'desconhecido');
Existem também algumas funções auxiliares fornecidas para trabalhar com múltiplas propriedades ao mesmo tempo.
$postData->all();$postData->only('título', 'corpo') ->toArray(); $postData->except('autor') ->toArray();
Observe que all()
simplesmente retornará todas as propriedades, enquanto toArray()
também converterá DTOs aninhados em arrays.
Você pode encadear os métodos except()
e only()
:
$postData->except('título') ->exceto('corpo') ->toArray();
É importante observar que except()
e only()
são imutáveis, eles não alteram o objeto de transferência de dados original.
Este pacote não força objetos imutáveis já que o PHP não os suporta, mas você é sempre incentivado a manter seus DTOs imutáveis. Para ajudá-lo, existe um método clone
em cada DTO que aceita dados para substituição:
$clone = $original->clone(outro: ['nome' => 'a']);
Observe que nenhum dado em $original
é alterado.
Esta versão remove a classe DataTransferObjectCollection
. Em vez disso, você pode usar rodízios simples e suas próprias classes de coleção.
Aqui está um exemplo de conversão de uma coleção de DTOs em uma matriz de DTOs:
classe Bar estende DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(FooArrayCaster::class)]public array $collectionOfFoo; }classe Foo estende DataTransferObject {string pública $nome; }
classe FooArrayCaster implementa Caster {public function cast(misto $value): array{if (! is_array($value)) {throw new Exception("Só pode converter arrays para Foo"); }return array_map(fn (array $dados) => new Foo(...$dados),$valor); } }
Se você não deseja o typehint redundante ou deseja funcionalidade de coleção estendida; você poderia criar suas próprias classes de coleção usando qualquer implementação de coleção. Neste exemplo, usamos o Laravel:
classe Bar estende DataTransferObject { #[CastWith(FooCollectionCaster::class)]public CollectionOfFoo $collectionOfFoo; }classe Foo estende DataTransferObject {string pública $nome; }
use IlluminateSupportCollection;class CollectionOfFoo estende a coleção {// Adicione aqui o tipo de retorno correto para que os analisadores estáticos saibam que tipo de array é esse public function offsetGet($key): Foo{return parent::offsetGet($key); } }
classe FooCollectionCaster implementa Caster {public function cast(misto $valor): CollectionOfFoo{return new CollectionOfFoo(array_map(fn (array $data) => new Foo(...$data),$value)); } }
Para um array simples de DTOs, ou um objeto que implementa ArrayAccess
integrado do PHP, considere usar o ArrayCaster
que requer que um tipo de item seja fornecido:
classe Bar estende DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionOfFoo; }
teste de compositor
Consulte CHANGELOG para obter mais informações sobre o que mudou recentemente.
Consulte CONTRIBUINDO para obter detalhes.
Se você encontrou um bug relacionado à segurança, envie um email para [email protected] em vez de usar o rastreador de problemas.
Você é livre para usar este pacote, mas se ele chegar ao seu ambiente de produção, agradecemos muito que você nos envie um cartão postal de sua cidade natal, mencionando quais de nossos pacotes você está usando.
Nosso endereço é: Spatie, Kruikstraat 22, 2018 Antuérpia, Bélgica.
Publicamos todos os cartões postais recebidos no site da nossa empresa.
json2dto: uma GUI para converter objetos JSON em classes DTO (com suporte a aninhamento). Também fornece uma ferramenta CLI para uso local.
Fábrica de objetos de transferência de dados: gera de forma inteligente uma instância de DTO usando o conteúdo correto para suas propriedades com base em seu nome e tipo.
Brent Roose
Todos os colaboradores
Nossa classe Arr
contém funções copiadas do auxiliar Arr
do Laravel.
A licença MIT (MIT). Consulte Arquivo de licença para obter mais informações.