You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Symfony中用FOS/JMS BodyConverter从单负载反序列化多对象?

单个请求负载反序列化多对象(FOS/JMS BodyConverter + Symfony)

需求场景

需要从单个请求负载中反序列化出两个对象:

{ "object_data_1": ..., "object_data_2" : ...}

并通过ParamConverter注解直接在控制器方法中获取两个对象实例:

#[ParamConverter('obj1', options: ['configure starting node here?'], converter: 'fos_rest.request_body')]
#[ParamConverter('obj2', options: ['configure starting node here?'], converter: 'fos_rest.request_body')]
public function controllerMethod(Obj1 $obj1, Obj2 $obj2) : Response
{...}

可行实现方案

1. 基于JMS序列化组的基础方案

利用JMS序列化器的分组特性,匹配请求中的指定字段:

  • 给实体类的属性添加序列化别名和分组标记:
use JMS\Serializer\Annotation as Serializer;

class Obj1
{
    /**
     * @Serializer\SerializedName("object_data_1")
     * @Serializer\Groups({"obj1"})
     */
    private $property1;

    // 其他属性、getter/setter
}
class Obj2
{
    /**
     * @Serializer\SerializedName("object_data_2")
     * @Serializer\Groups({"obj2"})
     */
    private $propertyA;

    // 其他属性、getter/setter
}
  • 控制器中通过deserialization_context指定分组:
#[ParamConverter('obj1', options: [
    'deserialization_context' => ['groups' => ['obj1']]
], converter: 'fos_rest.request_body')]
#[ParamConverter('obj2', options: [
    'deserialization_context' => ['groups' => ['obj2']]
], converter: 'fos_rest.request_body')]
public function controllerMethod(Obj1 $obj1, Obj2 $obj2): Response
{
    // 业务逻辑
}

2. 自定义ParamConverter(灵活方案)

如果分组方式不满足需求,可自定义转换器直接指定解析节点:

  • 创建自定义转换器类:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Symfony\Component\HttpFoundation\Request;
use JMS\Serializer\SerializerInterface;

class MultiObjectParamConverter implements ParamConverterInterface
{
    private $serializer;

    public function __construct(SerializerInterface $serializer)
    {
        $this->serializer = $serializer;
    }

    public function apply(Request $request, ParamConverter $configuration)
    {
        $rawData = json_decode($request->getContent(), true);
        $paramName = $configuration->getName();
        $targetClass = $configuration->getClass();
        $targetNode = $configuration->getOptions()['node'] ?? '';

        if (!isset($rawData[$targetNode])) {
            return false;
        }

        $object = $this->serializer->deserialize(
            json_encode($rawData[$targetNode]),
            $targetClass,
            'json'
        );

        $request->attributes->set($paramName, $object);
        return true;
    }

    public function supports(ParamConverter $configuration)
    {
        return $configuration->getConverter() === 'multi_object';
    }
}
  • 在services.yaml中注册转换器:
services:
    App\Request\ParamConverter\MultiObjectParamConverter:
        tags:
            - { name: sensio_framework_extra.param_converter }
  • 控制器中使用自定义转换器:
#[ParamConverter('obj1', options: [
    'node' => 'object_data_1'
], converter: 'multi_object')]
#[ParamConverter('obj2', options: [
    'node' => 'object_data_2'
], converter: 'multi_object')]
public function controllerMethod(Obj1 $obj1, Obj2 $obj2): Response
{
    // 业务逻辑
}

3. 手动解析请求体(快速方案)

如果不想改动配置,可直接在控制器中手动拆分反序列化:

use JMS\Serializer\SerializerInterface;

public function controllerMethod(Request $request, SerializerInterface $serializer): Response
{
    $rawData = json_decode($request->getContent(), true);
    
    $obj1 = $serializer->deserialize(
        json_encode($rawData['object_data_1']),
        Obj1::class,
        'json'
    );
    $obj2 = $serializer->deserialize(
        json_encode($rawData['object_data_2']),
        Obj2::class,
        'json'
    );

    // 业务逻辑
}

内容的提问来源于stack exchange,提问作者Friedrich Roell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:42:35