Completed
Pull Request — master (#5)
by Yonel Ceruto
10:19 queued 23s
created

GraphQLEndpointController   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 88
Duplicated Lines 0 %

Test Coverage

Coverage 71.88%

Importance

Changes 0
Metric Value
wmc 17
dl 0
loc 88
ccs 23
cts 32
cp 0.7188
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A addGlobalValidationRules() 0 13 4
A getValidationRules() 0 14 4
C __invoke() 0 44 8
1
<?php
2
3
/*******************************************************************************
4
 *  This file is part of the GraphQL Bundle package.
5
 *
6
 *  (c) YnloUltratech <[email protected]>
7
 *
8
 *  For the full copyright and license information, please view the LICENSE
9
 *  file that was distributed with this source code.
10
 ******************************************************************************/
11
12
namespace Ynlo\GraphQLBundle\Controller;
13
14
use GraphQL\Error\Debug;
15
use GraphQL\GraphQL;
16
use GraphQL\Validator\DocumentValidator;
17
use GraphQL\Validator\Rules;
18
use Psr\Log\LoggerInterface;
19
use Symfony\Component\HttpFoundation\JsonResponse;
20
use Symfony\Component\HttpFoundation\Request;
21
use Symfony\Component\HttpFoundation\Response;
22
use Symfony\Component\HttpKernel\Exception\HttpException;
23
use Ynlo\GraphQLBundle\Schema\SchemaCompiler;
24
25
class GraphQLEndpointController
26
{
27
    private $compiler;
28 21
    private $debug;
29
    private $logger;
30 21
31 21
    public function __construct(SchemaCompiler $compiler, bool $debug, LoggerInterface $logger = null)
32 21
    {
33 21
        $this->compiler = $compiler;
34
        $this->debug = $debug;
35 21
        $this->logger = $logger;
36
    }
37 21
38
    public function __invoke(Request $request): JsonResponse
39
    {
40
        if (!$this->debug && $request->getMethod() !== Request::METHOD_POST) {
41 21
            throw new HttpException(Response::HTTP_BAD_REQUEST, 'The method should be POST to talk with GraphQL API');
42
        }
43 21
44 21
        $input = json_decode($request->getContent(), true);
45 21
        $query = $input['query'];
46 21
        $context = null;
47
        $variableValues = $input['variables'] ?? null;
48
        $operationName = $input['operationName'] ?? null;
49 21
        // this will override global validation rules for this request
50 21
        $validationRules = $this->getValidationRules($query);
51 21
52
        try {
53 21
            $schema = $this->compiler->compile();
54 21
            $schema->assertValid();
55 21
56
            $result = GraphQL::executeQuery($schema, $query, null, $context, $variableValues, $operationName, null, $validationRules);
57
58 21
            $debug = false;
59 21
            if ($this->debug) {
60
                $debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
61 21
            }
62 21
            $output = $result->toArray($debug);
63
            $statusCode = Response::HTTP_OK;
64
65
            if (isset($output['errors'])) {
66
                $statusCode = Response::HTTP_BAD_REQUEST;
67
            }
68
        } catch (\Exception $e) {
69
            if (null !== $this->logger) {
70
                $this->logger->error($e->getMessage(), $e->getTrace());
71
            }
72
            $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR;
73
            $output['errors']['message'] = $e->getMessage();
74
            $output['errors']['category'] = 'internal';
75
76
            if ($this->debug) {
77 21
                $output['errors']['trace'] = $e->getTraceAsString();
78
            }
79
        }
80
81
        return JsonResponse::create($output, $statusCode);
82
    }
83
84
    public function addGlobalValidationRules(array $validationRules): void
85
    {
86
        $rules = [];
87
        if (!empty($validationRules['query_complexity'])) {
88
            $rules[] = new Rules\QueryComplexity($validationRules['query_complexity']);
89
        }
90
        if (!empty($validationRules['query_depth'])) {
91
            $rules[] = new Rules\QueryDepth($validationRules['query_depth']);
92
        }
93
        if (!empty($validationRules['disable_introspection'])) {
94
            $rules[] = new Rules\DisableIntrospection();
95
        }
96
        array_map([DocumentValidator::class, 'addRule'], $rules);
97
    }
98
99
    private function getValidationRules(string $query): ?array
100
    {
101
        $rules = [];
102
103
        // disable query complexity limit for introspection query
104
        if (false !== strpos($query, "query IntrospectionQuery {\n    __schema {") && null !== DocumentValidator::getRule('QueryComplexity')) {
105
            $rules[] = new Rules\QueryComplexity(Rules\QueryComplexity::DISABLED);
106
        }
107
108
        if (!$rules) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rules of type GraphQL\Validator\Rules\QueryComplexity[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
109
            return null;
110
        }
111
112
        return array_merge(GraphQL::getStandardValidationRules(), $rules);
113
    }
114
}
115