JMSSerializer 按 id 反序列化实体 [英] JMSSerializer deserialize entity by id

查看:26
本文介绍了JMSSerializer 按 id 反序列化实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 JMSSerializer 来反序列化一个 JSON 请求,但我遇到了多对一关系的问题.我想从给定的 id 反序列化关系实体.示例:

i'm using JMSSerializer to deserialize a JSON request and i'm having troubles with ManyToOne relations. I would like to deserialize the relation entity from a id given. Example:

Class Game {


/**
 * @var Team
 *
 * @ORM\ManyToOne(targetEntity="Team")
 * @ORM\JoinColumn(name="home_team_id", referencedColumnName="id")
 * @JMSSerializer\SerializedName("home")
 */
private $homeTeam;

/**
 * @ORM\ManyToOne(targetEntity="Team")
 * @ORM\JoinColumn(name="visitor_team_id", referencedColumnName="id")
 * @JMSSerializer\SerializedName("visitor")
 */
private $visitorTeam;
}

所以当我得到这个 Json

So when i get this Json

{"home": "id1", "visitor": "id2"}

{"home": "id1", "visitor": "id2"}

获取相关实体.有云吗??我想不通

Get the related entities. Any clouds?? i can't figure it out

提前致谢

推荐答案

自定义 serializer handler 允许这样做.

Custom serializer handler allows to do it.

首先,您需要创建自己的序列化处理程序.像这样:

At first, you need to create your own serialization handler. Something like this:

<?php

namespace AppBundle\Serializer\Handler;

use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\RegistryInterface;
use JMS\Serializer\Context;
use JMS\Serializer\Exception\InvalidArgumentException;
use JMS\Serializer\GenericDeserializationVisitor;
use JMS\Serializer\Handler\SubscribingHandlerInterface;
use JMS\Serializer\VisitorInterface;
use JMS\Serializer\GraphNavigator;

class EntityHandler implements SubscribingHandlerInterface
{
    /**
     * @var RegistryInterface
     */
    protected $registry;

    /**
     * @return array
     */
    public static function getSubscribingMethods()
    {
        $methods = [];

        foreach (['json', 'xml', 'yml'] as $format) {
            $methods[] = [
                'type' => 'Entity',
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                'format' => $format,
                'method' => 'deserializeEntity',
            ];

            $methods[] = [
                'type' => 'Entity',
                'format' => $format,
                'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                'method' => 'serializeEntity',
            ];
        }

        return $methods;
    }

    /**
     * EntityHandler constructor.
     * @param RegistryInterface $registry
     */
    public function __construct(RegistryInterface $registry)
    {
        $this->registry = $registry;
    }

    /**
     * @param VisitorInterface $visitor
     * @param $entity
     * @param array $type
     * @param Context $context
     * @return mixed
     */
    public function serializeEntity(VisitorInterface $visitor, $entity, array $type, Context $context)
    {
        $entityClass = $this->getEntityClassFromParameters($type['params']);
        if (!$entity instanceof  $entityClass) {
            throw new InvalidArgumentException(
                sprintf("Entity class '%s' was expected, but '%s' got", $entityClass, get_class($entity))
            );
        }

        $entityManager = $this->getEntityManager($entityClass);
        $primaryKeyValues = $entityManager->getClassMetadata($entityClass)->getIdentifierValues($entity);
        if (count($primaryKeyValues) > 1) {
            throw new InvalidArgumentException(
                sprintf("Composite primary keys does'nt supported now (found in class '%s')", $entityClass)
            );
        }
        if (!count($primaryKeyValues)) {
            throw new InvalidArgumentException(
                sprintf("No primary keys found for entity '%s')", $entityClass)
            );
        }

        $id = array_shift($primaryKeyValues);
        if (is_int($id) || is_string($id)) {
            return $visitor->visitString($id, $type, $context);
        } else {
            throw new InvalidArgumentException(
                sprintf(
                    "Invalid primary key type for entity '%s' (only integer or string are supported",
                    $entityClass
                )
            );
        }
    }

    /**
    * @param GenericDeserializationVisitor $visitor
    * @param string $id
    * @param array $type
    */
    public function deserializeEntity(GenericDeserializationVisitor $visitor, $id, array $type)
    {
        if (null === $id) {
            return null;
        }

        if (!(is_array($type) && isset($type['params']) && is_array($type['params']) && isset($type['params']['0']))) {
            return null;
        }

        $entityClass = $type['params'][0]['name'];
        $entityManager = $this->getEntityManager($entityClass);

        return $entityManager->getRepository($entityClass)->find($id);
    }

    /**
     * @param array $parameters
     * @return string
     */
    protected function getEntityClassFromParameters(array $parameters)
    {
        if (!(isset($parameters[0]) && is_array($parameters[0]) && isset($parameters[0]['name']))) {
            throw new InvalidArgumentException('Entity class is not defined');
        }

        if (!class_exists($parameters[0]['name'])) {
            throw new InvalidArgumentException(sprintf("Entity class '%s' is not found", $parameters[0]['name']));
        }

        return $parameters[0]['name'];
    }

    /**
     * @param string $entityClass
     * @return EntityManagerInterface
     */
    protected function getEntityManager($entityClass)
    {
        $entityManager = $this->registry->getEntityManagerForClass($entityClass);
        if (!$entityManager) {
            throw new InvalidArgumentException(
                sprintf("Entity class '%s' is not mannaged by Doctrine", $entityClass)
            );
        }

        return $entityManager;
    }
}

然后你应该在你的服务配置文件中注册它.如果您使用 yaml,它将是这样的:

Then you should register it in your service configuration file. If you use yaml, it will be something like that:

custom_serializer_handle:
    class: AppBundle\Serializer\Handler\EntityHandler
    arguments: ['@doctrine']
    tags:
        - {name: 'jms_serializer.subscribing_handler'}

在您的实体中,定义 JMSSerializer Type 注释

In your entity, define JMSSerializer Type annotation

/**
 * @var Team
 * * @ORM\ManyToOne(targetEntity="Team")
 * @ORM\JoinColumn(name="home_team_id", referencedColumnName="id")
 * @JMSSerializer\SerializedName("home")
 * @JMSSerializer\Type("Entity<AppBundle\Entity\Team>")
 * List item
 */
private $homeTeam;

不要忘记清除缓存.仅此而已.

Don't forget clear caches. That's all.

这篇关于JMSSerializer 按 id 反序列化实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆