Completed
Push — dev-master ( 2915d1...bb4a55 )
by Derek Stephen
02:08
created

PlatesStrategy::invokeRouteCallable()   A

Complexity

Conditions 4
Paths 17

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 8.2515

Importance

Changes 0
Metric Value
dl 0
loc 25
ccs 5
cts 14
cp 0.357
rs 9.52
c 0
b 0
f 0
cc 4
nc 17
nop 2
crap 8.2515
1
<?php
2
3
namespace Bone\Mvc\Router;
4
5
use Bone\Mvc\Router\Decorator\NotAllowedDecorator;
6
use Bone\Mvc\Router\Decorator\NotFoundDecorator;
7
use Bone\Mvc\View\PlatesEngine;
8
use Bone\Traits\LayoutAwareTrait;
9
use Exception;
10
use League\Route\Http\Exception\{MethodNotAllowedException, NotFoundException};
11
use League\Route\Route;
12
use League\Route\Strategy\ApplicationStrategy;
13
use League\Route\Strategy\StrategyInterface;
14
use Psr\Http\Message\ResponseInterface;
15
use Psr\Http\Message\ServerRequestInterface;
16
use Psr\Http\Server\MiddlewareInterface;
17
use Zend\Diactoros\Response;
18
use Zend\Diactoros\Response\HtmlResponse;
19
use Zend\Diactoros\Stream;
20
21
class PlatesStrategy extends ApplicationStrategy implements StrategyInterface
22
{
23
    use LayoutAwareTrait;
24
25
    /** @var PlatesEngine $viewEngine */
26
    private $viewEngine;
27
28
    /** @var NotFoundDecorator $notFoundDecorator */
29
    private $notFoundDecorator;
30
31
    /** @var NotAllowedDecorator $notAllowedDecorator */
32
    private $notAllowedDecorator;
33
34
    /** @var bool  */
35
    private $i18nEnabled = false;
36
37
    /** @var array  */
38
    private $supportedLocales = [];
39
40
    /**
41
     * PlatesStrategy constructor.
42
     * @param PlatesEngine $viewEngine
43
     * @param NotFoundDecorator $notFound
44
     * @param NotAllowedDecorator $notAllowed
45
     * @param string $layout
46
     */
47 3
    public function __construct(PlatesEngine $viewEngine, NotFoundDecorator $notFound, NotAllowedDecorator $notAllowed, string $layout)
48
    {
49 3
        $this->viewEngine = $viewEngine;
50 3
        $this->notFoundDecorator = $notFound;
51 3
        $this->notAllowedDecorator = $notAllowed;
52 3
        $this->setLayout($layout);
53 3
    }
54
55
    /**
56
     * @param bool $i18nEnabled
57
     */
58 3
    public function setI18nEnabled(bool $i18nEnabled): void
59
    {
60 3
        $this->i18nEnabled = $i18nEnabled;
61 3
    }
62
63
    /**
64
     * @param array $locales
65
     */
66 3
    public function setSupportedLocales(array $locales): void
67
    {
68 3
        $this->supportedLocales = $locales;
69 3
    }
70
71
72
    /**
73
     * Invoke the route callable based on the strategy.
74
     *
75
     * @param \League\Route\Route $route
76
     * @param \Psr\Http\Message\ServerRequestInterface $request
77
     *
78
     * @return \Psr\Http\Message\ResponseInterface
79
     */
80 1
    public function invokeRouteCallable(Route $route, ServerRequestInterface $request): ResponseInterface
81
    {
82
        try {
83
84 1
            $response = parent::invokeRouteCallable($route, $request);
85 1
            $body = $this->getBody($response);
86 1
            $body = $this->viewEngine->render($this->layout, $body);
87
88 1
            return $this->getResponseWithBodyAndStatus($response, $body, $response->getStatusCode());
0 ignored issues
show
Compatibility introduced by
$response of type object<Psr\Http\Message\ResponseInterface> is not a sub-type of object<Zend\Diactoros\Response>. It seems like you assume a concrete implementation of the interface Psr\Http\Message\ResponseInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
89
90
        } catch (Exception $e) {
91
            $body = $this->viewEngine->render('error/error', [
92
                'message' => $e->getMessage(),
93
                'code' => $e->getCode(),
94
                'trace' => $e->getTrace(),
95
            ]);
96
            $body = $this->viewEngine->render($this->layout, [
97
                'content' => $body,
98
            ]);
99
            $status = ($e->getCode() >= 100 && $e->getCode() < 600) ? $e->getCode() : 500;
100
101
            return $this->getResponseWithBodyAndStatus(new HtmlResponse($body), $body, $status);
102
        }
103
104
    }
105
106
    /**
107
     * @param ResponseInterface $response
108
     * @return array|mixed
109
     */
110 1
    private function getBody(ResponseInterface $response)
111
    {
112
        switch (true) {
113 1
            case $response instanceof Response\JsonResponse:
114
                $contents = $response->getBody()->getContents();
115
                $body = json_decode($contents, true);
116
                $body = ($body === null) ? [] : $body;
117
                break;
118
119 1
            case $response instanceof Response:
120 1
                $body = ['content' => $response->getBody()->getContents()];
121 1
                break;
122
            default:
123
124
        }
125
126 1
        return $body;
0 ignored issues
show
Bug introduced by
The variable $body does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
127
    }
128
129
    /**
130
     * @param ResponseInterface $response
131
     * @param string $body
132
     * @param int $status
133
     * @return \Psr\Http\Message\MessageInterface|Response
134
     */
135 1
    private function getResponseWithBodyAndStatus(Response $response, string $body, int $status = 200)
136
    {
137 1
        $stream = new Stream('php://memory', 'r+');
138 1
        $stream->write($body);
139 1
        $response = $response->withStatus($status)->withBody($stream);
140
141 1
        return $response;
142
    }
143
144
    /**
145
     * Get a middleware that will decorate a NotFoundException
146
     *
147
     * @param \League\Route\Http\Exception\NotFoundException $exception
0 ignored issues
show
Bug introduced by
There is no parameter named $exception. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
148
     *
149
     * @return \Psr\Http\Server\MiddlewareInterface
150
     */
151 1
    public function getNotFoundDecorator(NotFoundException $e): MiddlewareInterface
152
    {
153 1
        return $this->notFoundDecorator;
154
    }
155
156
    /**
157
     * Get a middleware that will decorate a NotAllowedException
158
     *
159
     * @param \League\Route\Http\Exception\NotFoundException $e
160
     *
161
     * @return \Psr\Http\Server\MiddlewareInterface
162
     */
163
    public function getMethodNotAllowedDecorator(MethodNotAllowedException $e): MiddlewareInterface
164
    {
165
        return $this->notAllowedDecorator;
166
    }
167
}