Passed
Pull Request — master (#3041)
by
unknown
04:12
created

EntrypointAction::applyMappingToVariables()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 15
nc 7
nop 2
dl 0
loc 24
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the API Platform project.
5
 *
6
 * (c) Kévin Dunglas <[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
declare(strict_types=1);
13
14
namespace ApiPlatform\Core\GraphQl\Action;
15
16
use ApiPlatform\Core\GraphQl\ExecutorInterface;
17
use ApiPlatform\Core\GraphQl\Type\SchemaBuilderInterface;
18
use GraphQL\Error\Debug;
19
use GraphQL\Error\Error;
20
use GraphQL\Executor\ExecutionResult;
21
use Symfony\Component\HttpFoundation\JsonResponse;
22
use Symfony\Component\HttpFoundation\Request;
23
use Symfony\Component\HttpFoundation\Response;
24
25
/**
26
 * GraphQL API entrypoint.
27
 *
28
 * @author Alan Poulain <[email protected]>
29
 */
30
final class EntrypointAction
31
{
32
    private $schemaBuilder;
33
    private $executor;
34
    private $graphiQlAction;
35
    private $graphQlPlaygroundAction;
36
    private $debug;
37
    private $graphiqlEnabled;
38
    private $graphQlPlaygroundEnabled;
39
    private $defaultIde;
40
41
    public function __construct(SchemaBuilderInterface $schemaBuilder, ExecutorInterface $executor, GraphiQlAction $graphiQlAction, GraphQlPlaygroundAction $graphQlPlaygroundAction, bool $debug = false, bool $graphiqlEnabled = false, bool $graphQlPlaygroundEnabled = false, $defaultIde = false)
42
    {
43
        $this->schemaBuilder = $schemaBuilder;
44
        $this->executor = $executor;
45
        $this->graphiQlAction = $graphiQlAction;
46
        $this->graphQlPlaygroundAction = $graphQlPlaygroundAction;
47
        $this->debug = $debug ? Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE : false;
48
        $this->graphiqlEnabled = $graphiqlEnabled;
49
        $this->graphQlPlaygroundEnabled = $graphQlPlaygroundEnabled;
50
        $this->defaultIde = $defaultIde;
51
    }
52
53
    public function __invoke(Request $request): Response
54
    {
55
        if ($request->isMethod('GET') && 'html' === $request->getRequestFormat()) {
56
            if ('graphiql' === $this->defaultIde && $this->graphiqlEnabled) {
57
                return ($this->graphiQlAction)($request);
58
            }
59
60
            if ('graphql-playground' === $this->defaultIde && $this->graphQlPlaygroundEnabled) {
61
                return ($this->graphQlPlaygroundAction)($request);
62
            }
63
        }
64
65
        [$query, $operation, $variables] = $this->parseRequest($request);
66
67
        if (null === $query) {
68
            return new JsonResponse(new ExecutionResult(null, [new Error('GraphQL query is not valid')]), Response::HTTP_BAD_REQUEST);
69
        }
70
71
        if (null === $variables) {
72
            return new JsonResponse(new ExecutionResult(null, [new Error('GraphQL variables are not valid JSON')]), Response::HTTP_BAD_REQUEST);
73
        }
74
75
        try {
76
            $executionResult = $this->executor->executeQuery($this->schemaBuilder->getSchema(), $query, null, null, $variables, $operation);
77
        } catch (\Exception $e) {
78
            $executionResult = new ExecutionResult(null, [new Error($e->getMessage(), null, null, null, null, $e)]);
79
        }
80
81
        return new JsonResponse($executionResult->toArray($this->debug));
82
    }
83
84
    private function parseRequest(Request $request): array
85
    {
86
        $query = $request->query->get('query');
87
        $operation = $request->query->get('operation');
88
        if ($variables = $request->query->get('variables', [])) {
89
            $variables = json_decode($variables, true);
90
        }
91
92
        if (!$request->isMethod('POST')) {
93
            return [$query, $operation, $variables];
94
        }
95
96
        if ('json' === $request->getContentType()) {
97
            return $this->parseInput($query, $variables, $operation, $request->getContent());
98
        }
99
100
        if (false !== mb_stripos($request->headers->get('CONTENT_TYPE'), 'multipart/form-data')) {
101
            if ($request->request->has('operations')) {
102
                [$query, $operation, $variables] = $this->parseInput($query, $variables, $operation, $request->request->get('operations'));
103
104
                if ($request->request->has('map')) {
105
                    $variables = $this->applyMappingToVariables($request, $variables);
106
                }
107
            }
108
        }
109
110
        if ('application/graphql' === $request->headers->get('CONTENT_TYPE')) {
111
            $query = $request->getContent();
112
        }
113
114
        return [$query, $operation, $variables];
115
    }
116
117
    private function parseInput($query, $variables, $operation, string $jsonContent): array
118
    {
119
        $input = json_decode($jsonContent, true);
120
        if (isset($input['query'])) {
121
            $query = $input['query'];
122
        }
123
124
        if (isset($input['variables'])) {
125
            $variables = \is_array($input['variables']) ? $input['variables'] : json_decode($input['variables'], true);
126
        }
127
128
        if (isset($input['operation'])) {
129
            $operation = $input['operation'];
130
        }
131
132
        return [$query, $operation, $variables];
133
    }
134
135
    private function applyMappingToVariables(Request $request, array $variables): array
136
    {
137
        $mapValues = json_decode($request->request->get('map'), true);
138
        if (!$mapValues) {
139
            return $variables;
140
        }
141
        foreach ($mapValues as $key => $value) {
142
            if ($request->files->has($key)) {
143
                foreach ($mapValues[$key] as $mapValue) {
144
                    $path = explode('.', $mapValue);
145
                    if ('variables' === $path[0]) {
146
                        unset($path[0]);
147
                        $temp = &$variables;
148
                        foreach ($path as $pathValue) {
149
                            $temp = &$temp[$pathValue];
150
                        }
151
                        $temp = $request->files->get($key);
152
                        unset($temp);
153
                    }
154
                }
155
            }
156
        }
157
158
        return $variables;
159
    }
160
}
161