我正在开发一个symfony/api平台应用程序,允许用户跟踪体育比赛。我的实体看起来像这样(为简洁起见,将其缩短):
用户.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平台的endpoint,如/api/用户/{id}/统计
或/api/统计/{userId}
,它动态获取数据并显示用户在哪个运动中打了多少场比赛,在什么位置,以及用户赢了/平了/输了多少场比赛。理想情况下,endpoint将允许按运动过滤,看起来像/api/用户/{id}/统计?运动[]=足球
因为这些统计信息不会作为实体持久化到数据库中,所以我尝试了一种类似于没有任何路由留档页面的公开模型的方法。我创建了一个
统计
实体,如下所示:
/**
* @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;
}
并向
用户
实体添加了自定义操作:
* @ApiResource(
* ...
* itemOperations={
* "get_statistic"={
* "method"="GET",
* "path"="/users/{id}/statistics",
* }
* },
* ...
*/
然而,我不确定如何通过运动、位置和赢/平/输实现过滤。据我所知,“普通”过滤器不起作用,因为它只适用于集合的get操作。
如果这是可能的,我将如何在我的 API 中实现它?我已经尝试了自定义数据提供程序和控制器,但我无法在任一解决方案中获取过滤器查询参数,并且“普通”过滤器(如 SearchFilter 中内置的 api 平台)不起作用,因为它仅适用于集合的 get 操作,并且我正在处理一个项目。
这当然是可能的,但取决于你的选择,你需要做更多的工作来获得期望的结果。
我将使用自定义操作,因为这更容易解释,而且我已经有了一些代码示例。
要获取过滤所需的信息,您需要使用较低级别的方法。您错过的关键部分是API平台构建在Symfony之上,因此您可以使用请求
(用于自定义操作)或请求堆栈
(用于数据提供者)来获取过滤器。
此外,为了确保 API 平台知道如何序列化您输出的数据(统计
对象),您需要使用 DTO。
代码如下所示:
在您的实体上,我们添加自定义操作类并将输出指定为 Statistics 类:
* @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配置,正如托比亚斯·英戈尔德在下面的评论中指出的那样。
您可以使用 PHP 并创建规范化程序来执行此操作,如文档的覆盖 OpenAPI 配置部分中所述。
这也可以通过扩展< code>APIResource注释来实现,下面是一个示例:
* @ApiResource(
* ...
* collectionOperations={
* "post",
* "get"={
* "openapi_context"={
* "parameters"={
* {
* "name": "<query_string_param_name>",
* "type": "string",
* "in": "query",
* "required": false,
* "description": "description",
* "example": ""
* }
* }
* }
* }
* }
* ...
* })
我发现这种方法更容易使用,但是没有文档记录。我是根据我的OpenAPI规范知识和官方文档中配置接收上传文件的实体的例子推断出来的。
本文向大家介绍django 自定义过滤器的实现,包括了django 自定义过滤器的实现的使用技巧和注意事项,需要的朋友参考一下 自定义模版过滤器 虽然DTL给我们内置了许多好用的过滤器。但是有些时候还是不能满足我们的需求。因此Django给我们提供了一个接口,可以让我们自定义过滤器,实现自己的需求。 模版过滤器必须要放在app中,并且这个app必须要在INSTALLED_APPS中进行安装。然后再
我正在Google云平台上运行Hadoop集群,使用Google云存储作为持久数据的后端。我能够从远程机器ssh到主节点,并运行hadoop fs命令。无论如何,当我尝试执行以下代码时,我得到了一个超时错误。 密码 执行hdfs.exists()命令时,我得到一个超时错误。 错误 组织。阿帕奇。hadoop。网ConnectTimeoutException:来自gl051-win7/192的调用。
演示在网关追加一个header public class CustomFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 演示在网关追加heade
SOFARPC 提供了一套良好的可扩展性机制,为各个模块提供 SPI 的能力。 SOFARPC 对请求与响应的过滤链处理方式是通过多个过滤器 Filter 来进行具体的拦截处理,该部分可由用户自定义 Filter 扩展,自定义 Filter 的执行顺序在内置 Filter 之后。具体方式如下: Bolt Filter 新建自定义 Filter 。 public class CustomFilter
有什么建议吗?
我必须滚动到recyclerview中的特定项目。 首先,我需要通过匹配从活动传递给适配器的字符串来获取项的位置。然后聚焦到该项目的位置。 例如,在适配器中有一个存储了EventID的TextView,我将把一个字符串从activity传递给适配器,使其与EventID匹配,然后获取该项目的位置,并将焦点/滚动设置到该特定位置。我在适配器中定义了一个方法来获取项的位置,但我不知道如何从活动中调用它