Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/yzen-dev/plain-to-class
Class-transformer to transform your data into a typed object
https://github.com/yzen-dev/plain-to-class
class-transformer convert dataset php
Last synced: 7 days ago
JSON representation
Class-transformer to transform your data into a typed object
- Host: GitHub
- URL: https://github.com/yzen-dev/plain-to-class
- Owner: yzen-dev
- Created: 2021-03-17T13:54:41.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2023-11-15T15:35:21.000Z (12 months ago)
- Last Synced: 2024-04-25T10:21:41.661Z (7 months ago)
- Topics: class-transformer, convert, dataset, php
- Language: PHP
- Homepage: https://plain-to-class.readthedocs.io/en/latest/
- Size: 300 KB
- Stars: 166
- Watchers: 3
- Forks: 8
- Open Issues: 0
-
Metadata Files:
- Readme: README.RU.md
Awesome Lists containing this project
README
## ClassTransformer
![Packagist Version](https://img.shields.io/packagist/v/yzen.dev/plain-to-class?color=blue&label=version)
![GitHub Workflow Status](https://img.shields.io/github/workflow/status/yzen-dev/plain-to-class/Run%20tests?label=tests&logo=github)
[![Coverage](https://codecov.io/gh/yzen-dev/plain-to-class/branch/master/graph/badge.svg?token=QAO8STLPMI)](https://codecov.io/gh/yzen-dev/plain-to-class)
![License](https://img.shields.io/github/license/yzen-dev/plain-to-class)
![Packagist Downloads](https://img.shields.io/packagist/dm/yzen.dev/plain-to-class)
![Packagist Downloads](https://img.shields.io/packagist/dt/yzen.dev/plain-to-class)Эта библиотека позволит вам легко преобразовать любой набор данных в нужный вам объект. От вас не требуется менять структуру классов, наследовать их от внешних модулей и т.д. Никаких танцев с бубнами - только данные и нужный класс.
Хорошей практикой считается написание кода независимого от сторонних пакетов и фреймворков. Код разбивается на сервисы, доменные зоны, различные слои и т.д. Для передачи данных между слоями, как правило, используется шаблон DataTransfer Object (DTO). DTO - это объект, который необходим для инкапсуляции данных и отправки их из одной подсистемы приложения в другую.
Таким образом, сервисы/методы работают с конкретным объектом и данными необходимым для него. При этом неважно, откуда эти данные были получены - это может быть http запрос, БД, файл и т.д.
Соответственно, при каждом вызове сервиса нам необходимо инициализировать данное DTO. Но сопоставлять каждый раз данные вручную - неэффективно, и сказывается на читабельности кода, особенно если объект сложный.
Здесь на помощь приходит данный пакет, который берет на себя всю работу с мапингом и инициализацией необходимой DTO.
## :scroll: **Установка**
Пакет может быть установлен с помощью composer:
```
композитору требуется yzen.dev/plain-to-class
```> Примечание: Текущая версия пакета поддерживает только PHP 8.1 +.
> Для PHP версии 7.4 вы можете ознакомиться с документацией
> в [версия v0.*](https://github.com/yzen-dev/plain-to-class/tree/php-7.4 ).
>
>Для PHP версии 8.0 вы можете ознакомиться с документацией
> в [версия v1.*](https://github.com/yzen-dev/plain-to-class/tree/php-8.0 ).## :scroll: **Использование**
Общий вариант использования:
### :scroll: **Base**
```
namespace DTO;class CreateUserDTO
{
public string $email;
public float $balance;
}
``````php
$data = [
'email' => '[email protected]',
'balance' => 128.41,
];
$dto = ClassTransformer::transform(CreateUserDTO::class, $data);
var_dump($dto);
```Result:
```php
object(\LoginDTO)
'email' => string(13) "[email protected]"
'balance' => float(128.41)
```Также с версии php 8 вы можете передавать именованные аргументы:
```php
$dto = ClassTransformer::transform(CreateUserDTO::class,
email: '[email protected]',
balance: 128.41
);
```Если свойство не является скалярным типом, и у него явно указан класс, оно будет автоматически рекурсивно к нему
приведено.```php
class ProductDTO
{
public int $id;
public string $name;
}class PurchaseDTO
{
public ProductDTO $product;
public float $cost;
}$data = [
'product' => ['id' => 1, 'name' => 'phone'],
'cost' => 10012.23,
];$purchaseDTO = ClassTransformer::transform(PurchaseDTO::class, $data);
var_dump($purchaseDTO);
```Результат:
```php
object(PurchaseDTO)
public ProductDTO 'product' =>
object(ProductDTO)
public int 'id' => int 1
public string 'name' => string 'phone' (length=5)
public float 'cost' => float 10012.23
```### :scroll: **Коллекция**
Если у вас есть массив объектов определенного класса, то вы должны указать для него атрибут ConvertArray, передав ему в какой класс вам нужно привести элементы.
Также можно указать класс в PHP DOC, но тогда вам нужно написать полный путь к этому классу `array <\DTO\ProductDTO>`.
Это делается для того, чтобы точно знать, какой экземпляр нужно создать. Поскольку Reflection не предоставляет готовых
функций для получения файла `use`. Помимо `use`, вы можете указать псевдоним и его будет сложнее отследить. Пример:```php
class ProductDTO
{
public int $id;
public string $name;
}class PurchaseDTO
{
#[ConvertArray(ProductDTO::class)]
public array $products;
}$data = [
'products' => [
['id' => 1, 'name' => 'phone',],
['id' => 2, 'name' => 'bread',],
],
];
$purchaseDTO = ClassTransformer::transform(PurchaseDTO::class, $data);
```#### :scroll: **Анонимная коллекция**
В случае если вам нужно преобразовать массив данных в массив объектов класса, вы можете реализовать это с помощью
метода `transformCollection`.```php
$data = [
['id' => 1, 'name' => 'phone'],
['id' => 2, 'name' => 'bread'],
];
$products = ClassTransformer::transformCollection(ProductDTO::class, $data);
```В результате этого вы получите массив объектов ProductDTO
```php
array(2) {
[0]=>
object(ProductDTO) {
["id"]=> int(1)
["name"]=> string(5) "phone"
}
[1]=>
object(ProductDTO) {
["id"]=> int(2)
["name"]=> string(5) "bread"
}
}
```Вам также может потребоваться поэлементное преобразование массива. В таком случае вы можете передать массив классов,
который затем можно легко распаковать```php
$userData = ['id' => 1, 'email' => '[email protected]', 'balance' => 10012.23];
$purchaseData = [
'products' => [
['id' => 1, 'name' => 'phone',],
['id' => 2, 'name' => 'bread',],
],
'user' => ['id' => 3, 'email' => '[email protected]', 'balance' => 10012.23,],
];$result = ClassTransformer::transformMultiple([UserDTO::class, PurchaseDTO::class], [$userData, $purchaseData]);
[$user, $purchase] = $result;
var_dump($user);
var_dump($purchase);
```Result:
```php
object(UserDTO) (3) {
["id"] => int(1)
["email"]=> string(13) "[email protected]"
["balance"]=> float(10012.23)
}object(PurchaseDTO) (2) {
["products"]=>
array(2) {
[0]=>
object(ProductDTO)#349 (3) {
["id"]=> int(1)
["name"]=> string(5) "phone"
}
[1]=>
object(ProductDTO)#348 (3) {
["id"]=> int(2)
["name"]=> string(5) "bread"
}
}
["user"]=>
object(UserDTO)#332 (3) {
["id"]=> int(3)
["email"]=> string(13) "[email protected]"
["balance"]=> float(10012.23)
}
}
```### :scroll: ** Стиль написания**
Постоянная проблема со стилем написания, например, в базе данных это snake_case, а в коде camelCase.
И их постоянно нужно как-то трансформировать. Пакет позаботится об этом, вам просто нужно указать
атрибут WritingStyle в свойстве:```php
class WritingStyleSnakeCaseDTO
{
#[WritingStyle(WritingStyle::STYLE_CAMEL_CASE, WritingStyle::STYLE_SNAKE_CASE)]
public string $contact_fio;#[WritingStyle(WritingStyle::STYLE_CAMEL_CASE)]
public string $contact_email;
}$data = [
'contactFio' => 'yzen.dev',
'contactEmail' => '[email protected]',
];
$model = ClassTransformer::transform(WritingStyleSnakeCaseDTO::class, $data);
var_dump($model);
``````php
RESULT:object(WritingStyleSnakeCaseDTO) (2) {
["contact_fio"]=> string(8) "yzen.dev"
["contact_email"]=> string(13) "[email protected]"
}
```### :scroll: **Alias**
Для свойства можно задать различные возможные alias'ы, которые будут также искаться в источнике данных. Это может быть
полезно если DTO формируется по разным источникам данных.```php
class WithAliasDTO
{
#[FieldAlias('userFio')]
public string $fio;#[FieldAlias(['email', 'phone'])]
public string $contact;
}
```### :scroll: **Кастомизация сеттеров**
Если поле требует дополнительной обработки при его инициализации, вы можете мутировать его сеттер. Для это создайте в
классе метод следующего формата - `set{$name}Attribute`. Пример:```php
class UserDTO
{
public int $id;
public string $real_address;public function setRealAddressAttribute(string $value)
{
$this->real_address = strtolower($value);
}
}
```### :scroll: **Пост обработка**
Внутри класса вы можете создать метод `afterTransform`, который вызовется сразу по завершению преобразования. В нем мы
можете описать свою дополнительную логику проверки или преобразования работая уже с состоянием объекта.```php
class UserDTO
{
public int $id;
public float $balance;public function afterTransform()
{
$this->balance = 777;
}
}
```### :scroll: **Кастомное преобразование**
Если вам требуется полностью свое преобразование, то вы можете в классе создать метод transform. В таком случае никакие
обработки библиотеки не вызываются, вся ответственность преобразования переходит на ваш класс.```php
class CustomTransformUserDTOArray
{
public string $email;
public string $username;
public function transform($args)
{
$this->email = $args['login'];
$this->username = $args['fio'];
}
}
```