symfony - 如何限制 API 平台中嵌套实体的数量?
问题描述
有两个相关的实体,比如说作者和书籍,我可以限制(或分页)作者的结果,但不能限制其相关实体书籍的结果数量,它总是显示整个集合。
问题是作者可能有数百本书使生成的 JSON 变得庞大而沉重,因此我试图仅获取最后 5 本书。
我确定我遗漏了一些东西,因为我认为这可能是一种常见的情况,但我在文档和 StackOverflow 中都找不到任何东西。
我从 Api 平台开始,任何提示将不胜感激!
解决方案
我终于解决了它,为实体创建了一个规范化器,但我仍然认为它必须是一个更简单的解决方案。
这是我必须做的,按照作者/书籍的例子:
向 Author 实体添加一个 setter 以覆盖 Author's Book 集合:
// src/Entity/Author.php
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
// ...
/**
* @ApiResource
* @ORM\Entity(repositoryClass="App\Repository\AuthorRepository")
*/
class Author
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Book", mappedBy="author", orphanRemoval=true)
*/
private $books;
public function __construct()
{
$this->books = new ArrayCollection();
}
// Getters and setters
//...
public function setBooks($books): self
{
$this->books = $books;
return $this;
}
}
为作者的实体创建规范化器:
// App/Serializer/Normalizer/AuthorNormalizer.php
<?php
namespace App\Serializer\Normalizer;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Serializer\AbstractItemNormalizer;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerAwareTrait;
class AuthorNormalizer implements NormalizerInterface, DenormalizerInterface, SerializerAwareInterface
{
use SerializerAwareTrait;
private $normalizer;
public function __construct(
NormalizerInterface $normalizer,
IriConverterInterface $iriConverter
) {
if (!$normalizer instanceof DenormalizerInterface) {
throw new \InvalidArgumentException('The normalizer must implement the DenormalizerInterface');
}
if (!$normalizer instanceof AbstractItemNormalizer) {
throw new \InvalidArgumentException('The normalizer must be an instance of AbstractItemNormalizer');
}
$handler = function ($entity) use ($iriConverter) {
return $iriConverter->getIriFromItem($entity);
};
$normalizer->setMaxDepthHandler($handler);
$normalizer->setCircularReferenceHandler($handler);
$this->normalizer = $normalizer;
}
public function denormalize($data, $class, $format = null, array $context = [])
{
return $this->normalizer->denormalize($data, $class, $format, $context);
}
public function supportsDenormalization($data, $type, $format = null)
{
return $this->normalizer->supportsDenormalization($data, $type, $format);
}
public function normalize($object, $format = null, array $context = [])
{
// Number of desired Books to list
$limit = 2;
$newBooksCollection = new ArrayCollection();
$books = $object->getBooks();
$booksCount = count($books);
if ($booksCount > $limit) {
// Reverse iterate the original Book collection as I just want the last ones
for ($i = $booksCount; $i > $booksCount - $limit; $i--) {
$newBooksCollection->add($books->get($i - 1));
}
}
// Setter previously added to the Author entity to override its related Books
$object->setBooks($newBooksCollection);
$data = $this->normalizer->normalize($object, $format, $context);
return $data;
}
public function supportsNormalization($data, $format = null)
{
return $data instanceof \App\Entity\Author;
}
}
最后手动将规范器注册为服务(使用 autowire 导致我遇到循环引用问题):
services:
App\Serializer\Normalizer\AuthorNormalizer:
autowire: false
autoconfigure: true
arguments:
$normalizer: '@api_platform.jsonld.normalizer.item'
$iriConverter: '@ApiPlatform\Core\Api\IriConverterInterface'
推荐阅读
- linux - 在linux中随机选择行而不重复
- python - 按天在特定范围内的时间序列百分比
- typescript - 为没有任何共同点的类型联合编写类型保护的类型安全方法是什么?
- php - 如何将来自不同文件的两个或多个数组值合并到一个数组中
- python - 关于提高仿真效率同时减少 Python 方差的建议
- c++ - 跨平台程序集 ((x64 || x86) && (Microsoft x64 || SystemV))
- postgresql - PostgreSQL to_char 忽略语言环境
- linq - 基于 Lambda 表达式的连接
- scala - 如果 def 名称是 toString,Scala 隐式 def 不起作用
- reactjs - 材质 UI 文本字段无法更改多行的字体大小