JsonStrategy::getNotFoundDecorator()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php declare(strict_types=1);
2
3
namespace League\Route\Strategy;
4
5
use League\Route\{ContainerAwareInterface, ContainerAwareTrait};
6
use League\Route\Http\Exception as HttpException;
7
use League\Route\Http\Exception\{MethodNotAllowedException, NotFoundException};
8
use League\Route\Route;
9
use Psr\Http\Message\{ResponseFactoryInterface, ResponseInterface, ServerRequestInterface};
10
use Psr\Http\Server\{MiddlewareInterface, RequestHandlerInterface};
11
use Throwable;
12
13
class JsonStrategy extends AbstractStrategy implements ContainerAwareInterface
14
{
15
    use ContainerAwareTrait;
16
17
    /**
18
     * @var ResponseFactoryInterface
19
     */
20
    protected $responseFactory;
21
22
    /**
23
     * Construct.
24
     *
25
     * @param ResponseFactoryInterface $responseFactory
26
     */
27 48
    public function __construct(ResponseFactoryInterface $responseFactory)
28
    {
29 48
        $this->responseFactory = $responseFactory;
30
31 48
        $this->addDefaultResponseHeader('content-type', 'application/json');
32 48
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37 21
    public function invokeRouteCallable(Route $route, ServerRequestInterface $request): ResponseInterface
38
    {
39 21
        $controller = $route->getCallable($this->getContainer());
40 21
        $response = $controller($request, $route->getVars());
41
42 15
        if ($this->isJsonEncodable($response)) {
43 12
            $body     = json_encode($response);
44 12
            $response = $this->responseFactory->createResponse();
45 12
            $response->getBody()->write($body);
46
        }
47
48 15
        $response = $this->applyDefaultResponseHeaders($response);
49
50 15
        return $response;
51
    }
52
53
    /**
54
     * Check if the response can be converted to JSON
55
     *
56
     * Arrays can always be converted, objects can be converted if they're not a response already
57
     *
58
     * @param mixed $response
59
     *
60
     * @return bool
61
     */
62 15
    protected function isJsonEncodable($response): bool
63
    {
64 15
        if ($response instanceof ResponseInterface) {
65 3
            return false;
66
        }
67
68 12
        return (is_array($response) || is_object($response));
69
    }
70
71
    /**
72
     * {@inheritdoc}
73
     */
74 6
    public function getNotFoundDecorator(NotFoundException $exception): MiddlewareInterface
75
    {
76 6
        return $this->buildJsonResponseMiddleware($exception);
77
    }
78
79
    /**
80
     * {@inheritdoc}
81
     */
82 6
    public function getMethodNotAllowedDecorator(MethodNotAllowedException $exception): MiddlewareInterface
83
    {
84 6
        return $this->buildJsonResponseMiddleware($exception);
85
    }
86
87
    /**
88
     * Return a middleware the creates a JSON response from an HTTP exception
89
     *
90
     * @param HttpException $exception
91
     *
92
     * @return MiddlewareInterface
93
     */
94 12
    protected function buildJsonResponseMiddleware(HttpException $exception): MiddlewareInterface
95
    {
96
        return new class($this->responseFactory->createResponse(), $exception) implements MiddlewareInterface
97
        {
98
            protected $response;
99
            protected $exception;
100
101
            public function __construct(ResponseInterface $response, HttpException $exception)
102
            {
103 12
                $this->response  = $response;
104 12
                $this->exception = $exception;
105 12
            }
106
107
            public function process(
108
                ServerRequestInterface $request,
109
                RequestHandlerInterface $requestHandler
110
            ): ResponseInterface {
111 12
                return $this->exception->buildJsonResponse($this->response);
112
            }
113
        };
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119 18
    public function getExceptionHandler(): MiddlewareInterface
120
    {
121 18
        return $this->getThrowableHandler();
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function getThrowableHandler(): MiddlewareInterface
128
    {
129
        return new class($this->responseFactory->createResponse()) implements MiddlewareInterface
130
        {
131
            protected $response;
132
133 18
            public function __construct(ResponseInterface $response)
134
            {
135 18
                $this->response = $response;
136 18
            }
137
138 18
            public function process(
139
                ServerRequestInterface $request,
140
                RequestHandlerInterface $requestHandler
141
            ): ResponseInterface {
142
                try {
143 18
                    return $requestHandler->handle($request);
144 12
                } catch (Throwable $exception) {
145 12
                    $response = $this->response;
146
147 12
                    if ($exception instanceof HttpException) {
148 6
                        return $exception->buildJsonResponse($response);
149
                    }
150
151 6
                    $response->getBody()->write(json_encode([
152 6
                        'status_code'   => 500,
153 6
                        'reason_phrase' => $exception->getMessage()
154
                    ]));
155
156 6
                    $response = $response->withAddedHeader('content-type', 'application/json');
157 6
                    return $response->withStatus(500, strtok($exception->getMessage(), "\n"));
158
                }
159
            }
160
        };
161
    }
162
}
163