vendor/overblog/graphql-bundle/src/Request/Executor.php line 157

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Overblog\GraphQLBundle\Request;
  4. use ArrayObject;
  5. use Closure;
  6. use GraphQL\Executor\ExecutionResult;
  7. use GraphQL\Executor\Promise\PromiseAdapter;
  8. use GraphQL\GraphQL;
  9. use GraphQL\Type\Schema;
  10. use GraphQL\Validator\DocumentValidator;
  11. use GraphQL\Validator\Rules\DisableIntrospection;
  12. use GraphQL\Validator\Rules\QueryComplexity;
  13. use GraphQL\Validator\Rules\QueryDepth;
  14. use Overblog\GraphQLBundle\Event\Events;
  15. use Overblog\GraphQLBundle\Event\ExecutorArgumentsEvent;
  16. use Overblog\GraphQLBundle\Event\ExecutorContextEvent;
  17. use Overblog\GraphQLBundle\Event\ExecutorResultEvent;
  18. use Overblog\GraphQLBundle\Executor\ExecutorInterface;
  19. use RuntimeException;
  20. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  21. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  22. use function array_keys;
  23. use function is_callable;
  24. use function sprintf;
  25. class Executor
  26. {
  27.     public const PROMISE_ADAPTER_SERVICE_ID 'overblog_graphql.promise_adapter';
  28.     private array $schemas = [];
  29.     private EventDispatcherInterface $dispatcher;
  30.     private PromiseAdapter $promiseAdapter;
  31.     private ExecutorInterface $executor;
  32.     private bool $useExperimentalExecutor// TODO: remove in 1.0
  33.     /**
  34.      * @var callable|null
  35.      */
  36.     private $defaultFieldResolver;
  37.     public function __construct(
  38.         ExecutorInterface $executor,
  39.         PromiseAdapter $promiseAdapter,
  40.         EventDispatcherInterface $dispatcher,
  41.         ?callable $defaultFieldResolver null,
  42.         bool $useExperimental false // TODO: remove in 1.0
  43.     ) {
  44.         $this->executor $executor;
  45.         $this->promiseAdapter $promiseAdapter;
  46.         $this->dispatcher $dispatcher;
  47.         $this->defaultFieldResolver $defaultFieldResolver;
  48.         $this->useExperimentalExecutor $useExperimental// TODO: remove in 1.0
  49.     }
  50.     public function setExecutor(ExecutorInterface $executor): self
  51.     {
  52.         $this->executor $executor;
  53.         return $this;
  54.     }
  55.     public function addSchemaBuilder(string $nameClosure $builder): self
  56.     {
  57.         $this->schemas[$name] = $builder;
  58.         return $this;
  59.     }
  60.     public function addSchema(string $nameSchema $schema): self
  61.     {
  62.         $this->schemas[$name] = $schema;
  63.         return $this;
  64.     }
  65.     public function getSchema(string $name null): Schema
  66.     {
  67.         if (empty($this->schemas)) {
  68.             throw new RuntimeException('At least one schema should be declare.');
  69.         }
  70.         if (null === $name) {
  71.             $name = isset($this->schemas['default']) ? 'default' array_key_first($this->schemas);
  72.         }
  73.         if (!isset($this->schemas[$name])) {
  74.             throw new NotFoundHttpException(sprintf('Could not found "%s" schema.'$name));
  75.         }
  76.         $schema $this->schemas[$name];
  77.         if (is_callable($schema)) {
  78.             $schema $schema();
  79.             $this->addSchema((string) $name$schema);
  80.         }
  81.         return $schema;
  82.     }
  83.     public function getSchemasNames(): array
  84.     {
  85.         return array_keys($this->schemas);
  86.     }
  87.     public function setMaxQueryDepth(int $maxQueryDepth): void
  88.     {
  89.         /** @var QueryDepth $queryDepth */
  90.         $queryDepth DocumentValidator::getRule(QueryDepth::class);
  91.         $queryDepth->setMaxQueryDepth($maxQueryDepth);
  92.     }
  93.     public function setMaxQueryComplexity(int $maxQueryComplexity): void
  94.     {
  95.         /** @var QueryComplexity $queryComplexity */
  96.         $queryComplexity DocumentValidator::getRule(QueryComplexity::class);
  97.         $queryComplexity->setMaxQueryComplexity($maxQueryComplexity);
  98.     }
  99.     public function enableIntrospectionQuery(): void
  100.     {
  101.         DocumentValidator::addRule(new DisableIntrospection(DisableIntrospection::DISABLED));
  102.     }
  103.     public function disableIntrospectionQuery(): void
  104.     {
  105.         DocumentValidator::addRule(new DisableIntrospection());
  106.     }
  107.     /**
  108.      * @param array|ArrayObject|object|null $rootValue
  109.      */
  110.     public function execute(?string $schemaName, array $request$rootValue null): ExecutionResult
  111.     {
  112.         // TODO: remove following if-block in 1.0
  113.         if (method_exists(GraphQL::class, 'useExperimentalExecutor')) {
  114.             $this->useExperimentalExecutor GraphQL::useExperimentalExecutor() : GraphQL::useReferenceExecutor();
  115.         }
  116.         $schema $this->getSchema($schemaName);
  117.         /** @var string $schemaName */
  118.         $schemaName array_search($schema$this->schemas);
  119.         $executorArgumentsEvent $this->preExecute(
  120.             $schemaName,
  121.             $schema,
  122.             $request[ParserInterface::PARAM_QUERY] ?? null,
  123.             new ArrayObject(),
  124.             $rootValue,
  125.             $request[ParserInterface::PARAM_VARIABLES],
  126.             $request[ParserInterface::PARAM_OPERATION_NAME] ?? null
  127.         );
  128.         $executorArgumentsEvent->getSchema()->processExtensions();
  129.         $result $this->executor->execute(
  130.             $this->promiseAdapter,
  131.             $executorArgumentsEvent->getSchema(),
  132.             $executorArgumentsEvent->getRequestString(),
  133.             $executorArgumentsEvent->getRootValue(),
  134.             $executorArgumentsEvent->getContextValue(),
  135.             $executorArgumentsEvent->getVariableValue(),
  136.             $executorArgumentsEvent->getOperationName(),
  137.             $this->defaultFieldResolver
  138.         );
  139.         $result $this->postExecute($result$executorArgumentsEvent);
  140.         return $result;
  141.     }
  142.     /**
  143.      * @param mixed $rootValue
  144.      */
  145.     private function preExecute(
  146.         string $schemaName,
  147.         Schema $schema,
  148.         string $requestString,
  149.         ArrayObject $contextValue,
  150.         $rootValue null,
  151.         ?array $variableValue null,
  152.         ?string $operationName null
  153.     ): ExecutorArgumentsEvent {
  154.         // @phpstan-ignore-next-line (only for Symfony 4.4)
  155.         $this->dispatcher->dispatch(new ExecutorContextEvent($contextValue), Events::EXECUTOR_CONTEXT);
  156.         /** @var ExecutorArgumentsEvent $object */
  157.         // @phpstan-ignore-next-line (only for Symfony 4.4)
  158.         $object $this->dispatcher->dispatch(
  159.             // @phpstan-ignore-next-line
  160.             ExecutorArgumentsEvent::create($schemaName$schema$requestString$contextValue$rootValue$variableValue$operationName),
  161.             Events::PRE_EXECUTOR
  162.         );
  163.         return $object;
  164.     }
  165.     private function postExecute(ExecutionResult $resultExecutorArgumentsEvent $executorArguments): ExecutionResult
  166.     {
  167.         // @phpstan-ignore-next-line (only for Symfony 4.4)
  168.         return $this->dispatcher->dispatch(
  169.             new ExecutorResultEvent($result$executorArguments),
  170.             Events::POST_EXECUTOR
  171.         )->getResult();
  172.     }
  173. }