Passed
Pull Request — main (#2)
by Chema
03:17 queued 01:01
created

Route::controller()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Router;
6
7
use function is_object;
8
9
/**
10
 * @method static get(string $path, object|string $controller, string $action = '__invoke')
11
 * @method static head(string $path, object|string $controller, string $action = '__invoke')
12
 * @method static connect(string $path, object|string $controller, string $action = '__invoke')
13
 * @method static post(string $path, object|string $controller, string $action = '__invoke')
14
 * @method static delete(string $path, object|string $controller, string $action = '__invoke')
15
 * @method static options(string $path, object|string $controller, string $action = '__invoke')
16
 * @method static patch(string $path, object|string $controller, string $action = '__invoke')
17
 * @method static put(string $path, object|string $controller, string $action = '__invoke')
18
 * @method static trace(string $path, object|string $controller, string $action = '__invoke')
19
 */
20
final class Route
21
{
22
    /**
23
     * @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...
24
     */
25 42
    public function __construct(
26
        private string $method,
27
        private string $path,
28
        private object|string $controller,
29
        private string $action = '__invoke',
30
    ) {
31 42
    }
32
33
    /**
34
     * @param callable(RoutingConfigurator):void $fn
35
     */
36 42
    public static function configure(callable $fn): void
37
    {
38 42
        $routingConfigurator = new RoutingConfigurator();
39 42
        $fn($routingConfigurator);
40
41 42
        foreach ($routingConfigurator->routes() as $route) {
42 42
            if ($route->requestMatches()) {
43 40
                echo $route->run();
44 40
                break;
45
            }
46
        }
47
    }
48
49
    /**
50
     * @psalm-suppress MixedMethodCall
51
     */
52 40
    public function run(): string
53
    {
54 40
        $params = (new RouteParams($this))->asArray();
55
56 40
        if (is_object($this->controller)) {
57
            return (string)$this->controller
58
                ->{$this->action}(...$params);
59
        }
60
61 40
        return (string)(new $this->controller())
62 40
            ->{$this->action}(...$params);
63
    }
64
65 40
    public function path(): string
66
    {
67 40
        return $this->path;
68
    }
69
70
    /**
71
     * @return object|class-string
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...
72
     */
73 40
    public function controller(): object|string
74
    {
75 40
        return $this->controller;
76
    }
77
78 40
    public function action(): string
79
    {
80 40
        return $this->action;
81
    }
82
83 41
    public function getPathPattern(): string
84
    {
85 41
        $pattern = preg_replace('#({.*})#U', '(.*)', $this->path);
86
87 41
        return '#^/' . $pattern . '$#';
88
    }
89
90 42
    private function requestMatches(): bool
91
    {
92 42
        if (!$this->methodMatches()) {
93 1
            return false;
94
        }
95
96 41
        if (!$this->pathMatches()) {
97 1
            return false;
98
        }
99
100 40
        return true;
101
    }
102
103 42
    private function methodMatches(): bool
104
    {
105 42
        return Request::instance()->isMethod($this->method);
106
    }
107
108 41
    private function pathMatches(): bool
109
    {
110 41
        $path = Request::instance()->path();
111
112 41
        return preg_match($this->getPathPattern(), $path)
113 41
            || preg_match($this->getPathPatternWithoutOptionals(), $path);
114
    }
115
116 3
    private function getPathPatternWithoutOptionals(): string
117
    {
118 3
        $pattern = preg_replace('#/({.*\?})#U', '(/(.*))?', $this->path);
119
120 3
        return '#^/' . $pattern . '$#';
121
    }
122
}
123