Completed
Pull Request — master (#283)
by Phil
22:36
created

JsonStrategy::buildJsonResponseMiddleware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 9.584
c 0
b 0
f 0
ccs 6
cts 6
cp 1
cc 1
nc 1
nop 1
crap 1

2 Methods

Rating   Name   Duplication   Size   Complexity  
A JsonStrategy.php$1 ➔ __construct() 0 5 1
A JsonStrategy.php$1 ➔ process() 0 6 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Route\Strategy;
6
7
use JsonSerializable;
8
use League\Route\Http;
9
use League\Route\Http\Exception\{MethodNotAllowedException, NotFoundException};
10
use League\Route\Route;
11
use League\Route\{ContainerAwareInterface, ContainerAwareTrait};
12
use Psr\Http\Message\{ResponseFactoryInterface, ResponseInterface, ServerRequestInterface};
13
use Psr\Http\Server\{MiddlewareInterface, RequestHandlerInterface};
14
use Throwable;
15
16
class JsonStrategy extends AbstractStrategy implements ContainerAwareInterface, OptionsHandlerInterface
17
{
18
    use ContainerAwareTrait;
19
20
    /**
21
     * @var ResponseFactoryInterface
22
     */
23
    protected $responseFactory;
24
25
    /**
26
     * @var int
27
     */
28
    protected $jsonFlags;
29
30
    public function __construct(ResponseFactoryInterface $responseFactory, int $jsonFlags = 0)
31
    {
32
        $this->responseFactory = $responseFactory;
33
        $this->jsonFlags = $jsonFlags;
34
35
        $this->addResponseDecorator(static function (ResponseInterface $response): ResponseInterface {
36
            if (false === $response->hasHeader('content-type')) {
37 32
                $response = $response->withHeader('content-type', 'application/json');
38
            }
39 32
40 32
            return $response;
41
        });
42 32
    }
43 32
44
    public function getMethodNotAllowedDecorator(MethodNotAllowedException $exception): MiddlewareInterface
45
    {
46
        return $this->buildJsonResponseMiddleware($exception);
47
    }
48 14
49
    public function getNotFoundDecorator(NotFoundException $exception): MiddlewareInterface
50 14
    {
51 14
        return $this->buildJsonResponseMiddleware($exception);
52
    }
53 10
54 8
    public function getOptionsCallable(array $methods): callable
55 8
    {
56 8
        return function (ServerRequestInterface $request) use ($methods): ResponseInterface {
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
57
            $methods  = implode(', ', $methods);
0 ignored issues
show
Bug introduced by
Consider using a different name than the imported variable $methods, or did you forget to import by reference?

It seems like you are assigning to a variable which was imported through a use statement which was not imported by reference.

For clarity, we suggest to use a different name or import by reference depending on whether you would like to have the change visibile in outer-scope.

Change not visible in outer-scope

$x = 1;
$callable = function() use ($x) {
    $x = 2; // Not visible in outer scope. If you would like this, how
            // about using a different variable name than $x?
};

$callable();
var_dump($x); // integer(1)

Change visible in outer-scope

$x = 1;
$callable = function() use (&$x) {
    $x = 2;
};

$callable();
var_dump($x); // integer(2)
Loading history...
58
            $response = $this->responseFactory->createResponse();
59 10
            $response = $response->withHeader('allow', $methods);
60
            return $response->withHeader('access-control-allow-methods', $methods);
61 10
        };
62
    }
63
64
    public function getThrowableHandler(): MiddlewareInterface
65
    {
66
        return new class ($this->responseFactory->createResponse()) implements MiddlewareInterface
67
        {
68
            protected $response;
69
70
            public function __construct(ResponseInterface $response)
71
            {
72
                $this->response = $response;
73 10
            }
74
75 10
            public function process(
76 2
                ServerRequestInterface $request,
77
                RequestHandlerInterface $requestHandler
78
            ): ResponseInterface {
79 8
                try {
80
                    return $requestHandler->handle($request);
81
                } catch (Throwable $exception) {
82
                    $response = $this->response;
83
84
                    if ($exception instanceof Http\Exception) {
85 4
                        return $exception->buildJsonResponse($response);
86
                    }
87 4
88
                    $response->getBody()->write(json_encode([
89
                        'status_code'   => 500,
90
                        'reason_phrase' => $exception->getMessage()
91
                    ]));
92
93 4
                    $response = $response->withAddedHeader('content-type', 'application/json');
94
                    return $response->withStatus(500, strtok($exception->getMessage(), "\n"));
95 4
                }
96
            }
97
        };
98
    }
99
100
    public function invokeRouteCallable(Route $route, ServerRequestInterface $request): ResponseInterface
101
    {
102
        $controller = $route->getCallable($this->getContainer());
103
        $response = $controller($request, $route->getVars());
104
105 8
        if ($this->isJsonSerializable($response)) {
106
            $body = json_encode($response, $this->jsonFlags);
107
            $response = $this->responseFactory->createResponse();
108
            $response->getBody()->write($body);
109
        }
110
111
        return $this->decorateResponse($response);
112
    }
113
114 8
    protected function buildJsonResponseMiddleware(Http\Exception $exception): MiddlewareInterface
115 8
    {
116 8
        return new class ($this->responseFactory->createResponse(), $exception) implements MiddlewareInterface
117
        {
118
            protected $response;
119
            protected $exception;
120
121
            public function __construct(ResponseInterface $response, Http\Exception $exception)
122 8
            {
123
                $this->response  = $response;
124
                $this->exception = $exception;
125
            }
126
127
            public function process(
128
                ServerRequestInterface $request,
129
                RequestHandlerInterface $requestHandler
130 12
            ): ResponseInterface {
131
                return $this->exception->buildJsonResponse($this->response);
132 12
            }
133
        };
134
    }
135
136
    protected function isJsonSerializable($response): bool
137
    {
138 6
        if ($response instanceof ResponseInterface) {
139
            return false;
140
        }
141
142
        return (is_array($response) || is_object($response) || $response instanceof JsonSerializable);
0 ignored issues
show
Bug introduced by
The class JsonSerializable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
143
    }
144
}
145