We are using Symfony2 to create an API. When updating a record, we expect the JSON input to represent a serialized updated entity. The JSON data will not contain some fields (for instance, CreatedAt should be set only once when the entity is created - and never updated). For instance, here is an example JSON PUT request:
我们使用Symfony2来创建API。更新记录时,我们希望JSON输入表示序列化更新的实体。 JSON数据将不包含某些字段(例如,创建实体时,CreatedAt只应设置一次 - 并且永远不会更新)。例如,这是一个示例JSON PUT请求:
{"id":"1","name":"anyname","description":"anydescription"}
Here is the PHP code on the Controller that should update the entity according to the JSON above (we are using JMS serializer Bundle):
这是Controller上的PHP代码,它应该根据上面的JSON更新实体(我们使用的是JMS序列化器Bundle):
$supplier = $serializer->deserialize(
$this->get('request')->getContent(),
'WhateverEntity',
'json'
);
The EntityManger understands (correctly) that this is an update request (in fact, a SELECT query is implicitly triggered). The EntityManager also guess (not correctly) that CreatedAt property should be NULLified - it should instead keep the previous one.
EntityManger(正确地)理解这是一个更新请求(实际上,隐式触发了SELECT查询)。 EntityManager还猜测(不正确)CreatedAt属性应该被NULL化 - 它应该保留前一个属性。
How to fix this issue?
如何解决这个问题?
2 个解决方案
#1
9
I would use the Doctrine\ORM\Mapping\ClassMetadata
API to discover existing fields in your entity. You can do following (I don't know how JMSSerializerBundle works):
我将使用Doctrine \ ORM \ Mapping \ ClassMetadata API来发现实体中的现有字段。您可以执行以下操作(我不知道JMSSerializerBundle如何工作):
//Unserialize data into $data
$metadata = $em->getMetadataFactory()->getMetadataFor($FQCN);
$id = array();
foreach ($metadata->getIdentifierFieldNames() as $identifier) {
if (!isset($data[$identifier])) {
throw new InvalidArgumentException('Missing identifier');
}
$id[$identifier] = $data[$identifier];
unset($data[$identifier]);
}
$entity = $em->find($metadata->getName(), $id);
foreach ($metadata->getFieldNames() as $field) {
//add necessary checks about field read/write operation feasibility here
if (isset($data[$field])) {
//careful! setters are not being called! Inflection is up to you if you need it!
$metadata->setFieldValue($entity, $field, $data[$field]);
}
}
$em->flush();
#2
14
using the JMSSerializerBundle follow the install instructions at http://jmsyst.com/bundles/JMSSerializerBundle
使用JMSSerializerBundle按照http://jmsyst.com/bundles/JMSSerializerBundle上的安装说明进行操作
either create your own serializer service or alter the JMSSerializerBundle to use the doctrine object constructor instead of the simple object constructor.
要么创建自己的序列化程序服务,要么更改JMSSerializerBundle以使用doctrine对象构造函数而不是简单对象构造函数。
<service id="jms_serializer.object_constructor" alias="jms_serializer.doctrine_object_constructor" public="false"/>
This basically handles exactly what Ocramius solution does but using the JMSSerializerBundles deserialize.
这基本上可以处理Ocramius解决方案的功能,但使用JMSSerializerBundles反序列化。
#1
9
I would use the Doctrine\ORM\Mapping\ClassMetadata
API to discover existing fields in your entity. You can do following (I don't know how JMSSerializerBundle works):
我将使用Doctrine \ ORM \ Mapping \ ClassMetadata API来发现实体中的现有字段。您可以执行以下操作(我不知道JMSSerializerBundle如何工作):
//Unserialize data into $data
$metadata = $em->getMetadataFactory()->getMetadataFor($FQCN);
$id = array();
foreach ($metadata->getIdentifierFieldNames() as $identifier) {
if (!isset($data[$identifier])) {
throw new InvalidArgumentException('Missing identifier');
}
$id[$identifier] = $data[$identifier];
unset($data[$identifier]);
}
$entity = $em->find($metadata->getName(), $id);
foreach ($metadata->getFieldNames() as $field) {
//add necessary checks about field read/write operation feasibility here
if (isset($data[$field])) {
//careful! setters are not being called! Inflection is up to you if you need it!
$metadata->setFieldValue($entity, $field, $data[$field]);
}
}
$em->flush();
#2
14
using the JMSSerializerBundle follow the install instructions at http://jmsyst.com/bundles/JMSSerializerBundle
使用JMSSerializerBundle按照http://jmsyst.com/bundles/JMSSerializerBundle上的安装说明进行操作
either create your own serializer service or alter the JMSSerializerBundle to use the doctrine object constructor instead of the simple object constructor.
要么创建自己的序列化程序服务,要么更改JMSSerializerBundle以使用doctrine对象构造函数而不是简单对象构造函数。
<service id="jms_serializer.object_constructor" alias="jms_serializer.doctrine_object_constructor" public="false"/>
This basically handles exactly what Ocramius solution does but using the JMSSerializerBundles deserialize.
这基本上可以处理Ocramius解决方案的功能,但使用JMSSerializerBundles反序列化。