2013-05-13 78 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();