Как обновить объект symfony2/doctrine из политики включения @Groups JESSerializer десериализованный объект
Я пытаюсь обновить объекты symfony2/doctrine с помощью JMSSerializer с помощью политики @ExclusionPolicy: None @Groups Inclusion.
* @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 пытается обновить исключенные свойства (name, created_by) с нулевым значением.
Как сообщить JMSSerializer или Doctrine Entity Managers слияние, что я не хочу перезаписывать существующие свойства с нулевым значением?
Ответы
Ответ 1
Я нашел ответ.
$serializer
- это сервис, созданный пакетом интеграции symfony2 JMSSerializerBundle
.
Служба по умолчанию jms_serializer.serializer
инициализирует JMSSerializer
с помощью Object Constructor по умолчанию UnserializeObjectConstructor
, а для доктрины мне нужно десериализовать с помощью DoctrineObjectConstructor
.
потому что я использую только JMSSerializer
в проекте для сериализации/десериализации сущности доктрины, я перезаписал JMSSerializerBundle
jms_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)
Используя конструктор объекта doctrine, выясняется, что я хочу найти объект и применять обновления только к полям, указанным в $jsonFoo
(и группе флагов). Это полностью исключает необходимость объединения объединений сущностей доктрин, и я могу просто сохранить объект должным образом.
$em->persist($foo);
$em->flush();
Ответ 2
в дополнение к @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" />
Ответ 3
Чтобы использовать десериализатор 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, и если ваш десериализованный объект не является Документом, то он будет использоваться default unserialize_object_constructor
если вы десериализуете сущность
$em->persist($foo);
$em->flush();
если документ
$dm->persist($foo);
$dm->flush();