2013-05-13 75 views
11

我正在尝试使用带有@ExclusionPolicy的JMSSerializer更新symfony2/doctrine实体:无@Groups包含策略。如何从@Groups包含策略更新symfony2/doctrine实体JMSSerializer反序列化实体

* @Serializer\ExclusionPolicy("none") 
*/ 
class Foo 
{ 
    /** 
    * @Serializer\Groups({"flag","edit"}) 
    */ 
    protected $id; 

    /** 
    * @Serializer\Groups({"edit"}) 
    */ 
    protected $name; 

    /** 
    * @Serializer\Groups({"flag"}) 
    */ 
    protected $flag; 

    /** 
    * @Serializer\Exclude() 
    */ 
    protected $createdBy; 
} 

参考:http://jmsyst.com/libs/serializer/master/reference/annotations

结果为以下记录:

Foo (id:1, name:'bar', flagged:false ,created_by:123) 

使用集团列入避免序列化信息我不需要(协会,斑点等连载.. ),所以当我想更新一个实体时,我只从JSON反序列化实体的更新字段。

$foo->setFlagged(true); 
$data = $serializer->serialize($foo, 'json', SerializationContext::create()->setGroups(array("flag"))); 

result: 
{id:1,flagged:true} 
,当回传给应用

反序列化到实体

$foo = $serializer->deserialize($jsonFoo,'Foo','json'); 

result: 
Foo (id:1, name:null, flagged:true, created_by:null) 

问题是,当我尝试将实体合并回主义实体管理器:

$foo = $em->merge($foo); 
$em->persist($foo); 
$em->flush(); 

的导致foo试图用null更新排除的属性(name,created_by)。

如何告诉JMSSerializer或Doctrine实体管理器合并,我不想用null覆盖现有属性?

+0

唯一的选择,我发现远远http://stackoverflow.com/questions/8726611/how-to-update-a-doctrine-entity-from-a-serialized-json这意味着绕过JMSSerializers反序列化并检查它/更新实体手动(在这个例子中是绕过setter)。 – Heyflynn 2013-05-13 15:38:41

回答

17

我找到了答案。

$serializer是由symfony2集成包JMSSerializerBundle创建的服务。

默认服务为jms_serializer.serializer初始化JMSSerializer使用默认的对象构造UnserializeObjectConstructor和教义,我需要与DoctrineObjectConstructor反序列化。

,因为我只在项目学说实体的序列化/反序列化使用JMSSerializer,我改写JMSSerializerBundlejms_serializer.object_constructor与适当的对象构造服务的别名。

<service id="jms_serializer.object_constructor" alias="jms_serializer.doctrine_object_constructor" public="false"/> 

有没有更好的办法来配置哪些对象构造串行使用?

我还添加了适当的上下文反序列化:

$serializer->deserialize($jsonFoo,'Foo','json', DeserializationContext::create()->setGroups(array('flag'))); 

result: 
Foo (id:1, name:'bar', flagged:true ,created_by:123) 

使用学说对象的构造,它的数字出来,我想找到对象,只适用更新于$jsonFoo提供的字段(和标志组)。这完全消除了对教条实体管理器合并的需要,我可以正确地坚持对象。

$em->persist($foo); 
$em->flush(); 
4

除了@ Heyflynn的回答(谢谢!),我需要这与doctrine_mongodb工作,所以我修改services.yml如下:

services: 
    jms_serializer.doctrine_object_constructor: 
     class:  %jms_serializer.doctrine_object_constructor.class% 
     public:  false 
     arguments: ["@doctrine_mongodb", "@jms_serializer.unserialize_object_constructor"] 

    jms_serializer.object_constructor: 
     alias: jms_serializer.doctrine_object_constructor 

重要的事实是@doctrine_mongodb作为论据jms_serializer.doctrine_object_constructor代替原来doctrine参数在束的services.xml

<service id="jms_serializer.doctrine_object_constructor" class="%jms_serializer.doctrine_object_constructor.class%" public="false"> 
     <argument type="service" id="doctrine"/> 
     <argument type="service" id="jms_serializer.unserialize_object_constructor"/> 
    </service> 
    <service id="jms_serializer.unserialize_object_constructor" class="%jms_serializer.unserialize_object_constructor.class%" public="false" /> 
    <service id="jms_serializer.object_constructor" alias="jms_serializer.unserialize_object_constructor" public="false" /> 
1

要使用JMS解串器实现MongoDB文档和ORM实体,您可以使用

jms_serializer.doctrine_mongodb_object_constructor: 
    class:  %jms_serializer.doctrine_object_constructor.class% 
    public:  false 
    arguments: ["@doctrine_mongodb", "@jms_serializer.unserialize_object_constructor"] 

jms_serializer.doctrine_object_constructor: 
    class:  %jms_serializer.doctrine_object_constructor.class% 
    public:  false 
    arguments: ["@doctrine", "@jms_serializer.doctrine_mongodb_object_constructor"] 

jms_serializer.object_constructor: 
    alias: jms_serializer.doctrine_object_constructor 
    public: false 

正如你在jms_serializer.doctrine_object_constructor秒参数见(fallbackConstructor)是jms_serializer.doctrine_mongodb_object_constructor这意味着,如果你的对象不是实体则JMS将尝试使用fallbackConstructor,如果你deserialised对象不是文档不那么会使用默认unserialize_object_constructor

,如果你反序列化实体

$em->persist($foo); 
$em->flush(); 

如果文档

$dm->persist($foo); 
$dm->flush();