Symfony反序列化ApiPlatform MongoDB Paginator构造参数缺失问题问询
问题根因
ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Paginator 是依赖数据库游标(mongoDbOdmIterator)的运行时对象,该游标属于和数据库连接绑定的资源类型,本身不支持序列化存储。直接序列化整个Paginator对象只会序列化公共属性,反序列化时无法恢复依赖的游标实例,因此抛出构造参数缺失的错误:
无法基于序列化数据创建"\ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Paginator"实例,因为其构造函数要求传入参数"mongoDbOdmIterator"。
推荐实现方案
不直接序列化Paginator对象,提前提取业务需要的结果集数据和分页元数据后再序列化,反序列化后可按需构造兼容接口的分页对象,性能和可维护性更高,实现代码如下:
序列化阶段
$paginator = $this->getCollectionResults($aggregationBuilder, $resourceClass, $operationName, $context); // 提取可序列化的分页数据 $cacheData = [ 'items' => iterator_to_array($paginator->getIterator()), // 实际查询结果集 'totalItems' => $paginator->getTotalItems(), // 总数据条数 'currentPage' => $paginator->getCurrentPage(), // 当前页码 'itemsPerPage' => $paginator->getItemsPerPage(), // 每页条数 // 可追加其他需要的分页元数据 ]; // 序列化后存入Redis $serialized = $this->serializer->serialize($cacheData, 'json');
反序列化阶段
如果需要返回和原Paginator接口兼容的对象,可使用ArrayIterator构造虚拟Paginator实例,不需要依赖真实数据库游标:
$cacheData = $this->serializer->deserialize($serialized, 'array', 'json'); // 构造虚拟Paginator实例,适配原有逻辑的类型约束 $paginator = new \ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Paginator( new \ArrayIterator($cacheData['items']), $cacheData['totalItems'], $cacheData['itemsPerPage'], $cacheData['currentPage'] );
备选方案:自定义序列化处理器
如果需要让序列化逻辑透明处理Paginator类型,无需修改原有业务代码,可以给Symfony序列化器注册针对该类的自定义Normalizer:
- 创建自定义Normalizer类
use ApiPlatform\Core\Bridge\Doctrine\MongoDbOdm\Paginator; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; class MongoPaginatorNormalizer implements NormalizerInterface, DenormalizerInterface { public function normalize($object, string $format = null, array $context = []): array { /** @var Paginator $object */ return [ 'items' => iterator_to_array($object->getIterator()), 'totalItems' => $object->getTotalItems(), 'currentPage' => $object->getCurrentPage(), 'itemsPerPage' => $object->getItemsPerPage(), ]; } public function supportsNormalization($data, string $format = null): bool { return $data instanceof Paginator; } public function denormalize($data, string $type, string $format = null, array $context = []) { return new Paginator( new \ArrayIterator($data['items']), $data['totalItems'], $data['itemsPerPage'], $data['currentPage'] ); } public function supportsDenormalization($data, string $type, string $format = null): bool { return $type === Paginator::class; } }
- 注册到序列化器即可直接对Paginator对象序列化/反序列化
$normalizers = [new MongoPaginatorNormalizer(), new ObjectNormalizer()]; $serializer = new Serializer($normalizers, [new JsonEncoder()]); // 直接序列化Paginator对象 $serialized = $serializer->serialize($paginator, 'json'); // 直接反序列化还原Paginator对象 $paginator = $serializer->deserialize($serialized, Paginator::class, 'json');
内容的提问来源于stack exchange,提问作者Matthew Zarbatany
相关产品推荐
相关产品推荐

