alexpts/php-data-transformer2

将模型转换为 DTO,将 DTO 转换为模型

6.1.2 2023-01-05 11:11 UTC

This package is auto-updated.

Last update: 2024-09-05 14:50:24 UTC


README

phpunit codecov

允许从对象中提取数据并从数据中创建对象。允许按照预定义的方案在两个方向上执行此操作。例如,从 Model 中提取数据以记录到数据库。或者从数据库中创建/填充 Model 数据。

安装

composer require alexpts/php-data-transformer2

该库是 https://github.com/alexpts/php-hydrator 库的高级版本。通过扩展其功能并简化工作,提高了其效率

  • 声明性描述转换规则
  • 递归转换嵌套模型和模型集合
  • 更简洁的语法

基本转换方案规则在项目 https://github.com/alexpts/php-hydrator 中详细描述。

数据转换器

DataTransformer 类是高级的。它允许使用 HydratorService 并为每个类单独描述转换方案。

对于单个类,可以有许多转换方案。对于将模型保存到数据库的转换,需要将其转换为 DTO 实体(PHP 数组)。在此过程中,所有 \DateTime 类型的值都应转换为时间戳(整数类型)。如果我们通过 REST API 将同一模型传递给客户端,则转换方案可能不同。所有 \DateTime 值都需要以 ISO8601 格式的字符串表示。

use PTS\DataTransformer\DataTransformer;

$dataTransformer = new DataTransformer;
$dataTransformer->getMapsManager()->setMapDir(UserModel::class, __DIR__ . '/data');

$model = $dataTransformer->toModel(UserModel::class, [
    'id' => 1,
    'creAt' => new DateTime,
    'name' => 'Alex',
    'active' => 1,
]);

$dto = $dataTransformer->toDTO($model, 'dto');
$dtoForDb = $dataTransformer->toDTO($model, 'db');

表示变体

可能需要根据不同的场景从模型中提取不同的数据。或者可能只需要一个更紧凑的模型表示,而不需要额外的细节。可以为单个模型使用多个方案,例如 short.dto

$shortFormatDto = $dataTransformer->toDTO($model, 'short.dto');

也可以排除部分字段,而不需要为转换定义新的方案/映射,只需在调用时使用 excludeFields 选项指定要排除的字段数组即可。

$shortFormatDto = $dataTransformer->toDTO($model, 'dto', [
     'excludeFields' => ['password']
]);

模型集合

将同类型模型集合转换为 DTO 集合的小工具

$mapName = 'dto';
$excludedFields = ['name'];
$dtoCollection = $dataTransformer->toDtoCollection($models, $mapName);

嵌套模型

如果模型的属性是另一个模型或模型集合,则可以递归地提取/填充模型。为此,在映射方案中需要使用键 ref

// map file deepDto.php
return [
    'id' => [],
    'creAt' => [],
    'name' => [],
    'login' => [],
    'active' => [
        'pipe-populate' => ['boolval'],
        'pipe-extract' => ['boolval'],
    ],
    'email' => [
        'pipe-populate' => [ // any callable
            'strval',
            'strtolower',
         ]
    ],
    'refModel' => [
        'ref' => [
            'model' => UserModel::class,
            'map' => 'dto'
        ]
    ],
    'refModels' => [
        'ref' => [
            'model' => UserModel::class,
            'map' => 'dto',
            'collection' => true
        ]
    ],
];

// code file
$model = $dataTransformer->toModel(UserModel::class, [
    'id' => 1,
    'creAt' => new DateTime,
    'name' => 'Alex',
    'active' => 1,
    'refModel' => [
        'id' => 2,
        'name' => 'refModel',
    ]
], 'deepDto');

$model2 = $dataTransformer->toModel(UserModel::class, [
    'id' => 1,
    'creAt' => new DateTime,
    'name' => 'Alex',
    'active' => 1,
    'refModels' => [ // collection ref models
        [
            'id' => 2,
            'name' => 'refModel',
        ],
        [
            'id' => 2,
            'name' => 'refModel',
        ]
    ]
], 'deepDto');

pipe 处理器中的逻辑

pipe 处理器允许描述可调用的方法并编写任何将被应用于值的逻辑。在 pipe 处理器中可以强制类型。或者加密在数据库中写入前的字段。如果需要将整个映射逻辑集中在一个地方,可以通过将依赖项通过闭包传递到函数 pipe 中,从 $this->getContainer() 容器中获取它们来实现。

<?php
/**
 * @var MapsManager $this
 */

use PTS\DataTransformer\MapsManager;

$encrypter = $this->getContainer()->get('encrypter');

return [
    'id' => [],
    'creAt' => [],
    'name' => [],
    'password' => [
        'pipe-populate' => [
            'strtolower',
            function(string $openPassword) use($encrypter) {
                return $encrypter->encrypt($openPassword);
            },
        ],
        'pipe-extract' => [
            function(string $ePassword) use($encrypter) {
                return $encrypter->decrypt($ePassword);
            },
            'strtolower'
        ],
    ]
];

迁移

更新 5 到 6