Routes::redirect()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 4
dl 0
loc 10
ccs 3
cts 3
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Router\Configure;
6
7
use Gacela\Router\Controllers\RedirectController;
8
use Gacela\Router\Entities\Request;
9
use Gacela\Router\Entities\Route;
10
use Gacela\Router\Exceptions\MalformedPathException;
11
use Gacela\Router\Exceptions\UnsupportedHttpMethodException;
12
use Gacela\Router\Validators\PathValidator;
13
use RuntimeException;
14
15
use function in_array;
16
use function is_array;
17
18
/**
19
 * @method Route head(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
20
 * @method Route connect(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
21
 * @method Route get(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
22
 * @method Route post(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
23
 * @method Route put(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
24
 * @method Route patch(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
25
 * @method Route delete(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
26
 * @method Route options(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
27
 * @method Route trace(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
28
 * @method Route any(string $path, object|string $controller, string $action = '__invoke', ?string $pathPattern = null)
29
 */
30
final class Routes
31
{
32
    /** @var list<Route> */
33
    private array $routes = [];
34
35
    /**
36
     * @param array<mixed> $arguments
37
     *
38 86
     * @psalm-suppress MixedArgument
39
     */
40 86
    public function __call(string $method, array $arguments): Route
41 9
    {
42
        if ($method === 'any') {
43 77
            /** @phpstan-ignore-next-line argument.type */
44
            return $this->addRoute(Request::ALL_METHODS, ...$arguments);
45
        }
46
        /** @phpstan-ignore-next-line argument.type */
47
        return $this->addRoute($method, ...$arguments);
48
    }
49
50
    /**
51
     * @psalm-suppress MixedArgument
52
     *
53 8
     * @param string[] $methods
54
     * @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...
55
     */
56
    public function match(
57
        array $methods,
58
        string $path,
59
        object|string $controller,
60 8
        string $action = '__invoke',
61
        ?string $pathPattern = null,
62
    ): Route {
63 15
        return $this->addRoute($methods, $path, $controller, $action, $pathPattern);
64
    }
65
66
    public function redirect(
67
        string $uri,
68
        string $destination,
69 15
        int $status = 302,
70 10
        ?string $method = null,
71
    ): void {
72 5
        if ($method === null) {
73
            $this->addRoute(Request::ALL_METHODS, $uri, new RedirectController($destination, $status));
74
        } else {
75
            $this->addRoute([$method], $uri, new RedirectController($destination, $status));
76
        }
77
    }
78
79 104
    /**
80
     * @return list<Route>
81 104
     */
82
    public function getAllRoutes(): array
83
    {
84
        return $this->routes;
85
    }
86
87
    /**
88 109
     * @param string[]|string $methods
89
     * @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...
90
     */
91
    private function addRoute(
92
        array|string $methods,
93
        string $path,
94
        object|string $controller,
95 109
        string $action = '__invoke',
96 6
        ?string $pathPattern = null,
97
    ): Route {
98
        if (!PathValidator::isValid($path)) {
99 103
            throw MalformedPathException::withPath($path);
100 71
        }
101
102 103
        if (!is_array($methods)) {
0 ignored issues
show
introduced by
The condition is_array($methods) is always true.
Loading history...
103
            $methods = [$methods];
104 103
        }
105
        $methods = array_map(static fn ($method) => strtoupper($method), $methods);
106 103
107 103
        $path = ($path === '/') ? '' : $path;
108 1
109
        $firstRoute = null;
110
        foreach ($methods as $method) {
111 102
            if (!in_array($method, Request::ALL_METHODS, true)) {
112
                throw UnsupportedHttpMethodException::withName($method);
113
            }
114
115
            $route = new Route($method, $path, $controller, $action, $pathPattern);
116
            $this->routes[] = $route;
117
118
            // Store the first route to return for middleware chaining
119
            if ($firstRoute === null) {
120
                $firstRoute = $route;
121
            }
122
        }
123
124
        return $firstRoute ?? throw new RuntimeException('No routes were created');
125
    }
126
}
127