aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/Router.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/Router.php')
-rw-r--r--src/app/Router.php56
1 files changed, 56 insertions, 0 deletions
diff --git a/src/app/Router.php b/src/app/Router.php
new file mode 100644
index 0000000..9bfe09d
--- /dev/null
+++ b/src/app/Router.php
@@ -0,0 +1,56 @@
+<?php
+
+declare(strict_types=1);
+// Regex-based HTTP router that dispatches requests to controller methods.
+
+namespace App;
+
+class Router
+{
+ private array $routes = [];
+
+ public function get(string $path, string $controller, string $method): void
+ {
+ $this->routes[] = ['GET', $path, $controller, $method];
+ }
+
+ public function post(string $path, string $controller, string $method): void
+ {
+ $this->routes[] = ['POST', $path, $controller, $method];
+ }
+
+ public function dispatch(): void
+ {
+ $requestMethod = $_SERVER['REQUEST_METHOD'];
+ $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
+ $uri = rtrim($uri, '/') ?: '/';
+
+ foreach ($this->routes as [$method, $path, $controller, $action]) {
+ if ($method !== $requestMethod) {
+ continue;
+ }
+
+ // Convert route placeholders to named regex capture groups.
+ // Example with route '/post/{id}' and request '/post/42':
+ // 1. preg_replace turns '{id}' into '(?P<id>[^/]+)'
+ // result: '#^/post/(?P<id>[^/]+)$#'
+ // 2. preg_match against '/post/42' produces:
+ // [0 => '/post/42', 'id' => '42', 1 => '42']
+ // 3. array_filter keeps only string keys: ['id' => '42']
+ // 4. PostController->show('42') is called
+ $pattern = preg_replace('#\{(\w+)\}#', '(?P<$1>[^/]+)', $path);
+ $pattern = '#^' . $pattern . '$#';
+
+ if (preg_match($pattern, $uri, $matches)) {
+ $params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
+ $controllerClass = "App\\Controllers\\$controller";
+ $instance = new $controllerClass();
+ $instance->$action(...array_values($params));
+ return;
+ }
+ }
+
+ http_response_code(404);
+ echo '404 Not Found';
+ }
+}