Laravel: Data Transfer Objects — Зачем и Как

Источник: «Data Transfer Objects in Laravel- Why and How»
Data Transfer Object (DTO) — шаблон, который при правильном использовании может улучшить качество и удобство сопровождения приложения. В этой статье мы узнаем, зачем вы должны использовать DTO в своих приложениях и как это сделать в Laravel.

Что такое Data Transfer Object (DTO)

Объект Передачи Данных (DTO) — шаблон проектирования, используемый для передачи данных между программными системами или уровнями в программной архитектуре. Это простой объект содержащий набор данных, обычно в форме свойств или полей, которые представляют определённый объект или концепцию в системе. Основная цель 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().

Я мог бы сделать рефакторинг используя пользовательский Request класс:

class UserController extends Controller
{
public function store(CreateUserRequest $request): JsonResponse
{
return response()->json([
$this->service->createUser($request->validated()),
Response::HTTP_CREATED
]);
}
}

С приведённым выше кодом, если бы мне нужно было обновить метод createUser и я не помню, какие данные он использует, я мог бы посмотреть CreateUserRequest. Но это создаёт другие проблемы:

  1. Валидация данных теперь связана с HTTP Request. Если мне нужно вызвать метод createUser из моего кода, то нужно будет снова проверить данные вручную.
  2. У вас есть сопоставленные данные, но поскольку $request->validated() возвращает массив, вы не можете принудительно указать тип данных передаваемых в метод createUser.

Если применить шаблон DTO, мы сможем решить обе вышеописанные проблемы. Вместо этого мы можем сопоставить и проверить данные в DTO. Если мне нужно вызвать метод createUser из моего кода, то проверка будет выполнена автоматически, поскольку мне нужно передать DTO методу. И это также принудительно изменит тип данных, которые мы могли бы передать методу createUser поскольку теперь нам нужно будет передать для него определённый DTO.

Как использовать DTO

Как объяснялось выше, DTO могут быть простыми объектами для сопоставления свойств. Таким образом, самой простой реализацией DTO было бы создание простого класса, подобно этому:

class CreateUserDTO
{
public function __construct(
private string $name,
private string $email,
private string $username,
private string $password
) {}

// Добавить геттеры, сеттеры и валидацию
}

Затем можно создать 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.

Таким образом, мы решаем проблемы, которые подробно описали в предыдущем разделе. Теперь код стал более качественным и поддерживаемым.

Заключение

В этой статье мы узнали, что такое Data Transfer Objects, почему нужно использовать их в приложениях и как использовать их в Laravel.

Если вы хотите начать использовать DTO в своих приложениях, я написал пакет WendellAdriel/laravel-validated-dto предоставляющий базовый DTO класс с валидацией и преобразованием типов, а также команду artisan для создания вашего DTO.

Похожие статьи

Дополнительные материалы

Предыдущая Статья

Laravel: Управление маршрутами в большом приложении

Следующая Статья

Laravel: События Модели