View source
<?php
namespace Drupal\jsonrpc\Controller;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Cache\CacheableJsonResponse;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\CacheableResponseInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\jsonrpc\Exception\JsonRpcException;
use Drupal\jsonrpc\Shaper\RpcRequestFactory;
use Drupal\jsonrpc\Shaper\RpcResponseFactory;
use Shaper\Util\Context;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class HttpController extends ControllerBase {
protected $handler;
protected $validator;
protected $container;
public function __construct(ContainerInterface $container) {
$this->handler = $container
->get('jsonrpc.handler');
$this->validator = $container
->get('jsonrpc.schema_validator');
$this->container = $container;
}
public static function create(ContainerInterface $container) {
return new static($container);
}
public function resolve(Request $http_request) {
try {
$rpc_requests = $this
->getRpcRequests($http_request);
} catch (JsonRpcException $e) {
return $this
->exceptionResponse($e, Response::HTTP_BAD_REQUEST);
}
try {
$rpc_responses = $this
->getRpcResponses($rpc_requests);
if (empty($rpc_responses)) {
return CacheableJsonResponse::create(NULL, Response::HTTP_NO_CONTENT);
}
$is_batched_response = count($rpc_requests) !== 1 || $rpc_requests[0]
->isInBatch();
return $this
->getHttpResponse($rpc_responses, $is_batched_response);
} catch (JsonRpcException $e) {
return $this
->exceptionResponse($e, Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
protected function getRpcRequests(Request $http_request) {
$version = $this->handler
->supportedVersion();
try {
if ($http_request
->getMethod() === Request::METHOD_POST) {
$content = Json::decode($http_request
->getContent(FALSE));
}
elseif ($http_request
->getMethod() === Request::METHOD_GET) {
$content = Json::decode($http_request->query
->get('query'));
}
$context = new Context([
RpcRequestFactory::REQUEST_VERSION_KEY => $version,
]);
$factory = new RpcRequestFactory($this->handler, $this->container, $this->validator);
return $factory
->transform($content, $context);
} catch (\Exception $e) {
$id = isset($content) && is_object($content) && isset($content->id) ? $content->id : FALSE;
throw JsonRpcException::fromPrevious($e, $id, $version);
}
}
protected function getRpcResponses(array $rpc_requests) {
$rpc_responses = $this->handler
->batch($rpc_requests);
return empty($rpc_responses) ? NULL : $rpc_responses;
}
protected function getHttpResponse(array $rpc_responses, $is_batched_response) {
try {
$serialized = $this
->serializeRpcResponse($rpc_responses, $is_batched_response);
$http_response = CacheableJsonResponse::fromJsonString($serialized, Response::HTTP_OK);
$cache_context = (new CacheableMetadata())
->setCacheContexts([
'url.query_args:query',
]);
$http_response
->addCacheableDependency($cache_context);
return array_reduce($rpc_responses, function (CacheableResponseInterface $http_response, $response) {
return $http_response
->addCacheableDependency($response);
}, $http_response);
} catch (\Exception $e) {
throw JsonRpcException::fromPrevious($e, FALSE, $this->handler
->supportedVersion());
}
}
protected function serializeRpcResponse(array $rpc_responses, $is_batched_response) {
$context = new Context([
RpcResponseFactory::RESPONSE_VERSION_KEY => $this->handler
->supportedVersion(),
RpcRequestFactory::REQUEST_IS_BATCH_REQUEST => $is_batched_response,
]);
$data = array_values($rpc_responses);
$normalizer = new RpcResponseFactory($this->validator);
return Json::encode($normalizer
->transform($data, $context));
}
protected function exceptionResponse(JsonRpcException $e, $status = Response::HTTP_INTERNAL_SERVER_ERROR) {
$context = new Context([
RpcResponseFactory::RESPONSE_VERSION_KEY => $this->handler
->supportedVersion(),
RpcRequestFactory::REQUEST_IS_BATCH_REQUEST => FALSE,
]);
$normalizer = new RpcResponseFactory($this->validator);
$rpc_response = $e
->getResponse();
$serialized = Json::encode($normalizer
->transform([
$rpc_response,
], $context));
$response = CacheableJsonResponse::fromJsonString($serialized, $status);
return $response
->addCacheableDependency($rpc_response);
}
}