Completed
Push — master ( 300eda...15c856 )
by Rafael
09:26
created

GraphQLEndpointController::__invoke()   F

Complexity

Conditions 19
Paths 3097

Size

Total Lines 88
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 35
CRAP Score 31.611

Importance

Changes 0
Metric Value
dl 0
loc 88
ccs 35
cts 52
cp 0.6731
rs 2
c 0
b 0
f 0
cc 19
eloc 55
nc 3097
nop 1
crap 31.611

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\ClientAware;
15
use GraphQL\Error\Debug;
16
use GraphQL\GraphQL;
17
use GraphQL\Validator\DocumentValidator;
18
use GraphQL\Validator\Rules;
19
use Psr\Log\LoggerInterface;
20
use Symfony\Component\HttpFoundation\JsonResponse;
21
use Symfony\Component\HttpFoundation\Request;
22
use Symfony\Component\HttpFoundation\Response;
23
use Symfony\Component\HttpKernel\Exception\HttpException;
24
use Ynlo\GraphQLBundle\Request\ExecuteQuery;
25
use Ynlo\GraphQLBundle\Request\RequestMiddlewareInterface;
26
use Ynlo\GraphQLBundle\Schema\SchemaCompiler;
27
28
class GraphQLEndpointController
29
{
30
    /**
31
     * @var SchemaCompiler
32
     */
33
    protected $compiler;
34
35
    /**
36
     * @var bool
37
     */
38
    protected $debug;
39
40
    /**
41
     * @var LoggerInterface
42
     */
43
    protected $logger;
44
45
    /**
46
     * @var iterable
47
     */
48
    protected $middlewares = [];
49
50 22
    public function __construct(SchemaCompiler $compiler, iterable $middlewares = [], bool $debug = false, LoggerInterface $logger = null)
51
    {
52 22
        $this->middlewares = $middlewares;
53 22
        $this->compiler = $compiler;
54 22
        $this->debug = $debug;
55 22
        $this->logger = $logger;
56 22
    }
57
58 22
    public function __invoke(Request $request): JsonResponse
59
    {
60 22
        if (!$this->debug && $request->getMethod() !== Request::METHOD_POST) {
61
            throw new HttpException(Response::HTTP_BAD_REQUEST, 'The method should be POST to talk with GraphQL API');
62
        }
63
64 22
        $query = new ExecuteQuery();
65 22
        foreach ($this->middlewares as $middleware) {
66 22
            if ($middleware instanceof RequestMiddlewareInterface) {
67 22
                $middleware->processRequest($request, $query);
68
            }
69
        }
70
71 22
        $context = null;
72 22
        $validationRules = null;
73
74
        try {
75 22
            $schema = $this->compiler->compile();
76 22
            $schema->assertValid();
77
78 22
            $result = GraphQL::executeQuery(
79 22
                $schema,
80 22
                $query->getRequestString(),
81 22
                null,
82 22
                $context,
83 22
                $query->getVariables(),
84 22
                $query->getOperationName(),
85 22
                null,
86 22
                $validationRules
87
            );
88
89 22
            if (!$this->debug) {
90
                // in case of debug = false
91
                // If API_DEBUG is passed, output of error formatter is enriched which debugging information.
92
                // Helpful for tests to get full error logs without the need of enable full app debug flag
93 22
                if (isset($_ENV['API_DEBUG'])) {
94
                    $this->debug = $_ENV['API_DEBUG'];
95 22
                } elseif (isset($_SERVER['API_DEBUG'])) {
96
                    $this->debug = $_SERVER['API_DEBUG'];
97
                }
98
            }
99
100 22
            $debugFlags = false;
101 22
            if ($this->debug) {
102
                $debugFlags = Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE;
103
            }
104
105 22
            foreach ($result->errors as $error) {
106 22
                if (null !== $this->logger) {
107
                    $originError = $error->getTrace()[0]['args'][0] ?? null;
108
                    $context = [];
109
                    if ($originError instanceof \Exception) {
110
                        $context = [
111
                            'file' => $originError->getFile(),
112
                            'line' => $originError->getLine(),
113
                            'error' => get_class($originError),
114
                        ];
115
                    }
116
                    if ($error->isClientSafe()) {
117
                        $this->logger->notice($error->getMessage(), $context);
118
                    } else {
119
                        $this->logger->error($error->getMessage(), $context);
120
                    }
121
                }
122
            }
123
124
            $output = $result->toArray($debugFlags);
125
            $statusCode = Response::HTTP_OK;
126 22
        } catch (\Exception $e) {
127
            if (null !== $this->logger) {
128
                $this->logger->error($e->getMessage(), $e->getTrace());
129 22
            }
130
            $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR;
131 22
            $message = Response::$statusTexts[$statusCode] ?? 'Internal Server Error';
132 22
133 22
            if ($this->debug || ($e instanceof ClientAware && $e->isClientSafe())) {
134
                $message = $e->getMessage();
135 22
            }
136
137
            $output['errors']['message'] = $message;
138 22
            $output['errors']['category'] = 'internal';
139
140
            if ($this->debug) {
141 22
                $output['errors']['trace'] = $e->getTraceAsString();
142 22
            }
143
        }
144
145
        return JsonResponse::create($output, $statusCode);
146
    }
147
148
    public function addGlobalValidationRules(array $validationRules): void
149
    {
150
        $rules = [];
151
        if (!empty($validationRules['query_complexity'])) {
152
            $rules[] = new Rules\QueryComplexity($validationRules['query_complexity']);
153
        }
154
        if (!empty($validationRules['query_depth'])) {
155
            $rules[] = new Rules\QueryDepth($validationRules['query_depth']);
156
        }
157
        if (!empty($validationRules['disable_introspection'])) {
158
            $rules[] = new Rules\DisableIntrospection();
159
        }
160
        array_map([DocumentValidator::class, 'addRule'], $rules);
161
    }
162
}
163