Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
822 views
in Technique[技术] by (71.8m points)

symfony - how to update symfony2/doctrine entity from a @Groups inclusion policy JMSSerializer deserialized entity

I'm trying to update symfony2/doctrine entities using JMSSerializer with an @ExclusionPolicy:None @Groups Inclusion Policy.

 * @SerializerExclusionPolicy("none")
 */
 class Foo
 {
    /**
     * @SerializerGroups({"flag","edit"})
     */
    protected $id;

    /**
     * @SerializerGroups({"edit"})
     */
    protected $name;

    /**
     * @SerializerGroups({"flag"})
     */
    protected $flag;

    /**
     * @SerializerExclude()
     */
    protected $createdBy;
 }

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

the result for the following record:

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

is serialized using Group inclusion to avoid serializing information I don't need (associations, blobs, etc..) so when I want to update an entity I deserialize only the updated fields of the entity from the JSON.

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

result:
{id:1,flagged:true}

which when passed back to the application deserializes into the entity

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

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

The problem is when I try to merge the entity back into the doctrine entity manager:

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

The resulting foo is trying to update excluded properties (name,created_by) with null.

How do I tell JMSSerializer or Doctrine Entity Managers merge that I don't want to overwrite existing properties with null?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I found the answer.

$serializer is a service created by the symfony2 integration bundle JMSSerializerBundle.

The default service is jms_serializer.serializer initializes the JMSSerializer with the default Object Constructor UnserializeObjectConstructor and for doctrine I needed to deserialize with the DoctrineObjectConstructor.

because I only use JMSSerializer in the project for serialize/deserialize of doctrine entities, I overwrote JMSSerializerBundle's jms_serializer.object_constructor with the alias of the proper object constructor service.

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

Is there a better way to configure what object constructor the serializer uses?

I also added the proper context to deserialize:

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

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

Using the doctrine object constructor, it figures out that I want to find the object and only apply updates to fields provided in $jsonFoo (and the flag group). This totally eliminates the need for doctrines entity manager merge and I can just persist the object properly.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...