简体   繁体   English

使用 Symfony Serializer 将 JSON 反序列化为类实例数组

[英]Deserialize JSON into an array of class instances using Symfony Serializer

I'm trying to deserialize JSON into a DTO class, which has a property types as NestedDto[] .我正在尝试将 JSON 反序列化为一个 DTO 类,该类的属性类型为NestedDto[] Unfortunately, the objects inside the array are deserialized as arrays, not instances of NestedDto .不幸的是,数组内的对象被反序列化为数组,而不是NestedDto实例。 My DTO classes are like:我的 DTO 课程是这样的:

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

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

class NestedDto
{
    public string $s;
}

The code that orchestrates this use-case (I will show the code for the serializer at the end of the question):编排此用例的代码(我将在问题末尾显示序列化程序的代码):

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);
}

You can see that the property c is a proper NestedDto , but inside the cs array we have two arrays instead of two NestedDto instances.您可以看到属性c是一个适当的NestedDto ,但在cs数组中,我们有两个数组而不是两个NestedDto实例。

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

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

Here is the code for the JsonSerializer class which is a wrapper around the Symfony serializer:这是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');
    }

}

I have read all of the similar questions on Stack Overflow, but I fail to find what is missing in my code.我已经阅读了 Stack Overflow 上的所有类似问题,但我找不到我的代码中缺少什么。 My guess is something isn't wired up correctly in the normalizers used in JsonSerializer, but after spending an inordinate amount of time on this, I'm out of clues.我的猜测是在 JsonSerializer 中使用的规范化器中有些东西没有正确连接,但是在花费过多的时间之后,我失去了线索。

Here's all the code in a sandbox where you can run it: phpsandbox.io这是沙箱中的所有代码,您可以在其中运行它: phpsandbox.io

Just in case, the packages I've required with composer for this example are:以防万一,我在这个例子中需要的 Composer 包是:

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

I have forked your link, and upon serializing I am getting an array of NestedDto in $cs variable.我已经分叉了您的链接,并且在序列化时我在 $cs 变量中获得了一个 NestedDto 数组。 Working Solution: https://phpsandbox.io/n/fragrant-field-wgn5工作解决方案: https : //phpsandbox.io/n/fragrant-field-wgn5

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM