gacela-project /
router
| 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
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
|
|||
| 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
|
|||
| 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 |