【问题标题】:Deserialize JSON into an array of class instances using Symfony Serializer使用 Symfony Serializer 将 JSON 反序列化为类实例数组
【发布时间】:2020-10-30 11:43:07
【问题描述】:

我正在尝试将 JSON 反序列化为 DTO 类,该类的属性类型为 NestedDto[]。不幸的是,数组中的对象被反序列化为数组,而不是NestedDto 的实例。 我的 DTO 课程如下:

class TestDto
{
    /**
    * @var NestedDto
    */
    public NestedDto $c;

    /**
     * @var NestedDto[] $cs
     */
    public array $cs;
}

class NestedDto
{
    public string $s;
}

编排此用例的代码(我将在问题末尾显示序列化程序的代码):

function main() {
    $serializer = new JsonSerializer();
    $json = '{"c":{"s":"nested"},"cs":[{"s":"nested1"},{"s":"nested2"}]}';
    $dto = $serializer->fromJSON(TestDto::class, $json);
    echo '<pre>' . print_r($dto, true) . '</pre>';
    $response = $serializer->toJSON($dto);
    exit($response);
}

您可以看到属性c 是正确的NestedDto,但在cs 数组中,我们有两个数组而不是两个NestedDto 实例。

TestDto Object
(
    [c] => NestedDto Object
        (
            [s] => nested
        )

    [cs] => Array
        (
            [0] => Array
                (
                    [s] => nested1
                )
            [1] => Array
                (
                    [s] => nested2
                )
        )
)

这是 JsonSerializer 类的代码,它是 Symfony 序列化程序的包装器:

final class JsonSerializer
{

    private Serializer $serializer;
    private ValidatorInterface $validator;

    /**
     * JsonSerializer constructor.
     */
    public function __construct()
    {
        $encoders = [new JsonEncoder()];

        $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
        $normalizers = [
            new ObjectNormalizer($classMetadataFactory, NULL, NULL, new ReflectionExtractor()),
            new ArrayDenormalizer(),
            new DateTimeNormalizer(),
        ];

        $this->serializer = new Serializer($normalizers, $encoders);
        $this->validator = Validation::createValidatorBuilder()->enableAnnotationMapping()->getValidator();
    }

    /**
     * Create a DTO class from json. Will also auto-validate the DTO.
     * @param $classFQN string The class FQN, e.g. \App\Something\CreateQuoteDTO::class
     * @param $json string The string containing JSON we will use for the DTO.
     * @return array|mixed|object An instance of the $class.
     */
    public function fromJSON( string $classFQN, string $json )
    {
        $instance = $this->serializer->deserialize($json, $classFQN, 'json');
        $errors = $this->validator->validate($instance);
        if (count($errors) > 0) {
            throw new \RuntimeException('Invalid DTO.');
        }

        return $instance;
    }

    /**
     * Convert a class instance to JSON string
     * @param $object
     * @return string
     */
    public function toJSON( $object ) : string
    {
        return $this->serializer->serialize($object, 'json');
    }

}

我已阅读有关 Stack Overflow 的所有类似问题,但我找不到我的代码中缺少的内容。我的猜测是 JsonSerializer 中使用的规范化器中的某些东西没有正确连接,但是在花费了大量时间之后,我没有线索了。

这是沙盒中的所有代码,您可以在其中运行它:phpsandbox.io

以防万一,我在本示例中使用 composer 所需的包是:

"symfony/serializer-pack": "*",
"symfony/validator": "*",
"doctrine/annotations": "*",
"doctrine/cache": "*",

【问题讨论】:

  • 您可以尝试使用绑定到PhpDocExtractor 的ObjectNormalizer 吗?
  • 您能否使用共享沙箱链接交叉验证您的问题,因为我已经分叉了您的链接,并且在序列化时,我在 $cs 变量中获得了一组 NestedDto。工作解决方案:phpsandbox.io/n/fragrant-field-wgn5
  • @ChrisHaas 谢谢,感谢您,我已经设法解决了我的问题。一旦我发现我需要寻找 PhpDocExtractor,在网络上找到解决方案就变得非常简单了。再次感谢您。

标签: php symfony serialization json-deserialization


【解决方案1】:

我已经分叉了您的链接,并且在序列化后,我在 $cs 变量中获得了一组 NestedDto。工作解决方案:https://phpsandbox.io/n/fragrant-field-wgn5

【讨论】:

    猜你喜欢
    • 2014-05-27
    • 2021-09-27
    • 2018-08-16
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 2018-09-19
    相关资源
    最近更新 更多