Data Transfer Object (Объект передачи данных) — паттерн программирования, который, при правильном использовании, может улучшить качество код и удобство его дальнейшего сопровождения. В этой статье мы узнаем, почему нужно использовать DTO и как это сделать в Laravel.
Что такое объект передачи данных?
Объект передачи данных (DTO) используется для передачи данных между уровнями приложения. Это простой объект, который содержит набор данных, обычно в форме свойств или полей, которые представляют определенный объект или концепцию в системе. Основная цель DTO — отделить различные уровни или компоненты, позволяя им взаимодействовать и обмениваться данными без необходимости знать детали реализации друг друга.
Зачем использовать DTO
И для небольших и для сложных систем существуют стандарты и паттерны, которые позволяют создавать код высокого качества, легко поддерживаемый, адаптируемый и обновляемый, и именно здесь в игру вступают DTO.
Допустим, у меня есть такой код:
class UserController extends Controller
{
public function store(Request $request): JsonResponse
{
return response()->json([
$this->service->createUser($request->all()),
Response::HTTP_CREATED
]);
}
}
И мне нужно изменить метод createUser. Это, в целом, довольно простой код, но если бы я его создавал год назад, то и не вспомнил бы какие данные возвращает метод $request->all().
Я мог бы отрефакторить всё это через класс Custom Request:
class UserController extends Controller
{
public function store(CreateUserRequest $request): JsonResponse
{
return response()->json([
$this->service->createUser($request->validated()),
Response::HTTP_CREATED
]);
}
}
Но теперь возникают две другие проблемы:
— валидация теперь связана с HTTP-запросом. Если мне нужно вызвать метод createUser, то мне нужно будет снова вручную провалидировать данные.
— данные маппированы, но поскольку $request->validated() возвращает массив, то не получится принудительно указать тип данных, передаваемых методу createUser.
Если мы применим здесь паттерн DTO, то сможем решить обе вышеописанные проблемы. Будем маппировать и валидировать данные в DTO. И теперь, при вызове метода createUser откуда либо, валидация будет произведена автоматически, нужно просто передать DTO в метод.
Как использовать DTO
Как объяснялось выше, DTO могут быть простыми объектами для маппирования свойств. Таким образом, самой простой реализацией DTO было бы создание следующего класса:
class CreateUserDTO
{
public function __construct(
private string $name,
private string $email,
private string $username,
private string $password
) {}
// Add getters, setters, validation
}
Затем создаём свой DTO из Request:
class UserController extends Controller
{
public function store(Request $request): JsonResponse
{
return response()->json([
$this->service->createUser(new CreateUserDTO(...$request->all())),
Response::HTTP_CREATED
]);
}
}
В new CreateUserDTO(...$request->all()) мы используем именованные аргументы из PHP 8 для создания экземпляра CreateUserDTO.
Таким образом, мы решаем проблемы, которые мы подробно описали в предыдущем разделе. Теперь у нас качественный код и его легко поддерживать.
Заключение
В этой статье мы узнали, что такое Объекты передачи данных, почему мы должны использовать их в наших приложениях и как их использовать в Laravel .
Если вы хотите начать использовать DTO в своих приложениях, я создал специальный пакет, который предоставляет базовый DTO-класс с валидацией и преобразованием типов, а также artisan-команду для создания DTO.
Автор: Wendell Adriel
Перевод: Алексей Широков
Наш Телеграм-канал — следите за новостями о Laravel.
