gpt4 book ai didi

php - 如何在 api 平台中通过过滤实现自定义项获取端点?

转载 作者:行者123 更新时间:2023-12-04 01:19:29 24 4
gpt4 key购买 nike

我正在开发一个允许用户跟踪体育比赛的 symfony/api 平台应用程序。我的实体看起来像这样(为简洁起见缩短):

User.php

class User implements UserInterface
{
// ...

/**
* @ORM\OneToMany(targetEntity=MatchPlayer::class, mappedBy="user")
*/
private $matches;

// ...
}

MatchPlayer.php

class MatchPlayer
{
// ...

/**
* @ORM\ManyToOne(targetEntity=User::class, inversedBy="matches")
* @ORM\JoinColumn(onDelete="SET NULL")
*/
private $user;

/**
* @ORM\ManyToOne(targetEntity=Match::class, inversedBy="players")
*/
private $playedMatch;

/**
* @ORM\ManyToOne(targetEntity=Position::class, inversedBy="matches")
*/
private $position;

// ...
}

匹配.php

class Match
{
// ...

/**
* @ORM\Column(type="smallint")
* @Groups({"match:read"})
*/
private $outcome;

/**
* @ORM\ManyToOne(targetEntity=Sport::class, inversedBy="matches")
*/
private $sport;

/**
* @ORM\OneToMany(targetEntity=MatchPlayer::class, mappedBy="playedMatch", cascade={"persist", "remove"})
*/
private $players;

// ....
}

因此在我的模型中,一个用户可以与多场比赛相关联,而一场比赛可以通过胶水表与许多用户相关联,该胶水表还保存了用户所玩的位置。

现在我想公开一个带有 api 平台的端点,例如 /api/users/{id}/statistics/api/statistics/{userId} 来获取数据动态地显示用户在哪项运动中参加了多少场比赛,处于什么位置,以及用户赢/平/输了多少场比赛。理想情况下,端点将允许按运动进行过滤,例如类似于 /api/users/{id}/statistics?sport[]=football&sport[]&outcome=win

因为这些统计数据不会作为一个实体持久保存到数据库中,所以我尝试了一种类似于 Expose a model without any routes documentation page 的方法.我创建了一个如下所示的 Statistics 实体:

/**
* @ApiResource(
* collectionOperations={},
* itemOperations={
* "get"={
* "controller"=NotFoundAction::class,
* "read"=false,
* "output"=false,
* },
* }
* )
*/
class Statistic
{
/**
* @var User
* @ApiProperty(identifier=true)
*/
public $user;

/**
* @var Position[]|null
*/
public $position = [];

/**
* @var Sport[]|null
*/
public $maps = [];

/**
* @var int
*/
public $wins = 0;

/**
* @var int
*/
public $ties = 0;

/**
* @var int
*/
public $losses = 0;
}

并向 User 实体添加自定义操作:

 * @ApiResource(
* ...
* itemOperations={
* "get_statistic"={
* "method"="GET",
* "path"="/users/{id}/statistics",
* }
* },
* ...
*/

但是我不确定如何按运动项目、位置和胜/平/负进行过滤。据我所知,“普通”过滤器不起作用,因为它仅适用于集合的获取操作。

如果这甚至可能,我将如何在我的 api 中实现它?我已经尝试过自定义数据提供程序和 Controller ,但我无法在任一解决方案中获取过滤器查询参数,并且“普通”过滤器(如 SearchFilter 中内置的 api 平台)将不起作用,因为它仅适用于集合的获取操作,并且我正在处理一个项目。

最佳答案

这绝对是可能的,但根据您的选择,您需要做更多的工作才能获得所需的结果。

我将使用自定义操作,因为这更容易解释,而且我已经有了一些代码示例。

要获得过滤所需的信息,您需要采用较低级别的方法。您错过的关键部分是 API 平台构建在 Symfony 之上,因此您可以只使用 Request(用于自定义操作)或 RequestStack(用于数据提供者)来获取过滤器。

还要确保 API 平台知道如何序列化您正在输出的数据(Statistics 对象),您需要使用 DTO .

代码如下所示:

在您的实体上,我们添加自定义操作类并将输出指定为统计类:

 * @ApiResource(
* ...
* itemOperations={
* "get_statistics"={
* "method"="GET",
* "path"="/users/{id}/statistics",
* "controller"=UserStatsAction::class,
* "input"=Statistics::class
* }
* },
* ...
*/

自定义操作代码示例:

final class UserStatsAction
{
private $em;


public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}

public function __invoke(Request $request)
{
$id = $request->get('id');
$repository = $this->em->getRepository(User::class);
if(!($user = $repository->find($id))) {
throw new NotFoundHttpException();
}

$sports = $request->query->get('sport', []);
$outcome = $request->query->get('outcome');

// Optional: validate your filter data
$validator = Validation::createValidator();
$context = $validator->startContext();
$context->atPath('sports')->validate($sports, [
new Assert\Choice([
'choices' => ['football', 'basketball'],
]),
]);
$context->atPath('outcome')->validate($outcome, [
new Assert\Choice([
'choices' => ['win', 'loose', 'tie'],
]),
]);
$violations = $context->getViolations();

if (0 !== count($violations)) {
throw new ValidationException($violations);
}

// I'll assume you are hnadiling empty/nulls value properly inside this method
// and return all the stats if
$results = $repository->getStatistics($sports, $outcome);

// For this to work, you'll need to set a DTO for your stats
return $results;
}
}

我使用 Request 作为自定义操作的参数,而不是 User 实体。我的示例中有一些您可能不需要的代码,例如从存储库中获取用户或验证过滤器(不过我确实鼓励用户输入清理/验证)。

重要的一点:API 平台不鼓励自定义操作,您将失去对 GraphQL 的支持。如果您需要 GraphQL,可以使用 DataProvider 实现相同的结果,但这是更高级的设置,我需要模拟您应用的某些部分才能弄明白。

希望这对您有所帮助。

更新:

要使过滤器正常工作,您还需要更新 OpenAPI/Swagger 配置,如 tobias ingold在下面的评论中指出。

您可以使用 PHP 并创建规范器来做到这一点,如 Override the OpenAPI speficiation 中所述文档部分。

这也可以通过扩展 APIResource 注释来完成,下面是一个例子:

 * @ApiResource(
* ...
* collectionOperations={
* "post",
* "get"={
* "openapi_context"={
* "parameters"={
* {
* "name": "<query_string_param_name>",
* "type": "string",
* "in": "query",
* "required": false,
* "description": "description",
* "example": ""
* }
* }
* }
* }
* }
* ...
* })

我发现这种方法更易于使用,但没有记录在案。我根据我的 OpenAPI 规范知识和 Configuring the Entity Receiving the Uploaded File 推断出这一点官方文档中的示例。

关于php - 如何在 api 平台中通过过滤实现自定义项获取端点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62816024/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com