Api-平台:使用PUT创建资源

Api-Platform: using PUT for creating resources

我想使用 PUT 方法创建资源。它们由 UUID 标识,并且由于可以在客户端创建 UUID,我想启用以下行为:

可以通过实施 ItemDataProviderInterface / RestrictedDataProviderInterface 来实现。

但是,我的资源实际上是一个子资源,所以假设我想创建一个新的 Book 来引用现有的 Author.

我的构造函数如下所示:

/**
 * Book constructor
 */
public function __construct(Author $author, string $uuid) {
    $this->author = $author;
    $this->id = $uuid;
}

但我不知道如何从我的 BookItemProvider 访问 Author 实体(在请求正文中提供)。

有什么想法吗?

在 API 平台中,项目创建时应发生的许多事情都基于请求的类型。改起来会很麻烦。

这里有 2 种可能性来制作您想要的东西。

首先,你可以考虑做一个自定义路由,使用你自己的逻辑。如果你这样做,你可能会很高兴知道在你的自定义路由上使用选项 _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());
        }
    }
}

并且您需要指定一个配置来将您的 class 声明为服务装饰器:

services:
    CustomReadListener:
        decorate: api_platform.listener.request.read
        arguments:
            - "@CustomReadListener.inner"

希望对您有所帮助。 :)

更多信息: