diezz / yaml-to-object-mapper
Yaml到对象映射器
Requires
- php: >=8
- symfony/yaml: ^6.0
Requires (Dev)
- phpunit/phpunit: ^9.5
README
Yaml到对象映射器
架起YAML与PHP对象之间的桥梁
利用Yaml到对象映射器库,轻松将您的YAML配置转换为强大的PHP对象。通过高效映射、强大的验证和灵活的变量处理,同时利用PHP 8属性的便利性,提升开发体验。
主要功能
- 无缝映射:轻松将分层YAML数据映射到深层嵌套的PHP对象,节省您繁琐的手动配置。
- 全面验证:通过内置的验证机制,如#[Required]属性、类型提示和自定义规则,确保数据完整性。
- 声明式DSL:自定义字段和验证的属性配置,减少样板代码,提高可读性。
- 变量处理:在YAML文件中直接使用动态变量,如${env:DB_PASSWORD},简化配置管理。
- 自定义参数解析器:通过为变量创建自定义逻辑,获得最大的灵活性,以满足您的特定需求。
- 内置变量:享受一系列预定义变量,如now、self和format,以简化YAML配置中的常见任务。
- PHP 8集成:利用PHP 8属性的力量,编写更干净、更简洁的代码,提升您的开发体验。
安装
composer require diezz/yaml-to-object-mapper
基本用法
我们有一个简单的config.yml
文件
name: object mapper connection: host: localhost port: 3202 username: test password: password
我们希望将其映射到类的对象中
class Config { public string $name; public ConnectionSettings $connection } class ConnectionSettings { public string $host; public string $port; public string $username; public string $password; } $config = Mapper::make()->mapFromFile(Config::class, 'config.yml');
在目标类属性中设置值
在目标类属性中设置值 映射器会自动将映射的值分配给目标类中相应的属性。以下是需要注意的几点
属性访问
- 公共属性:直接赋值以实现无缝更新。
- 非公共属性:需要相应的setter方法。
setter命名
- 默认方法:使用与属性名称相同的setter前缀命名(例如,setName用于name属性)。
- 自定义命名:使用属性上的
#[Setter('yourSetterName')]
属性覆盖默认值(例如,#[Setter('updateName')]
)。
扩展用法
使用默认值解析器动态字段映射
厌倦了在YAML中编写冗余的属性名称和嵌套列表?默认值解析器可以自动推断字段名称和结构,简化配置。
示例
而不是这个冗长的YAML
tables: - name: users columns: username: varchar(255) email: varchar(255) password: varchar(255) - name: orders columns: id: int user_id: int price: float
use Diezz\YamlToObjectMapper\Attributes\Collection; class DatabaseSchema { #[Collection(class: Table::class)] public array $tables; } class Table { public string $name; public array $columns; }
想象一下这个简洁性
tables: users: username: varchar(255) email: varchar(255) password: varchar(255) orders: id: int user_id: int price: float
class Table { #[DefaultValueResolver(resolver: DefaultValueResolver::PARENT_KEY)] public string $name; #[DefaultValueResolver(resolver: DefaultValueResolver::NESTED_LIST)] public array $columns; }
工作原理
[DefaultValueResolver(resolver: DefaultValueResolver::PARENT_KEY)]
:自动将每个表对象的name字段设置为YAML列表中的键。[DefaultValueResolver(resolver: DefaultValueResolver::NESTED_LIST)]
:将每个YAML列表项视为对象的属性,并根据键创建关联数组。
验证
默认情况下,映射器会检查yml文件中是否存在必需的字段。有多种方式定义映射器如何定义哪个字段是必需的
- 最明显的方式是使用
#[Required]
属性标记必需字段。 - 如果类字段没有标记为必需属性,映射器会检查字段的类型提示。它可以是PHP 7类型提示或PHPdoc注释。可空属性或具有默认值的属性被视为非必需的或反之亦然。
使用库集成的验证机制,保持您配置的一致性和准确性。它提供了一种灵活的方法来定义必填字段和强制数据类型。
工作原理
- 使用
#[Required]
显式标记:使用#[Required]
属性清楚地指明必填字段。这提供了对验证预期的最直接控制。 - 类型提示和文档注释
- PHP 7 类型提示:具有显式类型提示的字段(例如,public string $name)被视为必填项。
- 文档注释:在其文档注释中具有类型提示的字段(例如,
@var string
)也被视为必填项。
- 默认值和可为空类型
- 具有默认值的字段:在其声明中分配了默认值的字段不是必填的,因为它们有一个回退值。
- 可为空类型:可为空的字段(在类型声明中使用问号或 |null)不是必填的,因为它们可以接受 null 作为有效值。
use Diezz\YamlToObjectMapper\Attributes\Required; class Model { /** * Explicitly required field */ #[Required] public $value0; /** * Required due to string type hint */ public string $value1; /** * Required based on type hint in doc comment * * @var string */ public $value2; /** * Not required due to default value */ public string $value3 = 'value3'; /** * Not required due to nullable type hint */ public ?string $value4; /** * Not required due to nullable type hint in doc comment * * @var string|null */ public $value5; }
使用变量处理进行动态配置
利用动态变量处理,充分释放您的 YAML 配置的潜力。库支持各种内置变量,甚至允许您为高级场景创建自定义逻辑。
内置变量
self
- 访问同一配置对象内的值,启用自引用和跨属性依赖。${self::connection.host}
substring
- 提取字符串的一部分,提供字符串操作功能${substring:${self:name}:7}
now
- 获取当前日期和时间,启用动态时间戳和时间相关的配置${now}
format
- 根据指定的模式格式化日期和时间,确保一致的日期/时间表示。${format:${now}:Y-M-D}
env
- 读取环境变量,安全地将配置与特定环境设置集成${env:DB_PASSWORD}
语法
${varName:firstArgument:secondArgument}
另一个变量可以作为另一个变量的参数传递,例如
${varName1:${varName2:argument1}:argument2}
自定义参数解析器
为了获得更大的灵活性,创建自定义参数解析器以处理独特的变量处理需求。
步骤
- 创建自定义解析器类:扩展 CustomArgumentResolver 类并实现 doResolve 方法来定义变量的逻辑。
- 注册解析器:使用 Mapper::registerCustomArgumentResolver 方法将解析器与变量名关联。
- 在 YAML 中使用变量:在您的 YAML 配置中使用已注册的变量,按需传递参数。
在变量处理顶部有一个 ArgumentResolver。您可以创建自己的 ArgumentResolvers,这为您提供了在 yaml 文件中处理自定义变量的能力。要这样做,创建一个扩展 CustomArgumentResolver
的类。CustomArgumentResolver 实现的构造函数应接受 ArgumentResolver
,它是变量的参数解析器。构造函数中参数的数量应等于变量支持的参数数量。
class SumArgumentResolver extends CustomArgumentResolver { private array $arguments; public function __construct(...$arguments) { $this->arguments = $arguments; } protected function doResolve($context = null): int { $sum = 0; foreach ($this->arguments as $iValue) { $sum += $iValue->resolve($context); } return $sum; } } $mapper = Mapper::make(); //Register the resolver $mapper->registerCustomArgumentResolver('sum', SumArgumentResolver::class); $result = $mapper->map($file, Output::class);
现在您可以在 yaml 文件中使用它,例如
price: item1: 100 item2: 200 total: ${sum:${self:price.item1}:${self:price.item2}}