API 平台 - 我应该使用哪种方法来创建没有实体的自定义操作
我是 API 平台的新手.我认为这很棒,但我找不到任何示例如何创建不基于任何实体的自定义端点.有很多基于实体的例子,通常都是关于 CRUD 的.但是自定义操作呢?
I'm new to API Platform. I think it's great but I cannot find any example how to create custom endpoint that isn't based on any entity. There are a lot of examples based on an entity and usually they are all about CRUD. But what about custom operations?
我需要使用一些与任何实体无关的自定义参数通过数据库创建自定义搜索.例如.我想收到这样的 POST 请求:
I need to create custom search through database with some custom parameters which aren't related to any entity. E.g. I want to receive POST request something like this:
{
"from": "Paris",
"to": "Berlin"
}
这个数据没有保存到数据库中,我也没有实体.收到这些数据后,应该有很多业务逻辑,包括通过大量数据库表进行数据库查询以及从外部来源获取数据.然后,在业务逻辑完成后,我想返回结果,该结果也是自定义的,与任何实体无关.例如
This data isn't saved to db and I haven't entity for it. After I receive this data, there should be a lot of business logic including db queries through a lot of db tables and also getting data from external sources. Then, after the business logic is finished, I want to return back result which is also custom and isn't related to any entity. E.g.
{
"flights": [/* a lot of json data*/],
"airports": [/* a lot of json data*/],
"cities": [/* a lot of json data*/],
.......
}
所以,我想我不是唯一一个做类似事情的人.但我真的找不到如何做到这一点的解决方案或最佳实践.在文档中,我找到了至少三种方法,但我无法实现它们中的任何一种.最好的,我想最适合我的是使用自定义操作和控制器.但是文档说不推荐使用这个.此外,我认为我应该将 DTO 用于请求和响应,但对于这种方法,我不确定我是否可以使用它们.
So, I think I'm not the only on who does something similar. But I really cannot find a solution or best practices how to do this. In the documentation I've found at least three approaches and I cannot implement none of them. The best one, I guess the most suitable for me it is using Custom Operations and Controllers. But documentation says this one is not recommended. Also I think I should use DTOs for request and response, but for this approach I'm not sure I can use them.
第二个我发现它使用数据传输对象,但这种方法需要一个实体.根据文档,我应该使用 DTO 和 DataTransformers 将 DTO 转换为实体.但我不需要实体,我不需要将它保存到数据库.我只想自己处理收到的 DTO.
The second one I found it's using Data Transfer Objects, but this approach requires an entity. According to the documentation, I should use DTOs and DataTransformers to convert DTO to an Entity. But I don't need entity, I don't need save it to db. I want just handle received DTO on my own.
我猜第三个是使用数据提供程序,但我不确定它是否适合我的要求.
The third one I guess it is using Data Providers, but I'm not sure it is suitable for my requirements.
因此,主要问题是我应该使用哪种方法或最佳实践来实现与任何实体无关的自定义操作.使用 DTO 进行请求和响应将非常有用.
So, the main question is which approach or best practice should I use to implement custom operation which isn't related to any entity. And it will be great use DTOs for request and response.
您不会被迫使用实体.用 @ApiResource
注释标记的类可能不是实体.实际上,如果您的应用程序比基本 CRUD 更智能,您应该避免将实体标记为 ApiResource.
You are not forced to use entities. Classes that are marked with @ApiResource
annotation may not be entities. Actually, if your application is smarter than basic CRUD you should avoid marking entities as ApiResource.
由于您想使用 POST HTTP 方法(用于创建资源项),您可以执行以下操作.
Since you want to use POST HTTP method (which is for creating resource items) you can do something like this.
1) 定义描述搜索字段的类,这将是您的 @ApiResource
1) Define class describing search fields and which will be your @ApiResource
<?php
// src/ApiResource/Search.php
namespace App\ApiResource;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Action\NotFoundAction;
use ApiPlatform\Core\Annotation\ApiProperty;
use App\Dto\SearchResult;
/**
* @ApiResource(
* itemOperations={
* "get"={
* "controller"=NotFoundAction::class,
* "read"=true,
* "output"=false,
* },
* },
* output=SearchResult::class
* )
*/
class Search
{
/**
* @var string
* @ApiProperty(identifier=true)
*/
public $from;
/** @var string */
public $to;
}
2) 定义将代表输出的 DTO
2) Define DTO that will represent the output
<?php
// src/Dto/SearchResult.php
namespace App\Dto;
class SearchResult
{
public $flights;
public $airports;
public $cities;
}
3) 创建将实现 DataPersisterInterface
以处理业务逻辑的类.框架会调用它,因为您发出 POST 请求.
3) Create class that will inplement DataPersisterInterface
for handling business logic.
It will be called by framework because you make POST request.
<?php
// src/DataPersister/SearchService.php
declare(strict_types=1);
namespace App\DataPersister;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use App\Dto\SearchResult;
use App\ApiResource\Search;
final class SearchService implements DataPersisterInterface
{
public function supports($data): bool
{
return $data instanceof Search;
}
public function persist($data)
{
// here you have access to your request via $data
$output = new SearchResult();
$output->flights = ['a lot of json data'];
$output->airports = ['a lot of json data'];
$output->cities = ['inputData' => $data];
return $output;
}
public function remove($data)
{
// this method just need to be presented
}
}
这样您就可以根据请求收到结果.
That way you will recieve results based on request.