如何在API Platform中让Question仅嵌入5条最新Answer(GET操作)
API Platform 实现问题关联答案的两种获取方式
问题背景
现有 Question 和 Answer 两个实体,ORM 关联关系如下:
Question 实体代码
#[ApiResource] class Question { //... #[ORM\OneToMany(mappedBy: "question", targetEntity: Answer::class)] private Collection $answers; }
Answer 实体代码
#[ApiResource] class Answer { //... #[ORM\ManyToOne(inversedBy: 'answers')] #[ORM\JoinColumn(nullable: false)] private Question $question; }
需求:
- 获取
Question详情时,仅嵌入5条最新的Answer - 同时提供独立端点,支持分页获取某
Question的所有Answer
解决方案
1. 为 Question 添加「最新5条答案」的嵌入字段
直接修改原有 $answers 字段会干扰全量查询,建议新增专门字段(如 latestAnswers)承载需求:
#[ApiResource] class Question { // 原有关联,保留用于全量查询 #[ORM\OneToMany(mappedBy: "question", targetEntity: Answer::class)] private Collection $answers; // 新增字段:返回最新5条答案,嵌入到Question详情 #[ApiProperty(readableLink: false)] public function getLatestAnswers(): Collection { // 按创建时间倒序排序后取前5条 return $this->answers->sort(function (Answer $a, Answer $b) { return $b->getCreatedAt() <=> $a->getCreatedAt(); })->slice(0, 5); } }
注意:需确保
Answer实体包含createdAt(或类似时间戳字段)及对应的 getter 方法,若没有需先添加ORM映射。
2. 配置 Answer 端点,支持按 Question 过滤+分页
在 Answer 的 ApiResource 注解中开启分页和字段过滤:
use ApiPlatform\Metadata\ApiFilter; use ApiPlatform\Doctrine\Orm\Filter\SearchFilter; use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\GetCollection; #[ApiResource( operations: [ new GetCollection( paginationEnabled: true, paginationItemsPerPage: 10 // 默认每页10条,可通过URL参数覆盖 ) ] )] #[ApiFilter(SearchFilter::class, properties: ['question' => 'exact'])] class Answer { //... #[ORM\ManyToOne(inversedBy: 'answers')] #[ORM\JoinColumn(nullable: false)] private Question $question; #[ORM\Column(type: 'datetime_immutable')] private \DateTimeImmutable $createdAt; public function getCreatedAt(): \DateTimeImmutable { return $this->createdAt; } }
3. 验证效果
- 获取 Question 详情时,响应会包含
latestAnswers字段,返回5条最新答案 - 调用
GET /answers?question=<QuestionID>即可分页获取该问题的所有答案,可通过page和itemsPerPage参数自定义分页规则
性能优化(可选)
若答案数量庞大,内存排序会有性能损耗,可改用ORM自定义查询实现:
步骤1:修改 Question 实体关联
#[ApiResource] class Question { //... #[ORM\OneToMany(mappedBy: "question", targetEntity: Answer::class)] private Collection $answers; #[ORM\OneToMany(mappedBy: "question", targetEntity: Answer::class)] #[ORM\OrderBy(['createdAt' => 'DESC'])] #[ApiProperty(readableLink: false)] private Collection $latestAnswers; public function __construct() { $this->answers = new ArrayCollection(); $this->latestAnswers = new ArrayCollection(); } }
步骤2:配置 Question 详情使用自定义Repository
use ApiPlatform\Metadata\Get; use App\Repository\QuestionRepository; #[ApiResource( operations: [ new Get( provider: [QuestionRepository::class, 'findOneByIdWithLatestAnswers'] ) ] )] class Question { //... }
步骤3:实现 Repository 查询方法
class QuestionRepository extends ServiceEntityRepository { //... public function findOneByIdWithLatestAnswers(int $id): ?Question { return $this->createQueryBuilder('q') ->leftJoin('q.latestAnswers', 'a') ->where('q.id = :id') ->setParameter('id', $id) ->setMaxResults(5) ->getQuery() ->getOneOrNullResult(); } }
内容的提问来源于stack exchange,提问作者Osmanys Fuentes-Lombá
相关产品推荐
相关产品推荐

