consistence-community / consistence-jms-serializer
Consistence 库与 JMS Serializer 的集成
Requires
- php: ~8.0
- consistence-community/consistence: ^2.1.2
- jms/serializer: ~3.14
Requires (Dev)
- ext-simplexml: *
- consistence-community/coding-standard: 3.11.1
- phing/phing: 2.17.0
- php-parallel-lint/php-parallel-lint: 1.3.1
- phpunit/phpunit: 9.5.10
Conflicts
- doctrine/annotations: <1.11
Replaces
README
此包是 consistence/consistence-jms-serializer
的分支,由社区维护,以支持新的 PHP 版本。
此库提供了 Consistence 值对象与 JMS Serializer 的集成,以便您可以在序列化映射中使用它们。
目前,所需的唯一集成是 枚举(Enums),以下是一些示例。
使用方法
枚举(Enums)代表一组预定义的值,当然,您也希望对这些值进行序列化和反序列化。由于 枚举(Enums)
是对象,并且您只想(反)序列化表示的值,因此必须有一些映射。
您可以在以下示例中看到,您想要(反)序列化 User
对象中的性别。
<?php namespace Consistence\JmsSerializer\Example\User; class Sex extends \Consistence\Enum\Enum { public const FEMALE = 'female'; public const MALE = 'male'; }
现在您可以在 User
对象中使用 Sex
枚举。类型指定为 enum<Your\Enum\Class>
<?php namespace Consistence\JmsSerializer\Example\User; use JMS\Serializer\Annotation as JMS; class User extends \Consistence\ObjectPrototype { // ... /** * @JMS\Type("enum<Consistence\JmsSerializer\Example\User\Sex>") * @var \Consistence\JmsSerializer\Example\User\Sex|null */ private $sex; // ... public function __construct( // ... Sex $sex = null // ... ) { // ... $this->sex = $sex; // ... } }
现在一切准备就绪,当您序列化对象时,只有 female
将作为枚举的值返回
<?php namespace Consistence\JmsSerializer\Example\User; /** @var \JMS\Serializer\Serializer $serializer */ $user = new User(Sex::get(Sex::FEMALE)); var_dump($serializer->serialize($user, 'json')); /* { "sex": "female" } */
当您反序列化对象时,您将再次收到 Sex
枚举对象
<?php namespace Consistence\JmsSerializer\Example\User; /** @var \JMS\Serializer\Serializer $serializer */ var_dump($serializer->deserialize('{ "sex": "female" }', User::class, 'json')); /* class Consistence\JmsSerializer\Example\User\User#46 (1) { private $sex => class Consistence\JmsSerializer\Example\User\Sex#5 (1) { private $value => string(6) "female" } } */
这意味着对象的 API 是对称的(您得到与您设置相同类型),您可以开始从枚举的优势中受益,例如确保您得到的是一个有效的值,并且可以在表示的值之上定义方法。
默认为可空
序列化和反序列化都将接受 null
值,没有特殊的映射(按照 Jms Serializer
的约定),因此如果您期望非空值,您必须通过其他方式强制执行此操作 - 要么通过限制对象 API,要么通过验证(尤其是在反序列化时)。
无效值
在序列化时,不应该存在无效值,因为 枚举(Enums) 保证实例中只包含有效值。
在反序列化时,可能给出一个无效值,将抛出异常
<?php namespace Consistence\JmsSerializer\Example\User; /** @var \JMS\Serializer\Serializer $serializer */ var_dump($serializer->deserialize('{ "sex": "FOO" }', User::class, 'json')); // \Consistence\Enum\InvalidEnumValueException: FOO [string] is not a valid value, accepted values: female, male
如果您在 API 中使用此功能,请确保您将捕获此异常并向消费者发送详细说明此错误的响应,您也可以编写自定义消息,可用的值列在 InvalidEnumValueException::getAvailableValues()
中。
XML 支持
与 JSON 不同,在 XML 中无法直接从值推断值类型。因此,如果您需要反序列化 XML,您必须手动提供此类型。您可以通过在类型定义中写入类型来完成此操作 - 对于上面的示例,它将是 string
<?php namespace Consistence\JmsSerializer\Example\User; use JMS\Serializer\Annotation as JMS; class User extends \Consistence\ObjectPrototype { // ... /** * @JMS\Type("enum<Consistence\JmsSerializer\Example\User\Sex, string>") * @var \Consistence\JmsSerializer\Example\User\Sex|null */ private $sex; // ... }
对映射的 MultiEnums 的特殊支持
由于反序列化操作只与枚举所表示的值相关,因此在多枚举的情况下,这意味着输出内部位掩码的值。如果客户端和服务器使用相同的枚举对象,这可能很有用,否则这会破坏抽象,并且对于人类消费者来说可读性也更差。
如果您使用的是映射到单个枚举的多枚举,提供了一个方便的解决方案,如果您在映射中添加了enum<Your\Enum\Class, as_single>
- 注意新的as_single
参数,那么MultiEnum
的值将序列化为单个Enum
值的集合
<?php namespace Consistence\JmsSerializer\Example\User; use Consistence\Type\ArrayType\ArrayType; use JMS\Serializer\Annotation as JMS; class RoleEnum extends \Consistence\Enum\Enum { public const USER = 'user'; public const EMPLOYEE = 'employee'; public const ADMIN = 'admin'; } class RolesEnum extends \Consistence\Enum\MultiEnum { /** @var int[] format: single Enum value (string) => MultiEnum value (int) */ private static $singleMultiMap = [ RoleEnum::USER => 1, RoleEnum::EMPLOYEE => 2, RoleEnum::ADMIN => 4, ]; public static function getSingleEnumClass(): string { return RoleEnum::class; } /** * Converts value representing a value from single Enum to MultiEnum counterpart * * @param string $singleEnumValue * @return int */ protected static function convertSingleEnumValueToValue($singleEnumValue): int { return ArrayType::getValue(self::$singleMultiMap, $singleEnumValue); } /** * Converts value representing a value from MultiEnum to single Enum counterpart * * @param int $value * @return string */ protected static function convertValueToSingleEnumValue(int $value): string { return ArrayType::getKey(self::$singleMultiMap, $value); } } class User extends \Consistence\ObjectPrototype { // ... /** * @JMS\Type("enum<Consistence\JmsSerializer\Example\User\RolesEnum, as_single>") * @var \Consistence\JmsSerializer\Example\User\RolesEnum */ private $roles; // ... public function __construct( // ... RolesEnum $roles // ... ) { // ... $this->roles = $roles; // ... } } $user = new User(RolesEnum::getMultiByEnums([ RoleEnum::get(RoleEnum::USER), RoleEnum::get(RoleEnum::ADMIN), ])); /** @var \JMS\Serializer\Serializer $serializer */ var_dump($serializer->serialize($user, 'json')); /* { "roles": [ "user", "admin" ] } */
反序列化同样也是对称的 - 提供单个Enum
值的数组将生成一个MultiEnum
实例
<?php namespace Consistence\JmsSerializer\Example\User; /** @var \JMS\Serializer\Serializer $serializer */ var_dump($serializer->deserialize('{ "roles": [ "user", "admin" ] }', User::class, 'json')); /* class Consistence\JmsSerializer\Example\User\User#48 (1) { private $roles => class Consistence\JmsSerializer\Example\User\RolesEnum#37 (1) { private $value => int(5) } } */
安装
composer require consistence-community/consistence-jms-serializer
- 注册序列化处理器
<?php use Consistence\JmsSerializer\Enum\EnumSerializerHandler; use JMS\Serializer\Handler\HandlerRegistry; use JMS\Serializer\SerializerBuilder; $serializer = SerializerBuilder::create() ->configureHandlers(function (HandlerRegistry $registry) { $registry->registerSubscribingHandler(new EnumSerializerHandler()); }) ->build();
如果您使用的是Symfony,您可以在config/services.yaml
文件中注册处理器
services: Consistence\JmsSerializer\Enum\EnumSerializerHandler: tags: - { name: jms_serializer.subscribing_handler }
到此为止,您就可以开始使用了!