如何限制API平台中嵌套实体的数量



有两个相关的实体,比如Author和Book,我可以限制(或分页(Authors的结果,但不能限制其相关实体Books的结果数量,Books总是显示整个集合。

问题是,作者可能有数百本书,使生成的JSON庞大而繁重,因此我试图只获取最后5本书。

我确信我遗漏了一些东西,因为我认为这可能是一种常见的情况,但我在文档上和StackOverflow中都找不到任何东西。

我从Api平台开始,任何提示都将不胜感激!

我最终解决了这个问题,为实体创建了一个规范化器,但我仍然认为它必须是一个更简单的解决方案。

以下是我必须做的,以作者/图书为例:

向Author实体添加setter以覆盖Author的图书集合:

// src/Entity/Author.php
<?php
namespace AppEntity;
use DoctrineORMMapping as ORM;
// ...
/**
* @ApiResource
* @ORMEntity(repositoryClass="AppRepositoryAuthorRepository")
*/
class Author
{
/**
* @ORMId()
* @ORMGeneratedValue()
* @ORMColumn(type="integer")
*/
private $id;
/**
* @ORMColumn(type="string", length=255)
*/
private $name;
/**
* @ORMOneToMany(targetEntity="AppEntityBook", 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 AppSerializerNormalizer;
use ApiPlatformCoreApiIriConverterInterface;
use ApiPlatformCoreSerializerAbstractItemNormalizer;
use DoctrineCommonCollectionsArrayCollection;
use SymfonyComponentSerializerNormalizerDenormalizerInterface;
use SymfonyComponentSerializerNormalizerNormalizerInterface;
use SymfonyComponentSerializerSerializerAwareInterface;
use SymfonyComponentSerializerSerializerAwareTrait;
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 AppEntityAuthor;
}
}

最后手动将规范化器注册为服务(使用autowire导致我出现循环引用问题(:

services:
AppSerializerNormalizerAuthorNormalizer:
autowire: false
autoconfigure: true
arguments:
$normalizer: '@api_platform.jsonld.normalizer.item'
$iriConverter: '@ApiPlatformCoreApiIriConverterInterface'

最新更新