Passed
Push — main ( 3a9c9f...17fbbc )
by Chema
09:55 queued 07:39
created

RouteEntity::requestMatches()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 0
dl 0
loc 15
rs 10
c 0
b 0
f 0
ccs 8
cts 8
cp 1
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Router;
6
7
use ReflectionClass;
8
use ReflectionNamedType;
9
10
use function is_object;
11
12
final class RouteEntity
13
{
14
    private static bool $isResponded = false;
15
16
    /**
17
     * @param object|class-string $controller
0 ignored issues
show
Documentation Bug introduced by
The doc comment object|class-string at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in object|class-string.
Loading history...
18
     */
19 40
    public function __construct(
20
        private string $method,
21
        private string $path,
22
        private object|string $controller,
23
        private string $action = '__invoke',
24
    ) {
25 40
    }
26
27
    /**
28
     * @internal for testing
29
     */
30 40
    public static function reset(): void
31
    {
32 40
        self::$isResponded = false;
33
    }
34
35 40
    public function requestMatches(): bool
36
    {
37 40
        if (self::$isResponded) {
38 1
            return false;
39
        }
40
41 40
        if (!$this->methodMatches()) {
42 1
            return false;
43
        }
44
45 39
        if (!$this->pathMatches()) {
46 1
            return false;
47
        }
48
49 38
        return true;
50
    }
51
52
    /**
53
     * @psalm-suppress MixedMethodCall
54
     */
55 38
    public function run(): string
56
    {
57 38
        self::$isResponded = true;
58
59 38
        if (is_object($this->controller)) {
60
            return (string)$this->controller
61
                ->{$this->action}(...$this->getParams());
62
        }
63 38
        return (string)(new $this->controller())
64 38
            ->{$this->action}(...$this->getParams());
65
    }
66
67 40
    private function methodMatches(): bool
68
    {
69 40
        return Request::method() === $this->method;
70
    }
71
72 39
    private function pathMatches(): bool
73
    {
74 39
        return (bool)preg_match($this->getPathPattern(), Request::path());
75
    }
76
77 39
    private function getPathPattern(): string
78
    {
79 39
        $pattern = preg_replace('#({.*})#U', '(.*)', $this->path);
80 39
        return '#^/' . $pattern . '$#';
81
    }
82
83 38
    private function getParams(): array
84
    {
85 38
        $params = [];
86 38
        $pathParamKeys = [];
87 38
        $pathParamValues = [];
88
89 38
        preg_match($this->getPathPattern(), '/' . $this->path, $pathParamKeys);
90 38
        preg_match($this->getPathPattern(), Request::path(), $pathParamValues);
91
92 38
        unset($pathParamValues[0], $pathParamKeys[0]);
93 38
        $pathParamKeys = array_map(static fn ($key) => trim($key, '{}'), $pathParamKeys);
94
95 38
        $pathParams = array_combine($pathParamKeys, $pathParamValues);
96 38
        $actionParams = (new ReflectionClass($this->controller))
97 38
            ->getMethod($this->action)
98 38
            ->getParameters();
99
100 38
        foreach ($actionParams as $actionParam) {
101 36
            $paramName = $actionParam->getName();
102
            /** @var string|null $paramType */
103 36
            $paramType = null;
104
105 36
            if ($actionParam->getType() && is_a($actionParam->getType(), ReflectionNamedType::class)) {
106 36
                $paramType = $actionParam->getType()->getName();
107
            }
108
109 36
            $value = match ($paramType) {
110 36
                'string' => $pathParams[$paramName],
111 36
                'int' => (int)$pathParams[$paramName],
112 36
                'float' => (float)$pathParams[$paramName],
113 36
                'bool' => (bool)json_decode($pathParams[$paramName]),
114 36
                null => null,
115 36
            };
116
117 36
            $params[$paramName] = $value;
118
        }
119
120 38
        return $params;
121
    }
122
}
123