/** * Executes an API resource. * * @param string $method * The HTTP method to call. This will override the method in the current * Request object. * @param string $path * The path to the resource. This will override the path in the current * Request object. * @param array $data * (optional) An array of data to provide to the resource. Any data provided * will override the values in the current Request object. * @param array $headers * (optional) An array of headers to provide to the resource. * * @return JsonResponse * */ public function call($method, $path, array $data = [], array $headers = []) { $resource = restapi_get_resource($path); $method = strtolower($method); if (!$resource) { $message = sprintf('The path "%s" does not match any known resources.', $path); return $this->toError($message, 'not_found', 404); } if (!method_exists($resource->getClass(), $method)) { $message = sprintf('The method "%s" is not available for the resource "%s".', $method, $path); return $this->toError($message, 'not_allowed', 405); } $request = $this->getRequest()->withMethod($method)->withData($data); // Sets the new path, if it is different. $uri = $request->getUri(); if ($path != $uri->getPath()) { $uri = $uri->withPath($path); $request = $request->withUri($uri); } // Set headers on the new request object. foreach ($headers as $key => $value) { $request = $request->withHeader($key, $value); } try { $request = $this->invokeHookRequest($path, $resource, $request); $obj = $resource->invokeResource($this->getUser(), $request); $args = $resource->getArgumentsForPath($path); $obj->before(); $this->handleRequiredParameters($obj, $request); $this->handleAccess($obj, $method, $args); $response = call_user_func_array([$obj, $method], $args); if (!$response instanceof ResponseInterface) { $message = sprintf('%s::%s() must return an instance of ResponseInterface.', $resource->getClass(), $method); throw new Exception($message); } $obj->after($response); } catch (Exception $e) { $response = $this->invokeHookException($e); if (!$response) { $response = $this->toError($e->getMessage()); } } $response = $this->invokeHookResponse($path, $resource, $request, $response); return $response; }
/** * Executes an API resource. * * @param string $method * The HTTP method to call. This will override the method in the current * Request object. * @param string $path * The path to the resource. * @param array $data * An array of data to provide the resource. Any data provided will override * the values in the current Request object. * * @return JsonResponse * */ public function call($method, $path, array $data = []) { $resource = restapi_get_resource($path); $method = strtolower($method); if (!$resource) { $message = sprintf('The path "%s" does not match any known resources.', $path); return $this->toError($message, 'not_found', 404); } if (!method_exists($resource->getClass(), $method)) { $message = sprintf('The method "%s" is not available for the resource "%s".', $method, $path); return $this->toError($message, 'not_allowed', 405); } // We intentionally clone the request for this call to ensure that any // modifications due to a different $method or additional $data does not // affect the state of the global request. $request = clone $this->getRequest(); $request->setMethod($method); $request->setData($data); module_invoke_all('restapi_request', $path, $resource, $request); $obj = $resource->invokeResource($this->getUser(), $request); try { $obj->access($method); $obj->before(); $args = $resource->getArgumentsForPath($path); $response = call_user_func_array([$obj, $method], $args); if (!$response instanceof JsonResponse) { $message = sprintf('%s::%s() must return an instance of Response.', $resource->getClass(), $method); throw new Exception($message); } $obj->after($response); } catch (RestApiException $e) { $response = $this->toError($e->getMessage(), (string) $e, $e->getCode()); } catch (Exception $e) { $response = $this->toError($e->getMessage()); } module_invoke_all('restapi_response', $path, $resource, clone $request, $response); return $response; }