Passed
Push — master ( 23bdfa...6b6f8b )
by Adrien
02:53 queued 01:10
created

UploadMiddleware::decodeArray()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 3
nop 2
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Upload;
6
7
use GraphQL\Error\InvariantViolation;
8
use GraphQL\Server\RequestError;
9
use GraphQL\Utils\Utils;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ServerRequestInterface;
12
use Psr\Http\Server\MiddlewareInterface;
13
use Psr\Http\Server\RequestHandlerInterface;
14
15
class UploadMiddleware implements MiddlewareInterface
16
{
17 1
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
18
    {
19 1
        $request = $this->processRequest($request);
20
21 1
        return $handler->handle($request);
22
    }
23
24
    /**
25
     * Process the request and return either a modified request or the original one.
26
     */
27 11
    public function processRequest(ServerRequestInterface $request): ServerRequestInterface
28
    {
29 11
        $contentType = $request->getHeader('content-type')[0] ?? '';
30
31 11
        if (mb_stripos($contentType, 'multipart/form-data') !== false) {
32 9
            $this->validateParsedBody($request);
33 6
            $request = $this->parseUploadedFiles($request);
34
        }
35
36 5
        return $request;
37
    }
38
39
    /**
40
     * Inject uploaded files defined in the 'map' key into the 'variables' key.
41
     */
42 6
    private function parseUploadedFiles(ServerRequestInterface $request): ServerRequestInterface
43
    {
44
        /** @var string[] $bodyParams */
45 6
        $bodyParams = $request->getParsedBody();
46
47 6
        $map = $this->decodeArray($bodyParams, 'map');
48 3
        $result = $this->decodeArray($bodyParams, 'operations');
49
50 3
        foreach ($map as $fileKey => $locations) {
51 2
            foreach ($locations as $location) {
52 2
                $items = &$result;
53 2
                foreach (explode('.', $location) as $key) {
54 2
                    if (!isset($items[$key]) || !is_array($items[$key])) {
55 2
                        $items[$key] = [];
56
                    }
57 2
                    $items = &$items[$key];
58
                }
59
60 2
                $items = $request->getUploadedFiles()[$fileKey];
61
            }
62
        }
63
64
        return $request
65 3
            ->withHeader('content-type', 'application/json')
66 3
            ->withParsedBody($result);
67
    }
68
69
    /**
70
     * Validates that the request meet our expectations.
71
     */
72 9
    private function validateParsedBody(ServerRequestInterface $request): void
73
    {
74 9
        $bodyParams = $request->getParsedBody();
75
76 9
        if (null === $bodyParams) {
77 1
            throw new InvariantViolation(
78 1
                'PSR-7 request is expected to provide parsed body for "multipart/form-data" requests but got null'
79
            );
80
        }
81
82 8
        if (!is_array($bodyParams)) {
83 1
            throw new RequestError(
84 1
                'GraphQL Server expects JSON object or array, but got ' . Utils::printSafeJson($bodyParams)
85
            );
86
        }
87
88 7
        if (empty($bodyParams)) {
89 1
            throw new InvariantViolation(
90 1
                'PSR-7 request is expected to provide parsed body for "multipart/form-data" requests but got empty array'
91
            );
92
        }
93 6
    }
94
95
    /**
96
     * @param string[] $bodyParams
97
     *
98
     * @return string[][]
99
     */
100 6
    private function decodeArray(array $bodyParams, string $key): array
101
    {
102 6
        if (!isset($bodyParams[$key])) {
103 1
            throw new RequestError("The request must define a `$key`");
104
        }
105
106 5
        $value = json_decode($bodyParams[$key], true);
107 5
        if (!is_array($value)) {
108 2
            throw new RequestError("The `$key` key must be a JSON encoded array");
109
        }
110
111 3
        return $value;
112
    }
113
}
114