Test Failed
Pull Request — main (#35)
by
unknown
02:24
created

Route::calculateDefaultPathPattern()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 5
nop 0
dl 0
loc 19
ccs 0
cts 0
cp 0
crap 30
rs 9.5555
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Router\Entities;
6
7
use Gacela\Container\Container;
8
use Gacela\Router\Configure\Bindings;
9
use Gacela\Router\Exceptions\UnsupportedResponseTypeException;
10
use Stringable;
11
12
use function is_object;
13
use function is_string;
14
15
final class Route
16
{
17
    /**
18
     * @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...
19
     */
20 95
    public function __construct(
21
        private string $method,
22
        private string $path,
23
        private object|string $controller,
24
        private string $action = '__invoke',
25
        private ?string $pathPattern = null,
26 95
    ) {
27
    }
28
29
    /**
30
     * @psalm-suppress MixedMethodCall
31 90
     */
32
    public function run(Bindings $bindings): string|Stringable
33 90
    {
34
        $params = (new RouteParams($this))->getAll();
35 88
36 63
        if (!is_object($this->controller)) {
37
            $creator = new Container($bindings->getAllBindings());
38 63
            /** @var object $controller */
39 63
            $controller = $creator->get($this->controller);
40
            $response = $controller->{$this->action}(...$params);
41
        } else {
42 25
            /** @var string|Stringable $response */
43
            $response = $this->controller->{$this->action}(...$params);
44
        }
45 83
46 4
        if (!is_string($response) && !($response instanceof Stringable)) {
47
            throw UnsupportedResponseTypeException::fromType($response);
48
        }
49 79
50
        return $response;
51
    }
52 90
53
    public function path(): string
54 90
    {
55
        return $this->path;
56
    }
57
58
    /**
59
     * @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...
60 90
     */
61
    public function controller(): object|string
62 90
    {
63
        return $this->controller;
64
    }
65 90
66
    public function action(): string
67 90
    {
68
        return $this->action;
69
    }
70 90
71
    public function getPathPattern(): string
72 90
    {
73
        if ($this->pathPattern === null) {
74 90
            $this->pathPattern = $this->calculateDefaultPathPattern();
75
        }
76
77 95
        return $this->pathPattern;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->pathPattern could return the type null which is incompatible with the type-hinted return string. Consider adding an additional type-check to rule them out.
Loading history...
78
    }
79 95
80
    public function requestMatches(): bool
81
    {
82 95
        return $this->methodMatches() && $this->pathMatches();
83
    }
84 95
85
    private function methodMatches(): bool
86
    {
87 90
        return Request::fromGlobals()->isMethod($this->method);
88
    }
89 90
90
    private function pathMatches(): bool
91 90
    {
92 90
        $path = Request::fromGlobals()->path();
93
94
        return (bool)preg_match($this->getPathPattern(), $path);
95 3
    }
96
97 3
    /**
98
     * @todo: improve this method and maybe move it to a separate class
99 3
     *
100
     * @return string
101
     */
102
    private function calculateDefaultPathPattern(): string
103
    {
104
        if ($this->path === '') {
105
            return '#^/?$#';
106
        }
107
108
        $parts = explode('/', $this->path);
109
        $pattern = '';
110
        foreach ($parts as $part) {
111
            if (preg_match('#({.*[^?]})#U', $part)) {
112
                $pattern .= '/([^\/]+)';
113
            } elseif (preg_match('#(/?{.*\?})#U', $part)) {
114
                $pattern .= '/?([^\/]+)?';
115
            } else {
116
                $pattern .= '/' . $part;
117
            }
118
        }
119
120
        return '#^/' . ltrim($pattern, '/') . '$#';
121
    }
122
}
123