Symfony 6 Serializer的#[Ignore]属性与命名转换器不生效问题
问题根因
你的推测完全正确:Symfony 序列化器默认加载的归一化器优先级排序中,GetSetMethodNormalizer 优先级高于支持注解、名称转换规则的ObjectNormalizer。当序列化实体类时,GetSetMethodNormalizer会先匹配到实体的getter方法,直接走自身的归一化逻辑,既不会识别#[Ignore]属性,也不会应用全局配置的name_converter规则,最终导致两个配置都不生效。
另外还有两个容易踩的细节问题:
- 要确认
#[Ignore]引入的是正确命名空间:Symfony\Component\Serializer\Annotation\Ignore,不要误用Doctrine或其他组件的同名注解 - 手动实例化序列化器时如果没有主动传入名称转换器、调整归一化器顺序,同样会出现规则不生效的问题
方案1:仅通过YAML配置修复(推荐,无需改业务代码)
适用于Symfony 6.1及以上版本,只需要在原有配置基础上新增default_normalizers项,调整归一化器加载顺序即可:
# config/packages/framework.yaml framework: serializer: name_converter: 'serializer.name_converter.camel_case_to_snake_case' enable_annotations: true default_context: datetime_format: Y-m-d # 新增以下配置,调整归一化器优先级 default_normalizers: - 'serializer.normalizer.object' - 'serializer.normalizer.get_set_method' - 'serializer.normalizer.datetime' annotations: enabled: true
配置生效后,ObjectNormalizer会优先处理实体序列化逻辑,#[Ignore]字段排除、驼峰转蛇形命名、日期格式化规则都会正常生效。
如果你的项目是Symfony 6.0版本,只需要安装symfony/serializer-pack组件包后执行cache:clear,组件会自动调整归一化器优先级,不需要额外写配置。
方案2:手动实例化序列化器的正确写法
你之前手动编写的序列化器代码存在两个问题:一是没有传入名称转换器实例,二是没有处理JsonResponse二次转义的问题,修正后的代码如下:
use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; use Doctrine\Common\Annotations\AnnotationReader; // 初始化注解元数据工厂 $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); // 初始化驼峰转蛇形名称转换器 $nameConverter = new CamelCaseToSnakeCaseNameConverter(); // 实例化归一化器,传入元数据工厂和名称转换器 $objectNormalizer = new ObjectNormalizer($classMetadataFactory, $nameConverter); // 初始化序列化器,注意不要把GetSetMethodNormalizer放在ObjectNormalizer之前 $serializer = new Serializer([$objectNormalizer], [new JsonEncoder()]); // 最后一个参数设为true,告诉JsonResponse内容已经是序列化好的JSON,避免二次转义 return new JsonResponse( $serializer->serialize($events, 'json'), 200, [], true );
内容的提问来源于stack exchange,提问作者Erfan
相关产品推荐
相关产品推荐

