makinacorpus/generated-hydrator-bundle

为 Symfony 提供ocramius/generated-hydrator的集成

2.0.3 2023-05-23 09:49 UTC

README

集成 ocramius/generated-hydrator 库与 Symfony。

它还带来了一些新功能

  • 嵌套 hydrator,从 PHP 属性类型将 hydration 传递到对象图中。

  • 值 hydrator,对于每个 PHP 类型,您可以插入自己的全局 hydrator 实现来处理自定义类型。

  • 下一个计划的功能将是使用属性进行对象配置。

安装

首先安装依赖项

composer require makinacorpus/generated-hydrator-bundle

然后将它添加到您的 config/bundles.php 文件中

<?php

return [
    // ...
    \GeneratedHydrator\Bridge\Symfony\GeneratedHydratorBundle::class => ['all' => true],
];

配置

更改生成的 PHP 文件位置

默认配置将尝试将生成的 hydrator 代码写入到 %kernel.project_dir%/hydrator 文件夹。为此,您可能需要在您的 composer.json 文件中添加以下内容

{
    "autoload": {
        "classmap": [
            "hydrator"
        ]
    }
}

您可以通过添加以下 config/packages/generated-hydrator.yaml 文件来更改目标

generated_hydrator:
    target_directory: "%kernel.project_dir%/hydrator"

禁止从 hydration 中加载类

在某些时候,当 hydrator 尝试例如 hydration PHP 核心类时,您可能会遇到错误。为了避免这种情况,您可以使用以下配置完全禁用任何 PHP 类的 hydration 尝试

generated_hydrator:
    class_blacklist:
        - App\SomeClass
        - DateTime
        - DateTimeImmutable
        - DateTimeInterface
        - Ramsey\Uuid\Uuid
        - Ramsey\Uuid\UuidInterface
        # ...

这将防止嵌套对象 hydrator 对这些类的 hydration 尝试。

为生产预先生成类 hydrator

您可以设置一个需要预先生成 hydrator 的类的列表

generated_hydrator:
    class_list:
        - App\Entity\Foo
        - App\Entity\Bar
        # ...

这将允许 generated-hydrator:generate 命令预先生成所有 hydrator。

自动装配

您可以使用 GeneratedHydrator\Bridge\Symfony\HydratorAware 接口并在服务上设置它,这将使此捆绑包为您自动配置服务注入。

如果您不想自己实现 setObjectHydrator() 方法,您也可以使用 GeneratedHydrator\Bridge\Symfony\HydratorAwareTrait

使用方法

基本使用

注入 generated_hydrator 服务,或使用 GeneratedHydrator\Bridge\Symfony\Hydrator 进行类型提示来自动装配。

为了 hydration 一个对象

use App\Domain\Model\SomeEntity;
use GeneratedHydrator\Bridge\Symfony\Hydrator;

function some_function(Hydrator $hydrator)
{
    $object = $hydrator->createAndHydrate(
        SomeEntity::class,
        [
            // Scalar values
            'foo' => 1,
            // ...

            // It also handles nested objects
            'bar' => [
                'baz' => 2,
                // ...
            ],
        ]
    );
}

或提取其值

use App\Domain\Model\SomeEntity;
use GeneratedHydrator\Bridge\Symfony\Hydrator;

function some_function(Hydrator $hydrator)
{
    $object = new SomeEntity();

    $valueArray = $hydrator->extract($object);
}

值 hydrator

让我们假设您有以下类

namespace App\Entity;

interface Identifier
{
    public function __construct(mixed $value);

    public function __toString(): string;
}

class FooId
{
    public function __construct(
        private mixed $value,
    ) {}

    public function __toString(): string
    {
        return (string) $this->id;
    }
}

并将其用作以下实体类的标识符类

namespace App\Entity;

class Foo
{
    public function __construct(
        private FooId $id,
    ) {}

    // ...
}

如果您需要使用以下数据库中的数据 hydration 一些 Foo 实例

$foo = $hydrator->createAndHydrate(
    \App\Entity\Foo::class,
    [
        'id' => '12345',
    ],
);

这将失败,因为 $id 参数不能接受一个 string 值。

如果您在网站上到处都使用相同的模式,您可能希望使用全局值 hydrator,如下所示

namespace App\ValueHydrator;

use App\Entity\Identifier;
use GeneratedHydrator\Bridge\Symfony\Error\CannotHydrateValueError;
use GeneratedHydrator\Bridge\Symfony\ValueHydrator\ValueHydrator;

class IdentifierValueHydrator implements ValueHydrator
{
    /**
     * {@inheritdoc}
     */
    public function supports(string $phpType): bool
    {
        return \is_subclass_of($phpType, Identifier::class);
    }

    /**
     * {@inheritdoc}
     */
    public function hydrate(string $phpType, mixed $value): mixed
    {
        if (\is_subclass_of($phpType, Identifier::class)) {
            return new $phpType($value);
        }
        throw new CannotHydrateValueError();
    }
}

您可以通过显式设置 generated_hydrator.value_hydrator 服务标签,或将它添加到容器中,通过将 autowiringautoconfiguration 设置为 true 在此服务上来实现注册

services:
    App\ValueHydrator\IdentifierValueHydrator:
        autowire: true
        autoconfigure: true

一旦设置,每个需要 hydration 实现您的 App\Entity\Identifier 接口的属性值都将自动正确实例化。

一些注意事项

为了使嵌套 hydrator 能够工作,它需要能够使用反射对您的类进行元编程,以找到属性类型。

如果由于某种原因元编程失败,您可以显式安装 symfony/property-access 组件,它可能找到一些此 API 使用反射无法找到的类型。

路线图

达到 alpha 版本(强制)

  • 实现类黑名单,一些类如 \DateTime\Ramsey\Uuid\ 应被视为终端类型,并在业务层中进行归一化处理。
  • 当类生成时自动加载类,
  • 自动注册生成 hydrator 类的回退自动加载器,没有这个,缓存目录中生成的类将不可自动加载。

工业化(1.0)

  • 允许 API 用户无需显式使用嵌套实现即可使用 hydrator,可能使用特定的接口和特定的服务标识符,
  • 嵌套 hydrator 是一种权宜之计,它不应是默认设置,
  • 为用户编写高级配置,
  • 编写更多测试,大量测试。

远在天边

  • 处理嵌套提取/填充中的集合,
  • 添加一个选项,即使类已加载,也禁用属性信息的使用,
  • 为了替换我们的自定义解析器,移除 PHP docblock 解析器,为此,我们需要能够解析相对类命名空间。