2017-02-23 52 views
0

使用Symfony 3我写了一个应该通过JSON/JMSSerializer公开的实体(以RESTful方式)。它看起来像这样:JMSSerializer:使用ID从数据库中检索相关对象

/** 
* MainEntity 
* 
* @ORM\Table(name="MainEntity") 
* @ORM\Entity 
* 
*/ 
class MainEntity{ 

    /** 
    * @var integer 
    * 
    * @ORM\Column(name="id", type="integer", nullable=false) 
    * @ORM\Id 
    * @ORM\GeneratedValue(strategy="IDENTITY") 
    */ 
    private $id; 

    //... some more "simple" fields ... 

    /** 
    * @ORM\ManyToOne(targetEntity="SubEntity") 
    * @ORM\JoinColumns({ 
    * @ORM\JoinColumn(name="subentity", referencedColumnName="id") 
    * }) 
    * @JMS\Accessor(getter="getSubEntityId",setter="setSubEntity") 
    * @JMS\Type("integer") 
    * @JMS\SerializedName("subEntityId") 
    */ 
    private $subEntity; 
    //... 

    public function getSubEntityId() { 
     return $this->subEntity->getId(); 
    } 

} 

整个事情的JSON序列化就像一个魅力!尤其是,只有子实体ID才会暴露,而不是整个子实体,这可能相当大。

所以不是:

{"id": 1, ..., "subEntity": {"id": 123, "name": "Great subEntity", ...} } 

我得到

{"id": 1, ..., "subEntityId": 123 } 

这是完全是我啃老族。

但是,当涉及到系列化,我遇到麻烦......当然我还需要使用缩短的JSON格式的传入的请求,但这种失败,因为setSubEntity需要一个SubEntity实例,而不是一个号码。

有没有什么办法可以实现反序列化来检索相关对象ID时给出?

我想过这些可能性:

  1. 使用一个特殊的制定者(在@JMS\Accessor注释给出),采取id和填充从数据库中检索对象的subEntity场。但是这意味着将EntityManager注入实体(或类似的和不好的...)
  2. 添加一个新的数字字段subEntityId并让它由一个特殊的setter(如上图)填充。然后使用控制器读取它,从数据库中获取SubEntity对象,并在之后使用setSubEntity方法实体被反序列化。对我来说也不好看......

有什么建议吗?我看到,在Stackoverflow上有一些类似的问题,但在我看来,没有人描述我的特例。

非常感谢提前!

回答

1

其实你不不需要创建额外的字段或设置器。可能的方法是创建自己的Serializer handler并将其用于映射。

我已经回答了in this topic,所以你可以在那里得到代码示例。

+0

非常有帮助!谢谢! – ahuemmer

0

添加到您的服务配置,在这里我把它写在YAML

jms_serializer.object_constructor: 
    alias: jms_serializer.initialized_object_constructor 
    public: false 

jms_serializer.initialized_object_constructor: 
    class: MyApp\Bundle\CoreBundle\Serializer\InitializedObjectConstructor 
    arguments: ["@jms_serializer.unserialize_object_constructor"] 

jms_serializer.initialized_object_constructor

<?php 
namespace MyApp\Bundle\CoreBundle\Serializer; 
use JMS\Serializer\VisitorInterface; 
use JMS\Serializer\Metadata\ClassMetadata; 
use JMS\Serializer\DeserializationContext; 
use JMS\Serializer\Construction\ObjectConstructorInterface; 
class InitializedObjectConstructor implements ObjectConstructorInterface 
{ 
    private $fallbackConstructor; 
    public function __construct(ObjectConstructorInterface $fallbackConstructor) 
    { 
     $this->fallbackConstructor = $fallbackConstructor; 
    } 
    public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context) 
    { 
     if ($context->attributes->containsKey('target') && $context->getDepth() === 1) { 
      return $context->attributes->get('target')->get(); 
     } 
     return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context); 
    } 
} 

添加这个类在你的控制器:

protected function flushRequestData(Request $request, $entity = null) 
{ 
    $data = $request->getContent(); 
    $dm = $this->get('doctrine_mongodb.odm.default_document_manager'); 
    $context = new DeserializationContext(); 
    if ($entity) { 
     $context->attributes->set('target', $entity); 
    } 

    $deserializedObj = $this->get('serializer')->deserialize(
     $data, 
     $this->getRepository()->getClassName(), 
     'json', 
     $context 
    ); 

    // After deserialized into your entity you need to manually set each of the related entity one by one manually 
}