shipmonk / input-mapper
支持泛型、数组形状、可选字段等的高性能数组到对象映射器!
Requires
- php: ^8.1
- nette/utils: ^3.2 || ^4.0
- nikic/php-parser: ^4.15
- phpstan/phpdoc-parser: ^1.18.1
Requires (Dev)
- editorconfig-checker/editorconfig-checker: ^10.6.0
- ergebnis/composer-normalize: ^2.43.0
- phpstan/phpstan: ^1.12.0
- phpstan/phpstan-phpunit: ^1.4.0
- phpstan/phpstan-strict-rules: ^1.6.0
- phpunit/phpunit: ^10.5
- shipmonk/composer-dependency-analyser: ^1.7
- shipmonk/name-collision-detector: ^2.1.1
- shipmonk/phpstan-rules: ^3.2.0
- slevomat/coding-standard: ^8.15.0
This package is auto-updated.
Last update: 2024-09-09 14:06:32 UTC
README
高性能PHP输入映射器,支持泛型、数组形状和可空类型。对于每个输入类,在运行时生成映射器并在磁盘上缓存。映射器只生成一次,然后在后续请求中重用。生成的映射器高度优化以提高性能,且设计为易于阅读。您可以在测试目录中查看生成的映射器示例。
安装
composer require shipmonk/input-mapper
功能
内置映射器
Input Mapper 包含以下类型的内置映射器
array
,bool
,float
,int
,mixed
,string
,list
positive-int
,negative-int
,int<TMin, TMax>
,non-empty-list
array<V>
,array<K, V>
,list<V>
,non-empty-list<V>
array{K1: V1, ...}
?T
,Optional<T>
DateTimeInterface
,DateTimeImmutable
BackedEnum
- 最重要的是具有公共构造函数的类
您可以编写自己的映射器或用您自己的映射器替换默认映射器。
内置验证器
Input Mapper 包含一些内置验证器
- 整数验证器
AssertInt16
AssertInt32
AssertIntRange
AssertPositiveInt
AssertNegativeInt
AssertNonNegativeInt
AssertNonPositiveInt
AssertIntMultipleOf
- 浮点数验证器
AssertFloatRange
AssertPositiveFloat
AssertNegativeFloat
AssertNonNegativeFloat
AssertNonPositiveFloat
AssertFloatMultipleOf
- 字符串验证器
AssertStringLength
AssertStringMatches
AssertUrl
- 列表验证器
AssertListItem
AssertListLength
AssertUniqueItems
(通过===
比较项目)
- 日期时间验证器
AssertDateTimeRange
如果您需要更多,可以编写自己的验证器。
用法
编写输入类
要使用 Input Mapper,编写一个具有公共构造函数的类,并将本机类型或 PHPDoc 类型添加到所有构造函数参数。
可选字段可以是带有 #[Optional]
属性的(允许您指定默认值),或者如果您需要区分默认值和缺失值,您可以使用 ShipMonk\InputMapper\Runtime\Optional
类将类型包装起来。
use ShipMonk\InputMapper\Compiler\Mapper\Optional; class Person { public function __construct( public readonly string $name, public readonly int $age, #[Optional] public readonly ?string $email, /** @var list<string> */ public readonly array $hobbies, /** @var list<self> */ #[Optional(default: [])] public readonly array $friends, ) {} }
默认情况下,不允许任何额外属性。您可以通过在类上添加 #[AllowExtraKeys]
来更改此设置。
映射输入
要映射输入,提供一个可写目录的路径,生成的映射器将存储在该目录中。
在生产中设置 $autoRefresh 为 false 非常重要,以避免在每次请求时重新编译映射器。
$tempDir = sys_get_temp_dir() . '/input-mapper'; $autoRefresh = true; // MUST be set to false in production $mapperProvider = new ShipMonk\InputMapper\Runtime\MapperProvider($tempDir, $autoRefresh); $mapper = $mapperProvider->get(Person::class); try { $person = $mapper->map([ 'name' => 'John', 'age' => 30, 'hobbies' => ['hiking', 'reading'], 'friends' => [ [ 'name' => 'Jane', 'age' => 28, 'hobbies' => ['hiking', 'reading'], ], [ 'name' => 'Jack', 'age' => 28, 'hobbies' => ['hiking', 'reading'], ], ], ]); } catch (\ShipMonk\InputMapper\Runtime\Exception\MappingFailedException $e) { // $e->getMessage() // programmer readable error message in English // $e->getPath() // path of the problematic field for example ['friends', 0, 'name'] // ... }
添加验证规则
您可以通过将属性添加到构造函数参数中来添加验证规则。
例如,为了验证 age
在 18 到 99 之间,您可以将 AssertIntRange
属性添加到构造函数参数中
use ShipMonk\InputMapper\Compiler\Validator\Int\AssertIntRange; class Person { public function __construct( public readonly string $name, #[AssertIntRange(gte: 18, lte: 99)] public readonly int $age, ) {} }
重命名键
如果输入键与属性名称不匹配,您可以使用 #[SourceKey]
属性来指定键名
use ShipMonk\InputMapper\Compiler\Mapper\Object\SourceKey; class Person { public function __construct( #[SourceKey('full_name')] public readonly string $name, ) {} }
解析多态类(具有公共父类的子类型)
如果您需要解析类层次结构,您可以使用 #[Discriminator]
属性。(如果使用 #[AllowExtraKeys]
,则不需要将区分器字段映射到属性。)
use ShipMonk\InputMapper\Compiler\Mapper\Object\Discriminator; #[Discriminator( key: 'type', // key to use for mapping mapping: [ 'car' => Car::class, 'truck' => Truck::class, ] )] abstract class Vehicle { public function __construct( public readonly string $type, ) {} } class Car extends Vehicle { public function __construct( string $type, public readonly string $color, ) { parent::__construct($type); } } class Truck extends Vehicle { public function __construct( string $type, public readonly string $color, ) { parent::__construct($type); } }
或者,使用枚举
use ShipMonk\InputMapper\Compiler\Mapper\Object\Discriminator; enum VehicleType: string { case Car = 'car'; case Truck = 'truck'; } #[Discriminator( key: 'type', // key to use for mapping mapping: [ VehicleType::Car->value => Car::class, VehicleType::Truck->value => Truck::class, ] )] abstract class Vehicle { public function __construct( VehicleType $type, ) {} } class Car extends Vehicle { public function __construct( VehicleType $type, public readonly string $color, ) { parent::__construct($type); } } class Truck extends Vehicle { public function __construct( VehicleType $type, public readonly string $color, ) { parent::__construct($type); } }
使用自定义映射器
要使用自定义映射器映射类,您需要实现ShipMonk\InputMapper\Runtime\Mapper
接口,并将其注册到MapperProvider
class MyCustomMapper implements ShipMonk\InputMapper\Runtime\Mapper { public function map(mixed $data, array $path = []): mixed { return MyCustomClass::createFrom($data); } } $mapperProvider->registerFactory(MyCustomClass::class, function () { return new MyCustomMapper(); });
自定义从类型推断的默认映射器
要自定义从类型推断默认映射器的方式,您需要实现
ShipMonk\InputMapper\Compiler\MapperFactory\MapperCompilerFactory
和
.ShipMonk\InputMapper\Compiler\MapperFactory\MapperCompilerFactoryProvider
然后,将您的工厂提供者注册到MapperProvider
$mapperProvider = new ShipMonk\InputMapper\Runtime\MapperProvider( tempDir: $tempDir, autoRefresh: $autoRefresh, mapperCompilerFactoryProvider: new MyCustomMapperCompilerFactoryProvider(), );
贡献
- 使用
composer check
检查您的代码 - 使用
composer fix:cs
自动修复编码风格 - 所有功能都必须经过测试