如何用Symfony序列化器正确填充DTO的ArrayCollection属性?
解决方案
方法一:使用Doctrine集合专用归一化器
Symfony Serializer组件内置了DoctrineCollectionNormalizer,专门用于处理Doctrine的集合类型(如ArrayCollection)。它能自动将请求中的普通数组直接转换为ArrayCollection实例,无需手动构造elements结构。
步骤1:给DTO属性添加SerializedName注解
use Symfony\Component\Serializer\Annotation\SerializedName; use Doctrine\Common\Collections\ArrayCollection; use Symfony\Component\Validator\Constraints as Assert; class ParamsDto { #[Assert\Type(ArrayCollection::class)] #[Assert\All([ new Assert\Type('digit'), new Assert\Positive(), ])] #[SerializedName('tag-ids')] // 直接映射请求参数名 private ?ArrayCollection $tagIds = null; // 原有getter、setter保持不变 }
步骤2:修改序列化器实例化代码
添加DoctrineCollectionNormalizer到归一化器列表,并确保注解能被正确识别:
use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Normalizer\DoctrineCollectionNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Doctrine\Common\Annotations\AnnotationReader; // 初始化注解加载器,用于识别SerializedName注解 $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); $serializer = new Serializer([ new DoctrineCollectionNormalizer(), // 优先处理集合类型 new ArrayDenormalizer(), new ObjectNormalizer($classMetadataFactory, null, null, new ReflectionExtractor()), ], [new JsonEncoder()]);
这样处理后,序列化器会自动将tag-ids[]=2对应的数组值转换为ArrayCollection,无需任何预处理。
方法二:自定义类型转换逻辑(可选)
如果不想依赖DoctrineCollectionNormalizer,可以给ObjectNormalizer注册回调函数,手动处理数组到ArrayCollection的转换:
use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Doctrine\Common\Collections\ArrayCollection; $objectNormalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); // 注册回调,将数组转换为ArrayCollection $objectNormalizer->registerCallback(ArrayCollection::class, function ($data) { return new ArrayCollection($data); }); $serializer = new Serializer([ new ArrayDenormalizer(), $objectNormalizer, ], [new JsonEncoder()]);
这种方式需要自行处理类型判断,不如第一种方法简洁可靠,仅作为备选方案。
内容的提问来源于stack exchange,提问作者Twisted1919
相关产品推荐
相关产品推荐

