有两个相关的实体,比如说作者和书,我可以限制(或分页)作者的结果,但不能限制其相关实体书的结果数量,因为书总是显示整个集合。
问题是,作者可能有几百本书籍,这使得生成的JSON庞大而沉重,难以解析,所以我试图只得到,例如,最后5本书。
我确信我漏掉了什么,因为我认为这可能是一种常见的情况,但我在文档中和StackOverflow中都找不到任何东西。
我从Api平台开始,任何提示都将被感激!
我终于解决了这个问题,为实体创建了一个正常化器,但我仍然认为它必须是一个更简单的解决方案。
下面是我必须要做的,按照 Authors Books 的例子。
给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;
}
}
为Author's实体创建一个归一化器。
// 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'