我想使用PUT方法来创建资源。它们由UUID标识,并且由于可以在客户端创建UUID,我想启用以下行为:
可以通过实施ItemDataProviderInterface
/ RestrictedDataProviderInterface
来实现这一目标。
但是,我的资源实际上是一个子资源,所以我想说我想创建一个引用现有Book
的新Author
。
我的构造函数如下所示:
/**
* Book constructor
*/
public function __construct(Author $author, string $uuid) {
$this->author = $author;
$this->id = $uuid;
}
但我不知道如何从我的Author
访问BookItemProvider
实体(在请求正文中提供)。
有什么想法吗?
答案 0 :(得分:1)
在API平台中,项目创建时应该发生的许多事情都是基于它的请求类型。改变会很复杂。
这有两种可能性来制作你想要的东西。
首先,您可以考虑执行自定义路由并使用自己的逻辑。如果你这样做,你可能会很高兴知道在你的自定义路线上使用选项_api_resource_class
将启用APIPlaform的一些听众并避免你做一些工作。
如果您需要全局行为,第二种解决方案是覆盖API平台。你遇到的主要问题是ApiPlatform的ReadListener
如果无法找到你的资源就会抛出异常。此代码可能无效,但以下是如何覆盖此行为的想法:
class CustomReadListener
{
private $decoratedListener;
public function __construct($decoratedListener)
{
$this->decoratedListener = $decoratedListener;
}
public function onKernelRequest(GetResponseEvent $event)
{
try {
$this->decoratedListener->onKernelRequest($event);
} catch (NotFoundHttpException $e) {
// Don't forget to throw the exception if the http method isn't PUT
// else you're gonna break the 404 errors
$request = $event->getRequest();
if (Request::METHOD_PUT !== $request->getMethod()) {
throw $e;
}
// 2 solutions here:
// 1st is doing nothing except add the id inside request data
// so the deserializer listener will be able to build your object
// 2nd is to build the object, here is a possible implementation
// The resource class is stored in this property
$resourceClass = $request->attributes->get('_api_resource_class');
// You may want to use a factory? Do your magic.
$request->attributes->set('data', new $resourceClass());
}
}
}
您需要指定一个配置来将您的类声明为服务装饰器:
services:
CustomReadListener:
decorate: api_platform.listener.request.read
arguments:
- "@CustomReadListener.inner"
希望它有所帮助。 :)
更多信息: