Symfony3反序列化

时间:2019-02-12 10:06:28

标签: symfony symfony-3.4

我有这个实体:

AppBundle\Entity\Ciudad

class Ciudad{
    ...
    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\ComunidadAutonoma")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="id_ccaa", referencedColumnName="id")
     * })
     */
    private $ccaa;
    ....

    public function getCcaa()
    {
        return $this->ccaa;
    }

    public function setCcaa(ComunidadAutonoma $ccaa)
    {
        $this->ccaa = $ccaa;
    }
}

另一个实体是:

AppBundle\Entity\ComunidadAutonoma

class ComunidadAutonoma{
    properties
    getters
    setters
}

在控制器中,我从表单中获取数据,并试图将数据反序列化为Ciudad实体,但始终使我遇到相同的错误:

Expected argument of type "AppBundle\Entity\ComunidadAutonoma", "integer" given

enter image description here

在我发送给控制器中动作的表单数据中,comunidadautonoma的值是组合中所选选项的ID:

{
    parameters...
    ccaa:7,
    parameters...
}

在我的控制器中,我有这个:

<?php
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use AppBundle\Entity\Ciudad;

class CiudadController extends Controller
{
    public function procesarAction(Request $request)
    {
        $encoders = array(new XmlEncoder(), new JsonEncoder());
        $normalizers = array(new ObjectNormalizer());
        $this->serializer = new Serializer($normalizers, $encoders);

        $ciudad= $this->serializer->deserialize($parametros['parametros'], Ciudad::class, 'json');
    }
}

我缺少什么吗?我需要任何特殊的配置来反序列化具有关系的实体吗?

2 个答案:

答案 0 :(得分:0)

如果正确配置了类型,则无需执行任何操作。为您的实体创建表单类型时,请将类名添加到您的类型中,例如:

public function configureOptions(OptionsResolver $resolver)
{
    $resolver->setDefaults([
        'data_class' => Ciudad::class,
    ]);
}

请在项目中使用英文命名。

答案 1 :(得分:0)

首先,由于您要向控制器发送表单数据,因此可以使用“表单类型”类来利用Symfony表单组件的全部功能来为您完成所有工作。

回答您的特定问题(并假设您不能/不希望使用Symfony Form Component),绝对会出现此错误。正如您在setCcaa类中的Ciudad函数声明中所看到的:

public function setCcaa(ComunidadAutonoma $ccaa)

由于类型提示(ComunidadAutonoma $ccaasetCcaa函数需要类型为ComunidadAutonoma的参数。现在,当Symfony序列化程序尝试对您的json对象进行非规范化时,它将使用参数json中提供的ccaa值(在您的示例中为7)调用setCcaa函数,该值恰好是整数。因此,Symfony抱怨您提供的是整数而不是ComunidadAutonoma类型。

为了解决此问题,您必须创建并使用自己的normalizer,以便可以将此整数转换为数据库中的相应实体对象。像这样:

class EntityNormalizer extends ObjectNormalizer
{
    /**
     * Entity manager
     * @var EntityManagerInterface
     */
    protected $em;

    public function __construct(
        EntityManagerInterface $em,
        ?ClassMetadataFactoryInterface $classMetadataFactory = null,
        ?NameConverterInterface $nameConverter = null,
        ?PropertyAccessorInterface $propertyAccessor = null,
        ?PropertyTypeExtractorInterface $propertyTypeExtractor = null
    ) {
        parent::__construct($classMetadataFactory, $nameConverter, $propertyAccessor, $propertyTypeExtractor);
        // Entity manager
        $this->em = $em;
    }


    public function supportsDenormalization($data, $type, $format = null)
    {
        return strpos($type, 'App\\Entity\\') === 0 && (is_numeric($data) || is_string($data));
    }

    public function denormalize($data, $class, $format = null, array $context = [])
    {
        return $this->em->find($class, $data);
    }
}

此规范化器的作用是检查您的数据类型(在本例中为$ ccaa)是否为实体类型,并且所提供的数据值(在本例中为7)是否为整数,则将该整数转换为相应的整数。数据库中的实体对象(如果存在)。

要使此规范化器正常工作,您还应该在services.yaml配置中注册它,并使用适当的标签,如下所示:

services:
    App\Normalizer\EntityNormalizer:
        public: false
        autowire: true
        autoconfigure: true
        tags:
            - { name: serializer.normalizer }

您还可以设置规范化器的优先级,但是由于当Symfony的内置规范化器的优先级默认为负时,默认优先级值等于0,因此将首先使用规范化器。

您可以在article中查看有关此问题的完整说明示例。