anzusystems/serializer-bundle

序列化组件。

安装次数: 6,316

依赖关系: 2

建议者: 1

安全: 0

星标: 0

关注者: 6

分支: 0

开放问题: 2

类型:symfony-bundle

4.0.0 2024-05-13 09:06 UTC

README

一个快速且轻量级的symfony序列化组件。

安装

composer require anzusystems/serializer-bundle

用法

简单通过构造函数注入 AnzuSystems\SerializerBundle\Serializer,然后

// Serialize object or iterable to json:
$this->serializer->serialize($dto);

// Deserialize json into object:
$this->serializer->deserialize($json, SerializerTestDto::class);

// Deserialize json into array of objects:
$this->serializer->deserialize($json, SerializerTestDto::class, []);

// Deserialize json into collection of objects:
$this->serializer->deserialize($json, SerializerTestDto::class, new ArrayCollection());

可以更改 DateTimeInterface 对象的序列化和反序列化默认格式

# config/packages/anzu_systems_serializer.yaml
anzu_systems_serializer:
  date_format: 'Y-m-d\TH:i:s.u\Z'

属性

为了能够(反)序列化对象,该对象的属性(或方法)必须具有 AnzuSystems\SerializerBundle\Attributes\Serialize 属性。

    #[Serialize]
    private string $name;

    #[Serialize]
    private int $position;

    #[Serialize]
    private DummyDto $dummyDto;

    #[Serialize]
    private DateTimeImmutable $createdAt;

    // Custom date format used by `DateTime`. 
    #[Serialize(type: 'd.m.Y H:i:s')]
    private DateTimeImmutable $createdAtCustomFormat;

    // The valueObject must be an instance of `ValueObjectInterface`, to automatically (de)serialize.
    #[Serialize]
    private DummyValueObject $dummyValueObject;
    
    // The enum must be an instance of `EnumInterface`, to automatically (de)serialize.
    #[Serialize]
    private DummyEnum $dummyEnum;
    
    // Must be an instance of Symfony\Component\Uid\Uuid, to automatically (de)serialize.
    #[Serialize]
    private Uuid $docId;

    // Type (or discriminator map see below) must be provided for iterables in order to determine how to deserialize its items.
    #[Serialize(type: DummyDto::class)]
    private Collection $items;

    #[Serialize(type: DummyDto::class)]
    private array $itemsArray;

    // Serialize collection of entities as IDs ordered by position.
    #[Serialize(handler: EntityIdHandler::class, type: Author::class, orderBy: ['position' => Criteria::ASC])]
    protected Collection $authors;

    // Override type for deserialization based on provided "discriminator" field in json.
    #[Serialize(discriminatorMap: ['person' => Person::class, 'machine' => Machine::class])]
    private Collection $items;

    // Provide type via container parameter name. Example yaml config:
    // anzu_systems_serializer:
    //   parameter_bag:
    //     AnzuSystems\Contracts\Entity\AbstractUser: App\Entity\User
    #[Serialize(handler: EntityIdHandler::class, type: new ContainerParam(AbstractUser::class))]
    protected Collection $users;

    // (De)serialize a doctrine entity into/from IDs instead of (de)serializing whole object.
    #[Serialize(handler: EntityIdHandler::class)]
    private User $user;

    // Override the name of this property in json.
    #[Serialize(serializedName: 'stats')]
    private UserStats $decorated;

    // Serialize a virtual property (only serialization).
    #[Serialize]
    public function getViolations(): Collection

内置处理器

  • 基于类型的自动解析处理器
    • BasicHandler(标量值和null)
    • DateTimeHandler(日期格式可通过设置配置)
    • EnumHandler(字符串和 EnumInterface 之间的转换)
    • ObjectHandler(整个对象的转换,即嵌套)
    • UuidHandler(转换Symfony Uuids)
  • 自定义处理器
    • EntityIdHandler(将ID转换为实体及其反转换)
    • ArrayStringHandler(CSV到数组:将 '1,2,3''a, b,c' 转换为 [1, 2, 3]['a', 'b', 'c']

要强制使用特定处理器(覆盖自动解析处理器),只需在 AnzuSerialize 属性中指定处理器即可。

#[Serialize(handler: ArrayStringHandler::class)]
private array $ids;

自定义处理器。

要创建自定义处理器,只需扩展 AnzuSystems\SerializerBundle\Handler\Handlers\AbstractHandler

例如,在以下示例中,Geolocation类被转换为数组

use AnzuSystems\SerializerBundle\Context\SerializationContext;
use AnzuSystems\SerializerBundle\Handler\Handlers\AbstractHandler;

final class GeolocationHandler extends AbstractHandler
{
    /**
     * @param Geolocation $value
     */
    public function serialize(mixed $value, Metadata $metadata, SerializationContext $context): string): array
    {
        return [
            'lat' => $value->getLatitude(),
            'lon' => $value->getLongitude(),
        ];
    }

    /**
     * @param array $value
     */
    public function deserialize(mixed $value, Metadata $metadata): Geolocation
    {
        return new Geolocation(
            (float) $value['lat'],
            (float) $value['lon'],
        );
    }
}

然后只需通过属性强制使用处理器

#[Serialize(handler: GeolocationHandler::class)]
private Geolocation $location;

如果您想始终自动使用之前提到的类型 Geolocation 的所有属性并由 GeolocationHandler 处理(无需通过属性强制),请将以下方法添加到处理器中

    public static function supportsSerialize(mixed $value): bool
    {
        return $value instanceof Geolocation;
    }

    public static function supportsDeserialize(mixed $value, string $type): bool
    {
        return is_a($type, Geolocation::class, true) && is_array($value);
    }

如果您想使用多个自动处理器来同时支持同一项功能,您可以通过设置处理器的优先级来选择处理器。在这种情况下,请添加以下方法(优先级较高的将被首先选择)

public static function getPriority(): int
{
    return 3;
}

默认情况下,所有处理器的优先级都是0。除了:BasicHandler具有最高优先级(10) - 它处理简单的标量值,因此通常您希望它首先出现。ObjectHandler具有最低优先级(-1) - 它处理其他处理器不支持嵌套的可迭代对象/对象。

通过NelmioApiDocBundle自动生成API文档

如果存在NelmioApiDocBundle,则模型描述器将自动注册。Symfony注释也支持并反映在文档中。属性和方法的DocBlock标题也将自动添加为描述。

如果您创建自定义处理器,可以通过添加以下方法到处理器来覆盖生成的描述

use AnzuSystems\SerializerBundle\Metadata\Metadata;
use OpenApi\Annotations\Property;

public function describe(string $property, Metadata $metadata): array
{
    $description = parent::describe($property, $metadata);
    $description['type'] = 'object';
    $description['title'] = 'Geolocation';
    $description['properties'] = [
        new Property([
            'property' => 'lon',
            'title' => 'Longitude',
            'type' => 'float',
            'minimum' => -180,
            'maximum' => 180,
        ]),
        new Property([
            'property' => 'lat',
            'title' => 'Latitude',
            'type' => 'float',
            'minimum' => -90,
            'maximum' => 90,
        ]),
    ];

    return $description;
}

有关受支持的描述配置选项的列表,请查看Property属性。
除此之外,您可能还想添加NESTED_CLASS键来替换描述为整个另一个类的描述

$description[SerializerModelDescriber::NESTED_CLASS] = 'App\Entity\User';

如果您想定义特定对象的数组,那么

$description['items'][SerializerModelDescriber::NESTED_CLASS] = 'App\Entity\User';

最好查看AnzuSystems\SerializerBundle\Handler\Handlers命名空间,以获取其他处理器如何工作的灵感。

注意事项/要求/功能

  • 具有键的迭代将自动(反)序列化为关联数组或索引集合。
  • 目前,仅支持json格式。
  • 您想要(反)序列化的每个属性都必须有一个公共的getter和setter。
    • 属性 $email 的设置器名称示例:setEmail
    • 属性 $email 的获取器名称示例:getEmail
    • 布尔属性的获取器名称示例:isEnabled
  • 您想要序列化(反序列化)的对象的构造函数不能有必需的参数。
    • 如果您需要使用必需的参数来实例化一个对象,也可以使用公共静态函数。例如
public static function getInstance(Post $decorated): self
{
    return (new self())
        ->setDecorated($decorated)
    ;
}
  • 使用 SerializeParam 将请求数据转换为所需的对象。示例
#[Route('/topic', name: 'create', methods: [Request::METHOD_POST])]
public function create(#[SerializeParam] Topic $topic): JsonResponse
{
    return $this->createdResponse(
        $this->topicFacade->create($topic)
    );
}