Completed
Push — master ( 4a37c4...7b165c )
by Phil
13:05 queued 11:28
created

JsonStrategy   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 7
dl 0
loc 141
ccs 40
cts 40
cp 1
rs 10
c 0
b 0
f 0

11 Methods

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