alexpts / php-data-transformer2
将模型转换为 DTO,将 DTO 转换为模型
Requires
- php: >=8.1
- alexpts/php-hydrator: ^5.0
- psr/container: ^2.0
Requires (Dev)
- fzaninotto/faker: dev-master
- phpunit/phpunit: ^9.5
Suggests
- blackfire/php-sdk: ^1.30
README
允许从对象中提取数据并从数据中创建对象。允许按照预定义的方案在两个方向上执行此操作。例如,从 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' ], ] ];