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

问题描述

我正在尝试将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,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": "*",

解决方法

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