DEV Community

Marcelo Chiaretto
Marcelo Chiaretto

Posted on

DTOs e PHP: simplificando a transferência de dados entre as camadas da aplicação

O padrão DTO

O DTO (Data Transfer Object) é um padrão de projeto que visa ter objetos usados exclusivamente para a transferência de dados entre camadas de uma aplicação. É um objeto anêmico, ou seja, a classe tem apenas atributos e sem métodos que manipulem dados, apenas de construção do objeto.

Porque não um utilizar um array para receber dados em método?

Observe a classe CreateProduct:

<?php

namespace App\Actions\Product;

use App\Product\Contracts\ProductRepository;

class CreateProduct
{
    public function __construct(private ProductRepository $repository) {}

    public function execute(array $data): Product
    {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

Como o método execute() recebe um array associativo, quem instanciar essa classe precisará abrir o método e ver quais chaves do array será necessário informar.

Substituindo o array pelo DTO

Podemos construir uma classe DTO no PHP utilizando o modificador readonly para que os atributos dos objetos não sejam alterados.

PHP 8.1:

<?php

namespace App\Dto;

readonly class ProductDto
{
    public function __construct(
        public string $name,
        public string $description,
        public float $price,
        public int $quantity,
        public int $categoryId,
        public int $brandId,
        public string $sku,
        public string $ean
    ) {}
}
Enter fullscreen mode Exit fullscreen mode

E na classe CreateProduct podemos alterar o método execute():

public function execute(ProductDto $data): Product
{
    //
}
Enter fullscreen mode Exit fullscreen mode

Benefícios para a IDE

Ao utilizar a classe DTO no lugar do array associativo a IDE irá ajudar a identificar os atributos necessários:

Instanciando a classe ProductDto

E também na utilização desses dados:

Utilizando objeto ProductDto

Indo além com métodos estáticos

Para facilitar a criação desses objetos podemos criar métodos estáticos:

public static function fromRequest(Request $request): self
{
    return new self(
        name: $request->name,
        description: $request->description,
        price: $request->price,
        quantity: $request->quantity,
        categoryId: $request->category_id,
        brandId: $request->brand_id,
        sku: $request->sku,
        ean: $request->ean
    );
}

public static function fromArray(array $data): self
{
    return new self(
        name: $data['name'],
        description: $data['description'],
        price: $data['price'],
        quantity: $data['quantity'],
        categoryId: $data['categoryId'],
        brandId: $data['brandId'],
        sku: $data['sku'],
        ean: $data['ean']
    );
}
Enter fullscreen mode Exit fullscreen mode

E utilizando dessa forma:

$data = ProductDto::fromRequest($request);
Enter fullscreen mode Exit fullscreen mode

Quando não utilizar

Não vejo a necessidade de utilizar um DTO como parâmetro em métodos públicos que já indicam o dado que espera receber, como por exemplo um método que buscará uma lista de produtos pelos IDs informados:

class FindProducts
{
    public function execute(array $productsIds): Product
    {
        //
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)