Completed
Push — master ( 84726b...bd63f9 )
by Adrien
03:20
created

UploadMiddleware::processRequest()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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