Symfony3 десериализовать - PullRequest
       9

Symfony3 десериализовать

0 голосов
/ 12 февраля 2019

У меня есть эта сущность:

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 является идентификатором выбранной опции в комбинации:

{
    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 голосов
/ 12 февраля 2019

Прежде всего, поскольку вы отправляете данные формы на свой контроллер, вы можете использовать классы формы типа, чтобы использовать все возможности компонента формы Symfony, который будет выполнять всю эту работу за вас.

Ответ на ваш конкретный вопрос(и при условии, что вы не можете / не хотите использовать Symfony Form Component), эта ошибка абсолютно ожидаема.Как вы можете видеть в объявлении setCcaa функции внутри Ciudad класса:

public function setCcaa(ComunidadAutonoma $ccaa)

Из-за подсказки типа (ComunidadAutonoma $ccaa) setCcaa функция ожидает аргумент типа ComunidadAutonoma.Теперь, когда сериализатор Symfony пытается денормализовать ваш объект json, он вызывает функцию setCcaa с аргументом, значение ccaa, указанное в вашем json (в вашем примере это 7), которое оказывается целым числом.Поэтому Symfony жалуется, что вы предоставляете целое число вместо ComunidadAutonoma типа.

Чтобы решить эту проблему, вы должны создать и использовать собственный нормализатор , чтобы вы могли преобразовать это целое число всоответствующий объект сущности из вашей базы данных.Примерно так:

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 }

Вы также можете установить приоритет нормализатора, но, поскольку значение приоритета по умолчанию равно 0, когда приоритет встроенных нормализаторов Symfony по умолчанию отрицательный, ваш нормализатор будет использоваться первым.

Вы можете проверить полностью объясненный пример этого в этой прекрасной статье .

0 голосов
/ 12 февраля 2019

Вам не нужно ничего делать, если вы правильно настроили тип.При создании Типа формы для вашей сущности, пожалуйста, добавьте имя класса к вашему типу, например:

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

И, пожалуйста, используйте английские названия для своих проектов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...