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

Symfony Serializer分组在Slim4+PHP8.3中不生效,求解决方案

问题描述

我正在使用PHP8.3和Slim4框架开发应用,引入Symfony Serializer进行对象的序列化与反序列化操作。

依赖配置(dependencies.php)

$containerBuilder->addDefinitions([
        Serializer::class => function () {
            $encoders = [new JsonEncoder()];
            $extractors = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);
            $normalizers = [new ArrayDenormalizer(), new ObjectNormalizer(null, null, null, $extractors)];

            return new Serializer($normalizers, $encoders);
        }
    ]);

实体类代码

<?php

namespace App\Domain\Entity;

use App\Application\Repository\CompanyRepository;
use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\Table;
use Symfony\Component\Serializer\Annotation\Groups;

#[Entity(repositoryClass: CompanyRepository::class), Table(name: 'companies')]
class Company
{
    #[Groups(['save-company'])]
    #[Column(type: 'string', length: 9, nullable: true)]
    private string $siren;

    #[Groups(['save-company'])]
    #[Column(type: 'string', length: 15, nullable: true)]
    private string $siret;

    #[Column(name: 'trading_name', type: 'string', length: 50, nullable: true)]
    private ?string $tradingName;


    public function getSiren(): string
    {
        return $this->siren;
    }

    public function setSiren(string $siren): void
    {
        $this->siren = $siren;
    }

    public function getSiret(): string
    {
        return $this->siret;
    }

    public function setSiret(string $siret): void
    {
        $this->siret = $siret;
    }

    public function getTradingName(): ?string
    {
        return $this->tradingName;
    }

    public function setTradingName(?string $tradingName): void
    {
        $this->tradingName = $tradingName;
    }

}

反序列化代码

$this->sfSerializer->deserialize(json_encode($this->getFormData()), Company::class, JsonEncoder::FORMAT, [
            AbstractNormalizer::OBJECT_TO_POPULATE => $company,
            AbstractNormalizer::GROUPS => ['save-company']
        ]);

请求体

{
        "siren": "SRN-1",
        "siret": "SRT-1",
        "tradingName": "my comany name"
}

需求是仅反序列化siren和siret字段,但当前会处理所有属性,请问遗漏了什么配置?


解决方案

核心问题是:使用OBJECT_TO_POPULATE填充现有对象时,Symfony Serializer默认会处理所有存在setter方法的属性,不受Groups配置限制。要实现仅处理指定组内字段,需添加以下配置:

修改反序列化参数

添加AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES并设置为false,阻止Serializer处理未加入指定组的属性:

$this->sfSerializer->deserialize(json_encode($this->getFormData()), Company::class, JsonEncoder::FORMAT, [
    AbstractNormalizer::OBJECT_TO_POPULATE => $company,
    AbstractNormalizer::GROUPS => ['save-company'],
    // 新增:禁止处理组外属性
    AbstractNormalizer::ALLOW_EXTRA_ATTRIBUTES => false,
]);

补充说明

  • 当ALLOW_EXTRA_ATTRIBUTES设为false时,请求体中不在save-company组内的字段(如tradingName)会被直接忽略,不会调用对应的setTradingName方法。
  • 如果需要对组外字段抛出异常,可额外添加配置:AbstractNormalizer::EXTRA_ATTRIBUTES_EXCEPTION_CLASS => \Symfony\Component\Serializer\Exception\ExtraAttributesException::class,这样当请求包含组外字段时会直接报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 14:05:22