Какие существуют хорошие готовые решения для реализации data transfer object на php?

Доброго времени.
Исторически работаю преимущественно с Laravel. Но Вопрос интересует, скорее, в целом. Без привязки к конкретному фреймворку.
Некоторое время назад решил/возникла необходимость активно юзать DTO.
Полез искать готовые библиотеки.
Сразу обратил внимание на Data transfer object от Spatie. Вроде как считается дефакто стандартом в проектах на ларке. Плюс многие советовали.
Да, достаточно лёгкая и простая либа. Но.
Мне не нравится что все свойства торчат наружу (публичные). При заполнении объекта через конструктор мы ещё можем контролировать то, что мы туда пихаем, но нам никто не запрещает потом присвоить свойству любое значение. В целом, вопрос решается путём типизации свойств. Более того, можно сделать, чтобы каждое значение свойства представляло собой инстанс соответствующего ValueObject. но всё же...
Сразу небольшое примечание. Я понимаю, что правильная работа с DTO состоит в том, чтобы в одном месте мы заполнили объект значениями, а в другом - прочитали эти значения. И нигде по дороге они не должны/не могут модифицироваться. Если у нас сохраняется вероятность того, что где-то по пути от источника до получателя данные могут неконтролируемо измениться, то что-то идёт не так и у меня большие проблемы. Но параноя отказывается принимать разумную аргументацию.
Дальше. В рамках этой либы есть понятие кастеров и валидаторов.
Кастеры приводят значение к какому-то виду, прежде, чем поместить его в DTO. А валидаторы. Ну, они и в африке валидаторы.
И вроде всё прекрасно, если бы не порядок выполнения. Сначала отрабатывают кастеры, а потом уже валидаторы. Что мне кажется крайне странным.
Например, если нам нужно указать номер порта, очевидно, что мы сначала хотим проверить попадает ли число в разрешённый диапазон, и вообще является ли значение числом. А только потом создать некий ValueObject с этим значением. Но никак не наоборот.
Одним словом, либа не зашла.
И я написал своё решение на основе Symfony OptionsResolver.
Работает нормально, свои задачи выполняет, вроде норм. Но не оставляет ощущение, что это всё из пушки по воробьям.

В общем, кто что из вас использует для этих целей?
Может есть хорошие готовые решения, которые мне не попадались на глаза.

Или мне просто стоит понизить планку.. Даже не знаю планку чего. Перфекционизма что ли? И просто наслаждаться жизнью?
  • Вопрос задан
  • 1348 просмотров
Решения вопроса 5
Вообще не валидируем DTO. Он нужен только для перекидывания данных из одного слоя в другой. Что с этими данными будет на той стороне уже не касается того кто его создавал: на этапе создания dto уже поздно думать что где-то данные не того допуска, так как мы их либо из базы достали или сервиса или просто сгенерировали на лету. Принимающая сторона, если нужно, может провалидировать значения перед использованием и если что-то окажется за пределами допустимых значений как-то обработать данный кейс.

В данном контексте можно вспомнить про команды и запросы для CQRS. Мы их создаем через сериализатор: на вход подается массив данных для заполнения полей в создаваемой команде/запросе и класс команды/запроса в котором через аннотации указаны параметры валидации.
Ответ написан
Комментировать
@vism
У меня было время, когда всё идеально делать хотелось. И делал. А потом смотрел результат, можно было в 10 раз быстрее сделать, т.к. функционал не рос за несколько лет.
А те вещи которые сделал гибко и громоздко, и которые часто менялись, да удобно. да гибко.
Но по факту если бы всё сделал по простому, но с умом. Те пару компонентов можно было по факту отрефакторить.

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

Вобщем рефакторинг по мере усложнения, тем самым и уровень вхождения в проекты намного ниже, и быстрее и кода меньше.
Ответ написан
Комментировать
@kot999
Backend software engineer
Мне самому был бы интересен ответ на вопрос.
Мысли вслух: Если сделать readonly объект и позволить его сетить только через конструктор, будет ли удобно это делать для больших объектов. Описывать конструктор который принимает 50 аргументов?
может быть можно сделать доступ к аргументам через магический метод __get и аннотации, а сетить уже через сеттеры, билдером, например.
Лично я параноиться по поводу ридонли я бы не стал, т.к. Если кто-то захочет изменить объект, он его изменит , рефлексию никто не отменял. Это скорее должно работать на уровне договоренностей.
Но это только мое мнение, не претендую на истину.
Ответ написан
int128
@int128
developer
Вот хороший доклад на эту тему https://youtu.be/gDEFVplbB4Q
Ответ написан
Комментировать
dostrog
@dostrog
А я пользуюсь spatie/DTO и доволен. Тоже очень сильно сомневался как и вы вначале, но потом (как правильно заметил vism ) успокоился. Решаем же бизнес задачу, а не пишем академическую учебную работу.

Основной пакет spatie/DTO он не для Ларавеля. Он "общий". Для Лары есть отдельно, на его основе.
В ноябре выйдет 8.1 пых, там будут readonly для свойств.
В паре случаев, я переопределял конструктор, чтобы предвалидировать по-своему параметры перед кастингом.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы