Предупреждение. Мы решили прекратить поддержку этого пакета.
Рассмотрите возможность перехода на spatie/laravel-data или cuyz/valinor.
Не стесняйтесь форкнуть наш код и адаптировать его под свои нужды.
Вы можете установить пакет через композитор:
композитор требует spatie/data-transfer-object
Примечание . Версия 3 этого пакета поддерживает только php:^8.0
. Если вы ищете более старую версию, обратите внимание на v2.
Мы вкладываем много ресурсов в создание лучших в своем классе пакетов с открытым исходным кодом. Вы можете поддержать нас, купив один из наших платных продуктов.
Мы очень признательны вам за отправку нам открытки из вашего родного города с указанием того, какой из наших пакетов вы используете. Наш адрес вы найдете на странице контактов. Все полученные открытки мы публикуем на нашей виртуальной стене открыток.
Цель этого пакета — максимально упростить создание объектов из массивов (сериализованных) данных. Вот как выглядит DTO:
использовать SpatieDataTransferObjectAttributesMapFrom; использовать SpatieDataTransferObjectDataTransferObject; класс MyDTO расширяет DataTransferObject {public OtherDTO $otherDTO; общедоступная коллекция OtherDTOCollection $collection; #[CastWith(ComplexObjectCaster::class)]public ComplexObject $complexObject; общественный ComplexObjectWithCast $ complexObjectWithCast; #[NumberBetween(1, 100)]public int $a; #[MapFrom('address.city')]публичная строка $city; }
Вы можете построить этот DTO следующим образом:
$dto = новый MyDTO( а: 5, коллекция: [ ['id' => 1], ['id' => 2], ['id' => 3], ], complexObject: ['name' => 'тест', ], complexObjectWithCast: ['name' => 'test', ], другойDTO: ['id' => 5], );
Давайте обсудим все возможности по отдельности.
Построение DTO можно выполнить с помощью именованных аргументов. Также возможно использовать старую нотацию массива. Этот пример эквивалентен приведенному выше.
$dto = новый MyDTO(['a' => 5,'collection' => [ ['id' => 1], ['id' => 2], ['id' => 3], ],'complexObject' => ['name' => 'test', ],'complexObjectWithCast' => ['name' => 'test', ],'otherDTO' => ['id' => 5], ]);
Если у DTO есть свойство, которое является другим DTO или коллекцией DTO, пакет позаботится об автоматическом преобразовании массивов данных в эти DTO:
$dto = новый MyDTO( Collection: [ // Это станет объектом класса OtherDTOCollection['id' => 1], ['id' => 2], // Каждый элемент будет экземпляром OtherDTO['id' => 3], ], OtherDTO: ['id' => 5], // Эти данные будут преобразованы в OtherDTO);
Вы можете создавать свои собственные классы заклинателей, которые будут принимать любые входные данные и приводить их к желаемому результату.
Взгляните на ComplexObject
:
класс КомплексОбъект {публичная строка $имя; }
И его заклинатель ComplexObjectCaster
:
используйте SpatieDataTransferObjectCaster; класс ComplexObjectCaster реализует Caster {/** * @param array|mixed $value * * @return mix */public function cast(mixed $value): ComplexObject{return new ComplexObject( имя: $value['имя'] ); } }
Вместо того, чтобы указывать, какой заклинатель следует использовать для каждого свойства, вы также можете определить этот заклинатель в самом целевом классе:
класс MyDTO расширяет DataTransferObject {public ComplexObjectWithCast $ complexObjectWithCast; }
#[CastWith(ComplexObjectWithCastCaster::class)]class ComplexObjectWithCast {публичная строка $имя; }
Можно определить кастеры по умолчанию в самом классе DTO. Эти кастеры будут использоваться всякий раз, когда в классе DTO встречается свойство заданного типа.
#[ DefaultCast(DateTimeImmutable::class, DateTimeImmutableCaster::class), DefaultCast(MyEnum::class, EnumCaster::class), ]абстрактный класс BaseDataTransferObject расширяет DataTransferObject {public MyEnum $status; // Будет использоваться EnumCasterpublic DateTimeImmutable $date; // Будет использоваться DateTimeImmutableCaster}
Любому кастингу можно передавать собственные аргументы, встроенная реализация ArrayCaster
— хороший пример того, как это можно использовать.
Использование именованных аргументов при передаче входных данных вашему заклинателю поможет сделать ваш код более понятным, но они не являются обязательными.
Например:
/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionWithNamedArguments; /** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, Foo::class)]public array $collectionWithoutNamedArguments;
Обратите внимание, что первый аргумент, передаваемый конструктору приведения, всегда представляет собой массив с типом(ами) приводимого значения. Все остальные аргументы будут переданы в качестве дополнительных аргументов в атрибуте CastWith
.
Этот пакет не предлагает каких-либо конкретных функций проверки, но дает возможность создавать собственные атрибуты проверки. Например, NumberBetween
— это атрибут проверки, реализуемый пользователем:
класс MyDTO расширяет DataTransferObject { #[NumberBetween(1, 100)]public int $a; }
Под капотом это работает так:
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)]класс NumberBetween реализует Валидатор {публичная функция __construct(private int $min,private int $max) { } public function validate(mixed $value): ValidationResult{if ($value < $this->min) {return ValidationResult::invalid("Значение должно быть больше или равно {$this->min}"); }if ($value > $this->max) {return ValidationResult::invalid("Значение должно быть меньше или равно {$this->max}"); } return ValidationResult::valid(); } }
Вы можете сопоставить свойство DTO с исходным свойством с другим именем, используя атрибут #[MapFrom]
.
Он работает с именем свойства «точечная» нотация или индексом.
класс PostDTO расширяет DataTransferObject { #[MapFrom('postTitle')]публичная строка $title; #[MapFrom('user.name')]публичная строка $author; }$dto = new PostDTO(['postTitle' => 'Привет, мир','user' => ['name' => 'Джон Доу'] ]);
класс UserDTO расширяет DataTransferObject { #[MapFrom(0)]публичная строка $firstName; #[MapFrom(1)]публичная строка $lastName; }$dto = новый UserDTO(['Джон', 'Доу']);
Иногда вам также нужно сопоставить их во время преобразования в Array. Типичным вариантом использования будет трансформация из чехла-верблюда в чехол-змею. Для этого вы можете использовать атрибут #[MapTo]
.
класс UserDTO расширяет DataTransferObject { #[КартаИз(0)] #[MapTo('first_name')]публичная строка $firstName; #[КартаИз(1)] #[MapTo('last_name')]публичная строка $lastName; }$dto = new UserDTO(['John', 'Doe']);$dto->toArray() // ['first_name' => 'John', 'last_name'=> 'Doe'];$dto- >only('first_name')->toArray() // ['first_name' => 'Джон'];
В предыдущей версии этого пакета был добавлен класс FlexibleDataTransferObject
, который позволял игнорировать свойства, отсутствующие в DTO. Это поведение было изменено, все DTO теперь по умолчанию являются гибкими, но вы можете сделать их строгими, используя атрибут #[Strict]
:
класс NonStrictDto расширяет DataTransferObject {публичная строка $имя; }// Это работает, новый NonStrictDto( имя: 'имя', неизвестно: 'неизвестно');
используйте SpatieDataTransferObjectAttributesStrict; #[Strict]класс StrictDto расширяет DataTransferObject {публичная строка $имя; }// Это вызывает исключение SpatieDataTransferObjectExceptionsUnknownPropertiesnew StrictDto( имя: 'имя', неизвестно: 'неизвестно');
Также предусмотрены некоторые вспомогательные функции для одновременной работы с несколькими свойствами.
$postData->all();$postData->only('title', 'body') ->ToArray(); $postData->кроме('автор') ->ToArray();
Обратите внимание, что all()
просто вернет все свойства, а toArray()
также приведет к массивам вложенные DTO.
Вы можете связать методы except()
и only()
:
$postData->кроме('название') ->кроме('тело') ->ToArray();
Важно отметить, что except()
и only()
являются неизменяемыми, они не изменят исходный объект передачи данных.
Этот пакет не требует обязательного использования неизменяемых объектов, поскольку PHP их не поддерживает, но вам всегда рекомендуется сохранять неизменяемыми объекты DTO. Чтобы помочь вам, в каждом DTO есть метод clone
, который принимает данные для переопределения:
$clone = $original->clone(other: ['name' => 'a']);
Обратите внимание, что никакие данные в $original
не изменяются.
В этой версии удален класс DataTransferObjectCollection
. Вместо этого вы можете использовать простые кастингеры и свои собственные классы коллекций.
Вот пример приведения коллекции DTO к массиву DTO:
класс Bar расширяет DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(FooArrayCaster::class)]публичный массив $collectionOfFoo; } Класс Foo расширяет DataTransferObject {публичная строка $имя; }
класс FooArrayCaster реализует Caster {публичная функция cast(смешанное $value): array{if (! is_array($value)) {throw new Exception("Можно приводить только массивы к Foo"); } return array_map(fn (массив $data) => new Foo(...$data),$value); } }
Если вам не нужна избыточная подсказка или вам нужна расширенная функциональность коллекции; вы можете создавать свои собственные классы коллекций, используя любую реализацию коллекций. В этом примере мы используем Laravel:
класс Bar расширяет DataTransferObject { #[CastWith(FooCollectionCaster::class)]public CollectionOfFoo $collectionOfFoo; } Класс Foo расширяет DataTransferObject {публичная строка $имя; }
используйте IlluminateSupportCollection; класс CollectionOfFoo расширяет коллекцию {// Добавьте сюда правильный тип возвращаемого значения, чтобы статические анализаторы могли знать, какой это тип массива. public function offsetGet($key): Foo{return Parent::offsetGet($key); } }
класс FooCollectionCaster реализует Caster {публичное приведение функции (смешанное значение $): CollectionOfFoo {вернуть новую CollectionOfFoo (array_map (fn (массив $ data) => new Foo (... $ data), $ value)); } }
Для простого массива DTO или объекта, реализующего встроенный в PHP ArrayAccess
, рассмотрите возможность использования ArrayCaster
, который требует предоставления типа элемента:
класс Bar расширяет DataTransferObject {/** @var SpatieDataTransferObjectTestsFoo[] */#[CastWith(ArrayCaster::class, itemType: Foo::class)]public array $collectionOfFoo; }
композиторский тест
Пожалуйста, посетите CHANGELOG для получения дополнительной информации о том, что изменилось за последнее время.
Пожалуйста, смотрите ВКЛАД для получения подробной информации.
Если вы обнаружили ошибку, связанную с безопасностью, отправьте электронное письмо по адресу [email protected] вместо использования системы отслеживания проблем.
Вы можете свободно использовать этот пакет, но если он попадет в вашу производственную среду, мы будем очень признательны, если вы отправите нам открытку из вашего родного города с указанием того, какой из наших пакетов вы используете.
Наш адрес: Spatie, Kruikstraat 22, 2018, Антверпен, Бельгия.
Все полученные открытки мы публикуем на сайте нашей компании.
json2dto: графический интерфейс для преобразования объектов JSON в классы DTO (с поддержкой вложенности). Также предоставляет инструмент CLI для локального использования.
Фабрика объектов передачи данных: интеллектуально генерирует экземпляр DTO, используя правильное содержимое для ваших свойств на основе его имени и типа.
Брент Руз
Все участники
Наш класс Arr
содержит функции, скопированные из помощника Laravels Arr
.
Лицензия MIT (MIT). Дополнительную информацию см. в файле лицензии.