DTO не для проверки наличия переменных и их типов.
Да, DTO для прокидывания данных между слоями/процессами.
В моем случае я использую в отдельных сервисах. Которые на вход принимают DTO и делают свою работу на основе его, никак завися от внешних сущностей.
Это модель для общения между слоями.
Я могу просто объявить метод с переменными и код будет чище и понятнее.
function calculate(float $sum, float $percent, int $period) {}
Согласен, с таким примером можно и так указать. Не нужно усложнять простые методы. Пример привел просто для наглядности. Также в начале статьи я специально написал, что речь идет про код, где если у метода больше 2-3 входных аргументов многие делают (array args). Т.е. подразумевая что такое решение с массивом плохое. Так что простые методы где аргументы передаются по порядку (float $sum, float $percent, int $period) я не ставил под сомнение:)
Если рассмотреть создание какого-нибудь пользователя. У нас может быть фамилия, имя, отчество, дата рождения, почта, пароль, номер телефона.
Вы же не будете все 7 аргументов указывать во входных атрибутах?
И опять же у сущности может быть их десятки. И вот в таком кейсе хорошо использовать подход с DTO.
Из-за ублюдочности недоделанной системы типизации php назад можно вернуть dto, если возвращаемых параметров больше одного
Можно уточнить, а в чем все-таки «ублюдочность» типизации? И что плохого в том, что назад мы можем получить тоже DTO? Это ведь конкретная модель, с которой мы потом продолжаем работать, не пойму.
Видимо пример с использованием реквестов многих сбил с основного назначения пакета. Ну это моя первая статья, учту на будущее.
Это не какой-то новый слой, и он никак не зависит от реквеста. Допустим у вас есть бизнесовый сервис, который должен посчитать комиссию по кредиту. В аргументы ему необходимо передать процент годовых, сумма кредита, и период на который запрашивается сумма. Если бы вы использовали подход передачи аргументов массивов, то вам пришлось бы проверять наличие каждого ключа, также, даже если ключ и будет, он может быть любого типа, что тоже нужно проверить.
При описанном подходе вы создаете DTO:
class CalcDTO
{
public float $sum;
public float $percent;
public int $period;
}
Как мы видим, объект всегда будет содержать 3 параметра нужного нам типа. Вы не сможете инициализировать его с другим типов или не указать какое то поле. И тогда вы просто передаете эту DTO в калькулятор, который уже точно знает что все аргументы валидные.
Отвечая на вопрос в чем же чистота:
— Сервис становится типизированным;
— Сервис работает с валидными данными которые приходят к нему в DTO;
— Нам не нужно проверять наличие ключей;
— Исключается возможность передачи неверного типа;
Просто не всегда же все зависит от реквеста:) Поэтому тут скорее реквест требует данные которые необходимы для сервиса, а мой пакет поможет легко преобразовать запрос в нужную DTO.
Если в методе transform вы ручками переписываете все, что прилетело в Request — то где же профит?
Вы переписываете только в случае если наименования параметром из запроса отличается он наименований в DTO. В большинстве же случаев наименования все таки идентичные. Что в запросе firstName, что в сервисе по созданию firstName.
А разве DTO должен реализовывать валидацию?
Если вы используете типизированный подход с declare(strict_types=1), то тогда это сделает пыха, и не даст вам присвоить не верный тип.
По поводу spatie был не прав, выше уже написал об этом.
Я не особо вижу профита в промежуточном объекте вашего ClassTransformer'a для DTO который в целом при такой реализации выступает своего рода фабрикой DTO, при этом не обязательно, чтобы объект был DTO ведь скормить ему можно все что угодно, при этом отсутствует валидация типов.
В этом и суть была, то что я могу скормить туда массив или объект любого класса, а ClassTransformer автоматически преобразует в нужный мне объект DTO.
Валидация типов зависит от вас. Если вы укажите параметру $name тип string, и в dto укажите declare(strict_types=1); то при попытке присвоить имени какой нибудь объект пхп скажет хрен что так нельзя.
Да, вы правы. Первая проблема была все-таки плохого ресерча, из-за которого не смог оценить все текущие решения:( Поэтому сначала запилил свое, а потом только наткнулся на решение от spatie.
Я изначально старался сделать удобнее работу внутренних сервисов, а не получение данных из запроса. Допустим у вас есть бизнесовый сервис, который должен сгенерировать заявление на увольнение. В аргументы ему необходимо передать ФИО работника, должность и дату. В данном случае я могу легко привести любой набор данных, как передать это из запроса:
По-моему, это обертка ради обертки. Подобные реализации избыточны.
Сократить условный 'required|string' ради чего? Всю локализацию ошибок я и так могу отдельно описать.
Не стоит забывать про принцип KISS :)
Да, DTO для прокидывания данных между слоями/процессами.
В моем случае я использую в отдельных сервисах. Которые на вход принимают DTO и делают свою работу на основе его, никак завися от внешних сущностей.
Это модель для общения между слоями.
Согласен, с таким примером можно и так указать. Не нужно усложнять простые методы. Пример привел просто для наглядности. Также в начале статьи я специально написал, что речь идет про код, где если у метода больше 2-3 входных аргументов многие делают (array args). Т.е. подразумевая что такое решение с массивом плохое. Так что простые методы где аргументы передаются по порядку (float $sum, float $percent, int $period) я не ставил под сомнение:)
Если рассмотреть создание какого-нибудь пользователя. У нас может быть фамилия, имя, отчество, дата рождения, почта, пароль, номер телефона.
Вы же не будете все 7 аргументов указывать во входных атрибутах?
И опять же у сущности может быть их десятки. И вот в таком кейсе хорошо использовать подход с DTO.
Можно уточнить, а в чем все-таки «ублюдочность» типизации? И что плохого в том, что назад мы можем получить тоже DTO? Это ведь конкретная модель, с которой мы потом продолжаем работать, не пойму.
Это не какой-то новый слой, и он никак не зависит от реквеста. Допустим у вас есть бизнесовый сервис, который должен посчитать комиссию по кредиту. В аргументы ему необходимо передать процент годовых, сумма кредита, и период на который запрашивается сумма. Если бы вы использовали подход передачи аргументов массивов, то вам пришлось бы проверять наличие каждого ключа, также, даже если ключ и будет, он может быть любого типа, что тоже нужно проверить.
При описанном подходе вы создаете DTO:
Как мы видим, объект всегда будет содержать 3 параметра нужного нам типа. Вы не сможете инициализировать его с другим типов или не указать какое то поле. И тогда вы просто передаете эту DTO в калькулятор, который уже точно знает что все аргументы валидные.
Отвечая на вопрос в чем же чистота:
— Сервис становится типизированным;
— Сервис работает с валидными данными которые приходят к нему в DTO;
— Нам не нужно проверять наличие ключей;
— Исключается возможность передачи неверного типа;
Просто не всегда же все зависит от реквеста:) Поэтому тут скорее реквест требует данные которые необходимы для сервиса, а мой пакет поможет легко преобразовать запрос в нужную DTO.
Вы переписываете только в случае если наименования параметром из запроса отличается он наименований в DTO. В большинстве же случаев наименования все таки идентичные. Что в запросе firstName, что в сервисе по созданию firstName.
А разве DTO должен реализовывать валидацию?
Если вы используете типизированный подход с declare(strict_types=1), то тогда это сделает пыха, и не даст вам присвоить не верный тип.
В этом и суть была, то что я могу скормить туда массив или объект любого класса, а ClassTransformer автоматически преобразует в нужный мне объект DTO.
Валидация типов зависит от вас. Если вы укажите параметру $name тип string, и в dto укажите declare(strict_types=1); то при попытке присвоить имени какой нибудь объект пхп скажет хрен что так нельзя.
Но ведь тут совсем другой кейс.
Мой пакет только преобразует набор данных к нужному DTO классу.
Я изначально старался сделать удобнее работу внутренних сервисов, а не получение данных из запроса. Допустим у вас есть бизнесовый сервис, который должен сгенерировать заявление на увольнение. В аргументы ему необходимо передать ФИО работника, должность и дату. В данном случае я могу легко привести любой набор данных, как передать это из запроса:
так и сразу сущность из базы:
И дополнительно повлияло то, что среди окружения не было тех, кто бы применял такой подход, и следовательно кто бы знал о подобных решениях.
Так что пока не вижу ничего плохого в еще одном решение. Буду стараться развивать пакет, и может быть у меня появятся какие-нибудь свои фичи:)
Сократить условный 'required|string' ради чего? Всю локализацию ошибок я и так могу отдельно описать.
Не стоит забывать про принцип KISS :)