JMSSerializer:如何为同类型属性实现差异化序列化处理?
同一类型在不同序列化场景下的差异化处理方案
问题背景
已知可以为整个类型声明自定义处理器,但实际场景中需要对同一类型采用不同的序列化逻辑。比如实体Foo有个int类型的属性$popularity,序列化时希望通过PopularityProcessor的process方法把值乘2再输出,但因为是int类型没法注册全局自定义处理器,需要针对性的解决方案。
相关代码示例
class Foo { public int $popularity = 10; } class PopularityProcessor { public function process(int $popularity) { return $popularity * 2; } }
原映射配置:
App\Entity\Foo: properties: popularity: ~
解决方案
方案一:属性级访问器
直接在实体类里加一个专门用于序列化的getter方法,然后在映射配置里指定使用这个方法取值。
修改Foo类:
class Foo { public int $popularity = 10; // 专门给序列化用的getter public function getSerializedPopularity(): int { $processor = new PopularityProcessor(); return $processor->process($this->popularity); } }
更新YAML映射配置:
App\Entity\Foo: properties: popularity: accessor: getter: getSerializedPopularity
这样序列化时就会调用这个自定义getter,自动把值乘2输出。
方案二:序列化组+上下文处理器
如果需要多场景切换,比如有时候乘2,有时候用原值,可以用序列化组配合上下文感知的归一化器。
先写一个自定义归一化器:
use Symfony\Component\Serializer\Normalizer\ContextAwareNormalizerInterface; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerInterface; class PopularityContextNormalizer implements ContextAwareNormalizerInterface, SerializerAwareInterface { private SerializerInterface $serializer; public function normalize($object, string $format = null, array $context = []) { // 先让默认序列化逻辑处理 $data = $this->serializer->normalize($object, $format, $context); // 如果指定了对应分组,就处理popularity值 if (in_array('popularity_multiply', $context['groups'] ?? [])) { $processor = new PopularityProcessor(); $data['popularity'] = $processor->process($data['popularity']); } return $data; } public function supportsNormalization($data, string $format = null, array $context = []): bool { // 只对Foo实例且包含指定分组的请求生效 return $data instanceof Foo && in_array('popularity_multiply', $context['groups'] ?? []); } public function setSerializer(SerializerInterface $serializer) { $this->serializer = $serializer; } }
使用的时候指定分组即可:
// 需要乘2的场景 $serializer->serialize($foo, 'json', ['groups' => ['popularity_multiply']]); // 不需要处理的场景,不指定这个分组就行 $serializer->serialize($foo, 'json');
方案三:属性注解指定专属处理器(Symfony环境)
如果用注解配置映射,可以直接在属性上绑定专属的处理器:
先写一个针对单个属性的归一化器:
use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class SinglePropertyPopularityNormalizer implements NormalizerInterface { public function normalize($value, string $format = null, array $context = []) { $processor = new PopularityProcessor(); return $processor->process($value); } public function supportsNormalization($data, string $format = null): bool { // 只处理int类型,结合上下文可进一步限制为Foo的popularity属性 return is_int($data); } }
然后在Foo类的属性上用注解指定:
use Symfony\Component\Serializer\Annotation\Context; class Foo { #[Context(normalizer: [SinglePropertyPopularityNormalizer::class])] public int $popularity = 10; }
这样序列化这个属性时就会自动调用指定的处理器。
内容的提问来源于stack exchange,提问作者ozahorulia
相关产品推荐
相关产品推荐

