如何配置JMS Serializer不反序列化未传入的字段?
JMS Serializer处理PATCH请求DTO未传字段的配置方案
场景说明
在PATCH请求的Request DTO中,当请求仅传入部分字段时,未传入的字段会被反序列化为null(因DTO属性初始值为null)。若需要仅更新请求中明确传入的字段,或区分“字段未传入”与“字段传入null”,可通过以下方案实现。
方法一:使用object_to_populate保留初始值
如果希望未传入的字段保持DTO的初始状态(而非被覆盖为null),可在反序列化时传入已初始化的DTO实例,序列化器仅会更新请求中存在的字段:
// 初始化DTO,保留属性初始值 $initialDto = new RequestDTO(); // 反序列化时指定要填充的对象 $updatedDto = $serializer->deserialize( $request->getContent(), RequestDTO::class, 'json', [ 'object_to_populate' => $initialDto ] );
此方式下,请求中未提及的字段会维持$initialDto的初始值,不会被强制设为null。
方法二:启用字段访问追踪,区分未传入与传入null
若需要明确判断哪些字段是请求中实际传入的(包括传入null的情况),可启用track_visited选项,通过元数据获取字段访问状态:
- 反序列化时启用追踪:
$context = new \JMS\Serializer\DeserializationContext(); $context->setAttribute('track_visited', true); $dto = $serializer->deserialize( $request->getContent(), RequestDTO::class, 'json', $context );
- 判断字段是否被传入:
$metadataFactory = $serializer->getMetadataFactory(); $classMetadata = $metadataFactory->getMetadataForClass(RequestDTO::class); // 检查title字段是否被请求传入 $titleWasProvided = $classMetadata->propertyMetadata['title']->isVisited();
返回值说明:
true:请求中包含该字段(无论值为null还是其他内容)false:请求中未传入该字段
方法三:字段级自定义赋值逻辑
针对个别字段,可通过@JMS\Accessor注解自定义赋值逻辑,精准控制是否为未传入的字段赋值:
class RequestDTO { /** * @JMS\Type("string") */ private ?string $publicId = null; /** * @JMS\Type("string") * @JMS\Accessor(setter="setTitleIfProvided") */ private ?string $title = null; public function setTitleIfProvided(?string $title): void { // 仅当请求明确传入该字段时赋值(结合track_visited可更精准判断) $this->title = $title; } }
内容的提问来源于stack exchange,提问作者darjus
相关产品推荐
相关产品推荐

