我有一个称为事件的实体,该事件可以有很多房间,一个房间可以有很多参与者。 如果我(使用特定用户)访问所有事件,则可以使用扩展程序过滤用户没有访问权限(没有与特定用户连接的空间)的事件。
那很好。 响应包含具有至少一个具有访问权限的房间的所有事件。
但是,如果事件有多个房间,并且用户只能访问一个房间。响应包括两个房间。我创建了RoomExtension,但是不会调用此类。
谢谢
答案 0 :(得分:0)
您的问题是由以下事实引起的:过滤器和扩展名仅适用于检索主要实体的查询。使用学说关联来检索相关实体,这是领域模型的一部分,该学说旨在为所有目的提供单一的真理来源。您需要的是该模型的用户特定视图,在api的上下文中,该视图通常由DTO组成。
我认为基本上有两种解决方案:
我在这里解释第二种解决方案是因为我猜它是simpeler,它应该使您的RoomExtension开箱即用,这使其更适合您的问题,而且还因为我碰巧已经构建并测试了类似的东西tutorial中的内容,因此自信地编写答案要花很多时间。
此解决方案的缺点是它不支持分页。
因为此解决方案主要查询“房间”,所以操作在“房间”资源上。如果它是唯一的RoomOperationOperation,则可能是这样的:
(..)
* @ApiResource(
* collectionOperations={
* "get_accessible_events"={
* "method"="GET",
* "path"="/rooms/accessible-events",
* "output"=EventDTO::class,
* "pagination_enabled"=false
* }
* }
* }
*/
class Room {
(..)
(这不必是您唯一的collectionOperation,您仍然可以有“ get”,“ post”等)。
现在,这仍然会产生一个平面的房间集合,您需要将它们分组为EventDTO。 DTOs page of the docs建议制作一个DataTransformer来生成DTO,但这仅在您的DTO与查询检索的实体一对一的情况下才有效。但是CollectionDataProvider可以解决问题。因为您不需要调整查询本身,所以可以简单地修饰默认的CollectionDataProvider服务:
namespace App\DataProvider;
use ApiPlatform\Core\Api\OperationType;
use App\DTO\EventDTO;
use ApiPlatform\Core\DataProvider\ContextAwareCollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
use App\Entity\Room;
class RoomAccessibleEventCollectionDataProvider implements ContextAwareCollectionDataProviderInterface, RestrictedDataProviderInterface
{
/** @var CollectionDataProviderInterface */
private $dataProvider;
/**
* @param CollectionDataProviderInterface $dataProvider The built-in orm CollectionDataProvider of API Platform
*/
public function __construct(CollectionDataProviderInterface $dataProvider)
{
$this->dataProvider = $dataProvider;
}
/**
* {@inheritdoc}
*/
public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
{
return Room::class === $resourceClass
&& $operationName == 'get_accessible_events';
}
/**
* {@inheritdoc}
*/
public function getCollection(string $resourceClass, string $operationName = null, array $context = []): array
{
$rooms = $this->dataProvider->getCollection($resourceClass, $operationName, $context);
$dtos = [];
foreach ($rooms as $room) {
$key = $room->getId();
if (isset($dtos[$key])) {
$dtos[$key]->addRoom($room);
} else {
$dto = new EventDTO($room->getEvent());
$dto->addRoom($room);
$dtos[$key] = $dto;
}
}
return $dtos;
}
}
您确实需要在config / services.yaml中配置服务:
“ App \ DataProvider \ RoomAccessibleEventCollectionDataProvider”: 参数: $ dataProvider:“ @ api_platform.doctrine.orm.default.collection_data_provider”
这不会取代默认的CollectionDataProvider,而是添加另一个将注入默认的CollectionDataProvider。
我想您现在可以自己制作EventDTO类。然后它应该工作。在“会议室”上定义的过滤器也将照常工作,例如,如果可以按事件的日期对会议室进行过滤?event.date [gte] = 2020-10-10将仅查找在2020-10-10或之后发生事件的会议室并返回他们的EventDTO。
但是,在庞大的文档中,get_accessible_events操作摘要和描述仍然来自Room。您可以查看如何在文档中添加SwaggerDecorator或查看tutorial的Chapter9-api分支。后者还包含针对实体的完整说明和经过测试的代码,DTO(报告模型),以及仅用于显示用户被授权但并非针对您的问题的扩展名,总之超出了重点。答案。
关于其他解决方案,我无法在此站点上给您任何提示,因为该站点可能会将它们视为不完整或不清楚的答案,并为此惩罚我。