wotapi-8.x-1.x-dev/src/Controller/HttpController.php

src/Controller/HttpController.php
<?php

namespace Drupal\wotapi\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\wotapi\Exception\WotapiActionException;
use Drupal\wotapi\Shaper\RpcRequestFactory;
use Shaper\Util\Context;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * The main front controller.
 *
 * Handles all the incoming requests HTTP requests and responses.
 */
class HttpController extends ControllerBase {

  /**
   * The RPC handler service.
   *
   * @var \Drupal\wotapi\HandlerInterface
   */
  protected $handler;

  /**
   * The JSON Schema validator service.
   *
   * @var \JsonSchema\Validator
   */
  protected $validator;

  /**
   * The service container.
   *
   * @var \Symfony\Component\DependencyInjection\ContainerInterface
   */
  protected $container;

  /**
   * HttpController constructor.
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
   *   The service container.
   */
  public function __construct(ContainerInterface $container) {
    $this->handler = $container->get('wotapi_action.handler');
    $this->validator = $container->get('wotapi_action.schema_validator');
    $this->container = $container;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container);
  }

  /**
   * Resolves an RPC request over HTTP.
   *
   * @param \Symfony\Component\HttpFoundation\Request $http_request
   *   The HTTP request.
   *
   * @return \Drupal\Core\Cache\CacheableResponseInterface
   *   The HTTP response.
   */
  public function resolve(Request $http_request) {
    // Map the HTTP request to an RPC request.
    try {
      $rpc_requests = $this->getRpcRequests($http_request);
    }
    catch (WotapiActionException $e) {
      return $this->exceptionResponse($e, Response::HTTP_BAD_REQUEST);
    }

    // Execute the RPC request and get the RPC response.
    try {
      $rpc_responses = $this->getRpcResponses($rpc_requests);

      // If no RPC response(s) were generated (happens if all of the request(s)
      // were notifications), then return a 204 HTTP response.
      if (empty($rpc_responses)) {
        return CacheableJsonResponse::create(NULL, Response::HTTP_NO_CONTENT);
      }

      // Map the RPC response(s) to an HTTP response.
      //      $is_batched_response = count($rpc_requests) !== 1 || $rpc_requests[0]->isInBatch();
      return $this->getHttpResponse($rpc_responses, TRUE);
    }
    catch (WotapiActionException $e) {
      return $this->exceptionResponse($e, Response::HTTP_INTERNAL_SERVER_ERROR);
    }
  }

  /**
   * Get the JSON RPC request objects for the given Request object.
   *
   * @param \Symfony\Component\HttpFoundation\Request $http_request
   *   The HTTP request.
   *
   * @return \Drupal\wotapi\Object\Request[]
   *   The JSON-RPC request or requests.
   *
   * @throws \Drupal\wotapi\Exception\WotapiActionException
   *   When there was an error handling the response.
   */
  protected function getRpcRequests(Request $http_request) {
    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([]);
      $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 WotapiActionException::fromPrevious($e, $id);
    }
  }

  /**
   * Get the JSON RPC request objects for the given JSON RPC request objects.
   *
   * @param \Drupal\wotapi\Object\Request[] $rpc_requests
   *   The RPC request objects.
   *
   * @return \Drupal\wotapi\Object\Response[]|null
   *   The JSON-RPC response(s). NULL when the RPC request contains only
   *   notifications.
   *
   * @throws \Drupal\wotapi\Exception\WotapiActionException
   */
  protected function getRpcResponses(array $rpc_requests) {
    $rpc_responses = $this->handler->batch($rpc_requests);
    return empty($rpc_responses)
      ? NULL
      : $rpc_responses;
  }

  /**
   * Map RPC response(s) to an HTTP response.
   *
   * @param \Drupal\wotapi\Object\Response[] $rpc_responses
   *   The RPC responses.
   * @param bool $is_batched_response
   *   True if the response is batched.
   *
   * @return \Drupal\Core\Cache\CacheableResponseInterface
   *   The cacheable HTTP version of the RPC response(s).
   *
   * @throws \Drupal\wotapi\Exception\WotapiActionException
   */
  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);
      // Varies the response based on the 'query' parameter.
      $cache_context = (new CacheableMetadata())
        ->setCacheContexts(['url.query_args:query']);
      $http_response->addCacheableDependency($cache_context);
      // Adds the cacheability information of the RPC response(s) to the HTTP
      // response.
      return array_reduce($rpc_responses, function (CacheableResponseInterface $http_response, $response) {
        return $http_response->addCacheableDependency($response);
      }, $http_response);
    }
    catch (\Exception $e) {
      throw WotapiActionException::fromPrevious($e, FALSE);
    }
  }

  /**
   * Serializes the RPC response object into JSON.
   *
   * @param \Drupal\wotapi\Object\Response[] $rpc_responses
   *   The response objects.
   * @param bool $is_batched_response
   *   True if this is a batched response.
   *
   * @return string
   *   The serialized JSON-RPC response body.
   */
  protected function serializeRpcResponse(array $rpc_responses, $is_batched_response) {
    // This following is needed to prevent the serializer from using array
    // indices as JSON object keys like {"0": "foo", "1": "bar"}.
    $data = array_values($rpc_responses);
    // $normalizer = $this->validator;
    //    return Json::encode($normalizer->transform($data, $context));
    return Json::encode($data);
  }

  /**
   * Generates the expected response for a given exception.
   *
   * @param \Drupal\wotapi\Exception\WotapiActionException $e
   *   The exception that generates the error response.
   * @param int $status
   *   The response HTTP status.
   *
   * @return \Drupal\Core\Cache\CacheableResponseInterface
   *   The response object.
   */
  protected function exceptionResponse(WotapiActionException $e, $status = Response::HTTP_INTERNAL_SERVER_ERROR) {
    $context = new Context([
      RpcRequestFactory::REQUEST_IS_BATCH_REQUEST => FALSE,
    ]);
    $normalizer = $this->validator;
    $rpc_response = $e->getResponse();
    $serialized = Json::encode($normalizer->transform([$rpc_response], $context));
    $response = CacheableJsonResponse::fromJsonString($serialized, $status);
    return $response->addCacheableDependency($rpc_response);
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc