Passed
Push — master ( 9c9b87...481b02 )
by Evgeniy
02:15
created

RouteMatchMiddleware::isAllowedMethods()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 1
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace HttpSoft\Router\Middleware;
6
7
use HttpSoft\Router\Route;
8
use HttpSoft\Router\RouteCollector;
9
use Psr\Http\Message\ResponseFactoryInterface;
10
use Psr\Http\Message\ResponseInterface;
11
use Psr\Http\Message\ServerRequestInterface;
12
use Psr\Http\Server\MiddlewareInterface;
13
use Psr\Http\Server\RequestHandlerInterface;
14
15
use function array_filter;
16
use function array_unique;
17
use function implode;
18
use function in_array;
19
use function is_string;
20
use function strtoupper;
21
22
final class RouteMatchMiddleware implements MiddlewareInterface
23
{
24
    /**
25
     * @var RouteCollector
26
     */
27
    private RouteCollector $router;
28
29
    /**
30
     * @var ResponseFactoryInterface
31
     */
32
    private ResponseFactoryInterface $responseFactory;
33
34
    /**
35
     * @var string[]
36
     */
37
    private array $allowedMethods = [];
38
39
    /**
40
     * @param RouteCollector $router
41
     * @param ResponseFactoryInterface $responseFactory
42
     * @param array|string[] $allowedMethods common allowed request methods for all routes.
43
     * @psalm-suppress MixedAssignment
44
     */
45 5
    public function __construct(
46
        RouteCollector $router,
47
        ResponseFactoryInterface $responseFactory,
48
        array $allowedMethods = ['HEAD']
49
    ) {
50 5
        $this->router = $router;
51 5
        $this->responseFactory = $responseFactory;
52
53 5
        foreach ($allowedMethods as $allowedMethod) {
54 5
            if (is_string($allowedMethod)) {
55 5
                $this->allowedMethods[] = strtoupper($allowedMethod);
56
            }
57
        }
58 5
    }
59
60
    /**
61
     * {@inheritDoc}
62
     */
63 5
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
64
    {
65 5
        if (!$route = $this->router->routes()->match($request, false)) {
66 1
            return $handler->handle($request);
67
        }
68
69 4
        if (!$this->isAllowedMethods($request->getMethod()) && !$route->isAllowedMethod($request->getMethod())) {
70 1
            return $this->getEmptyResponseWithAllowedMethods($route->getMethods());
71
        }
72
73 3
        foreach ($route->getMatchedParameters() as $name => $value) {
74 1
            $request = $request->withAttribute($name, $value);
75
        }
76
77 3
        return $handler->handle($request->withAttribute(Route::class, $route));
78
    }
79
80
    /**
81
     * @param string[] $methods
82
     * @return ResponseInterface
83
     */
84 1
    private function getEmptyResponseWithAllowedMethods(array $methods): ResponseInterface
85
    {
86 1
        foreach ($this->allowedMethods as $method) {
87 1
            $methods[] = $method;
88
        }
89
90 1
        $methods = implode(', ', array_unique(array_filter($methods)));
91 1
        return $this->responseFactory->createResponse(405)->withHeader('Allow', $methods);
92
    }
93
94
    /**
95
     * @param string $method
96
     * @return bool
97
     */
98 4
    private function isAllowedMethods(string $method): bool
99
    {
100 4
        return ($this->allowedMethods !== [] && in_array(strtoupper($method), $this->allowedMethods, true));
101
    }
102
}
103