api-platform.com - 根据经过身份验证的用户自动过滤属性
问题描述
我有一个名为事件的实体,该事件可以有很多房间,一个房间可以有很多参与者。如果我访问所有事件(与特定用户),我可以使用扩展过滤用户没有访问权限的事件(没有与特定用户连接的空间)。
这很好用。响应包含至少有一个房间具有访问权限的所有事件。
但是如果活动有多个房间并且用户只能访问一个房间。响应包括两个房间。我创建了一个 RoomExtension,但不会调用这个类。
谢谢
解决方案
您的问题是由于过滤器和扩展仅适用于检索主要实体的查询。使用 Doctrine 关联检索相关实体,该关联是域模型的一部分,旨在成为所有目的的单一事实来源。您需要的是该模型的用户特定视图,在 api 的上下文中通常由 DTO 组成。
我认为基本上有两种解决方案:
- 主要查询事件并将其转换为 EventDTO,然后查询或过滤掉相关的房间,
- 主要查询房间,然后将它们分组到 EventDTO。
我在这里解释第二个解决方案,因为我猜它更简单,它应该让你的 RoomExtension 开箱即用,这使它更适合你的问题,但也因为我碰巧在教程中构建和测试了类似的东西因此,自信地写下答案的工作量要少得多。
这个解决方案的缺点是它不支持分页。
因为这个解决方案主要是查询房间,操作是在房间资源上的。如果它是 Room 的唯一 collectionOperation 可能是这样的:
(..)
* @ApiResource(
* collectionOperations={
* "get_accessible_events"={
* "method"="GET",
* "path"="/rooms/accessible-events",
* "output"=EventDTO::class,
* "pagination_enabled"=false
* }
* }
* }
*/
class Room {
(..)
(这不一定是你唯一的收藏操作,你仍然可以有“get”、“post”等)。
现在这仍然会产生一个平面的房间集合,你需要将它们分组到 EventDTO 中。文档的DTO 页面建议使用 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。
但是,在 swagger 文档中,get_accessible_events 操作摘要和描述仍然来自 Room。您可以查看如何在文档中添加 SwaggerDecorator 或查看教程的 chapter9-api 分支。后者还包含实体的完整解释和测试代码、DTO(报告模型)和仅显示用户被授权的数据的扩展,但不是针对您的问题而定制的,并且所有这些都超出了重点回答。
关于其他解决方案,我无法在此站点上向您提供更多提示,因为该站点可能会将它们视为不完整或不清楚的答案,并因此而惩罚我。
推荐阅读
- sass - Bootstrap 5 + SASS 错误:未定义的 MIXIN @include _assert-ascending
- amazon-cloudfront - 使用 Amazon S3 和 CloudFront 托管单页应用程序时出现问题:如何区分 403 与 S3 与 403 与后端服务?
- excel - 如何在 Visual Studio 中使用 Excel 互操作“查看 Excel 工作表的代码”?
- amazon-web-services - 为什么我的网站在 chrome 中有 HTTPS 而在 safari 中有 HTTP?
- html - CSS中的字体样式
- python - 使用python在excel中复制和粘贴数据(保持源格式)
- c++ - 如何将 svd.MatrixV() 中的最后一列转换为 3 x 3 矩阵?
- html - 如何做一个可拖动的可扩展 div (React, Tailwind)
- sql - 从 Start_Date 创建 End_Date 列
- wordpress - 如何在 Wordpress 的 2 或 3 列中显示博客页面中的帖子?