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.