Completed
Pull Request — master (#250)
by Alejandro
07:04 queued 03:20
created

BodyParserMiddleware   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Test Coverage

Coverage 93.33%

Importance

Changes 0
Metric Value
eloc 26
dl 0
loc 75
rs 10
c 0
b 0
f 0
ccs 28
cts 30
cp 0.9333
wmc 9

4 Methods

Rating   Name   Duplication   Size   Complexity  
A getRequestContentType() 0 5 1
A parseFromUrlEncoded() 0 11 2
A parseFromJson() 0 9 2
A process() 0 21 4
1
<?php
2
declare(strict_types=1);
3
4
namespace Shlinkio\Shlink\Rest\Middleware;
5
6
use Fig\Http\Message\RequestMethodInterface;
7
use Psr\Http\Message\ResponseInterface as Response;
8
use Psr\Http\Message\ServerRequestInterface as Request;
9
use Psr\Http\Server\MiddlewareInterface;
10
use Psr\Http\Server\RequestHandlerInterface;
11
use function array_shift;
12
use function explode;
13
use function Functional\contains;
14
use function parse_str;
15
use function Shlinkio\Shlink\Common\json_decode;
16
use function trim;
17
18
class BodyParserMiddleware implements MiddlewareInterface, RequestMethodInterface
19
{
20
    /**
21
     * Process an incoming server request and return a response, optionally delegating
22
     * to the next middleware component to create the response.
23
     *
24
     * @param Request $request
25
     * @param RequestHandlerInterface $handler
26
     *
27
     * @return Response
28
     */
29 3
    public function process(Request $request, RequestHandlerInterface $handler): Response
30
    {
31 3
        $method = $request->getMethod();
32 3
        $currentParams = $request->getParsedBody();
33
34
        // In requests that do not allow body or if the body has already been parsed, continue to next middleware
35 3
        if (! empty($currentParams) || contains([
36 3
            self::METHOD_GET,
37 3
            self::METHOD_HEAD,
38 3
            self::METHOD_OPTIONS,
39 3
        ], $method)) {
40 1
            return $handler->handle($request);
41
        }
42
43
        // If the accepted content is JSON, try to parse the body from JSON
44 2
        $contentType = $this->getRequestContentType($request);
45 2
        if (contains(['application/json', 'text/json', 'application/x-json'], $contentType)) {
46 1
            return $handler->handle($this->parseFromJson($request));
47
        }
48
49 1
        return $handler->handle($this->parseFromUrlEncoded($request));
50
    }
51
52
    /**
53
     * @param Request $request
54
     * @return string
55
     */
56 2
    private function getRequestContentType(Request $request): string
57
    {
58 2
        $contentType = $request->getHeaderLine('Content-type');
59 2
        $contentTypes = explode(';', $contentType);
60 2
        return trim(array_shift($contentTypes));
61
    }
62
63
    /**
64
     * @param Request $request
65
     * @return Request
66
     */
67 1
    private function parseFromJson(Request $request): Request
68
    {
69 1
        $rawBody = (string) $request->getBody();
70 1
        if (empty($rawBody)) {
71
            return $request;
72
        }
73
74 1
        $parsedJson = json_decode($rawBody);
75 1
        return $request->withParsedBody($parsedJson);
76
    }
77
78
    /**
79
     * @param Request $request
80
     * @return Request
81
     */
82 1
    private function parseFromUrlEncoded(Request $request): Request
83
    {
84 1
        $rawBody = (string) $request->getBody();
85 1
        if (empty($rawBody)) {
86
            return $request;
87
        }
88
89 1
        $parsedBody = [];
90 1
        parse_str($rawBody, $parsedBody);
91
92 1
        return $request->withParsedBody($parsedBody);
93
    }
94
}
95