symfony 反序列化嵌套对象

wyl*_*jon 3 serialization deserialization symfony-3.4

我使用了 Symfony 序列化器来序列化我的Recherche对象。在一个Recherche对象中,我有子对象 :CategorieLieu

当我反序列化我的Recherche对象时,所有子对象都被转换成数组。我希望它们再次成为对象。

这就是我序列化对象的方式:

$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getCode();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
$rechercheJson= $serializer->serialize($recherche, 'json');
Run Code Online (Sandbox Code Playgroud)

这就是我反序列化它的方式:

$encoders = array(new JsonEncoder());
$normalizer = new ObjectNormalizer();
$normalizer->setIgnoredAttributes(array('parent', 'enfants'));
$normalizer->setCircularReferenceHandler(function ($object) {
    return $object->getCode();
});
$normalizers = array($normalizer);
$serializer = new Serializer($normalizers, $encoders);
$recherche = $serializer->deserialize($recherche_json, Recherche::class, 'json');
Run Code Online (Sandbox Code Playgroud)

我认为可能与规范化器有关,但我在文档中找不到任何对我有帮助的内容。

任何人都有帮助的想法?

谢谢 !

编辑:看到这篇文章后:使用 symfony 2 序列化程序对对象中的嵌套结构进行非规范化

我试过这个:

$encoders = array(new JsonEncoder());
            $normalizer = new ObjectNormalizer(null, null, null, new SerializationPropertyTypeExtractor());
            $normalizer->setIgnoredAttributes(array('parent', 'enfants'));
            $normalizer->setCircularReferenceHandler(function ($object) {
                return $object->getCode();
            });
            $normalizers = array($normalizer,  new ArrayDenormalizer());
            $serializer = new Serializer($normalizers, $encoders);
            $recherche = $serializer->deserialize($recherche_json, Recherche::class, 'json');
Run Code Online (Sandbox Code Playgroud)

和 SerializationPropertyTypeExtractor:

class SerializationPropertyTypeExtractor implements PropertyTypeExtractorInterface {
    /**
     * {@inheritdoc}
     */
    public function getTypes($class, $property, array $context = array())
    {
        if (!is_a($class, Recherche::class, true)) {
            return null;
        }

        if ('make' !== $property) {
            return null;
        }

        if ('lieu' === $property)
        {
            return [new Type(Type::BUILTIN_TYPE_OBJECT, true, LieuRecherche::class)];
        }
        if ('categorie' === $property)
        {
            return [new Type(Type::BUILTIN_TYPE_OBJECT, true, Categorie::class)];
        }

        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

这很好用!

Loc*_*Ngu 6

我遇到了类似的问题,并尝试使用自定义 PropertyTypeExtractor 解决该问题。由于我有许多带有嵌套对象的实体,这感觉很麻烦,而且当嵌套对象再次嵌套对象时它也不起作用。

我使用 PhpDocExtractor 和 ReflectionExtractor 找到了一个更好的解决方案,它为您提取属性信息。

$encoder = [new JsonEncoder()];
$extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
$normalizer = [new ArrayDenormalizer(), new ObjectNormalizer(null, null, null, $extractor)];
$serializer = new Serializer($normalizer, $encoder);
$result = $serializer->deserialize($data,someEntity::class,'json');
Run Code Online (Sandbox Code Playgroud)

这为我完成了所有工作。我希望这会帮助某人。


Edw*_*ard 0

参考:我的评论。我知道您正在以经典方式使用序列化器,但我建议您应用推荐的策略模式,这样您就可以完全控制组件并可以轻松扩展。

因此,我们的想法是为规范化和非规范化创建单独的类,如下所示:

./src/反规范化器

<?php

declare(strict_types=1);

namespace App\Denormalizer;

use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Class ConfigDenormalizer
 * @package App\Denormalizer
 */
class ConfigDenormalizer implements DenormalizerInterface
{

    /**
     * @param mixed $data
     * @param string $class
     * @param null $format
     * @param array $context
     * @return array
     */
    public function denormalize($data = [], $class, $format = null, array $context = array())
    {
        $result = [];
        foreach($data as $key => $config) {
            $result[ $config['attribute'] ] = $config['valorem'];
        }
        return $result;
    }

    /**
     * @param mixed $data
     * @param string $type
     * @param null $format
     * @return bool
     */
    public function supportsDenormalization($data, $type, $format = null)
    {
        return $type === self::class;
    }
}
Run Code Online (Sandbox Code Playgroud)

./src/标准化器

<?php

declare(strict_types=1);

namespace App\Normalizer;

use Symfony\Component\Form\Form;
use Symfony\Component\Serializer\Exception\CircularReferenceException;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
use Symfony\Component\Serializer\Exception\LogicException;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;

/**
 * Class WidgetConfigNormalizer
 * @package App\Normalizer
 */
class WidgetAttributeNormalizer implements NormalizerInterface
{
    /**
     * @param object $form
     * @param null $format
     * @param array $context
     * @return array
     */
    public function normalize($form, $format = null, array $context = array()): array
    {
        $result = [];

        foreach($form->getData() as $key => $value) {
            $result[] = [
                'attribute' => (string) $key,
                'valorem' => (string) $value,
            ];
        }

        return $result;
    }

    /**
     * @param mixed $form
     * @param null $format
     * @return bool
     */
    public function supportsNormalization($form, $format = null)
    {
        if($form instanceof Form) {
            return $form->getName() === 'widgetAttribute';
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

你会这样称呼它:

//denormalize
$this->denormalizer->denormalize(
    json_decode($response->getContent(), true),
    ConfigDenormalizer::class
);

//normalize
$form = $this->formFactory->create(myConfigFormType::class);
$form->submit($data);
$this->normalizer->normalize($form);
Run Code Online (Sandbox Code Playgroud)

或者,如果您想使用序列化器(请注意,我们不需要 json_decode):

//deserialize
$array = $this->serializer->deserialize(
    $response->getContent(),
    ConfigDenormalizer::class,
    'json'
);

//serialize
$json = $this->serialize->serialize($form, 'json');
Run Code Online (Sandbox Code Playgroud)

当然,在反规范化器中,您可以将数组转换为普通的旧 php 对象(实体)。或者只是输出一个数组,选择权在你。

这样你所要做的就是将 SerializerInterface 注入到你的控制器中,如下所示:

use Symfony\Component\Serializer\SerializerInterface;

class EmbedController extends Controller
{
    /**
    * @var SerializerInterface
    */
    private $serializer;

    public function __construct(SerializerInterface $serializer)
    {
        $this->serializer = $serializer;
    }

}
Run Code Online (Sandbox Code Playgroud)

这种方法也使单元测试变得更加容易,因为一切都是解耦的,因此可以进行模拟。:)

它还值得检查文档: https ://symfony.com/doc/current/components/serializer.html

尤其是顶部的图像,它可以很好地提示您应该如何使用每个类。

希望这可以帮助。