Api-Platform:使用PUT创建资源

时间:2018-04-11 06:02:36

标签: symfony api-platform.com

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

  • on PUT / api / myresource / 4dc6efae-1edd-4f46-b2fe-f00c968fd881如果此资源存在,请更新
  • on PUT / api / myresource / 4dc6efae-1edd-4f46-b2fe-f00c968fd881如果此资源不存在,请创建

可以通过实施ItemDataProviderInterface / RestrictedDataProviderInterface来实现这一目标。

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

我的构造函数如下所示:

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

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

有什么想法吗?

1 个答案:

答案 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"

希望它有所帮助。 :)

更多信息: