router = new Router(); $this->errorHandler = new ErrorHandler($debug); $this->cookie = new Cookies($cookieDefaults); } public function use(callable $middleware): self { $this->middleware[] = $middleware; return $this; } public function get(string $route, callable $handler): self { $this->router->get($route, $handler); return $this; } public function post(string $route, callable $handler): self { $this->router->post($route, $handler); return $this; } public function put(string $route, callable $handler): self { $this->router->put($route, $handler); return $this; } public function patch(string $route, callable $handler): self { $this->router->patch($route, $handler); return $this; } public function delete(string $route, callable $handler): self { $this->router->delete($route, $handler); return $this; } public function head(string $route, callable $handler): self { $this->router->head($route, $handler); return $this; } public function route(string $method, string $route, callable $handler): self { $this->router->add($method, $route, $handler); return $this; } public function group(string $prefix, callable $callback): self { $originalRouter = $this->router; $groupRouter = new Router(); $this->router = $groupRouter; $callback($this); foreach ($groupRouter->dump() as $path => $methods) { $this->addGroupRoutes($originalRouter, $prefix, $path, $methods); } $this->router = $originalRouter; return $this; } public function setErrorHandler(int $status, callable $handler): self { $this->errorHandler->register($status, $handler); return $this; } public function setDefaultErrorHandler(callable $handler): self { $this->errorHandler->setDefaultHandler($handler); return $this; } private function addGroupRoutes(Router $router, string $prefix, string $path, mixed $node, string $currentPath = ''): void { if ($path !== '') $currentPath = $currentPath ? "$currentPath/$path" : $path; if (!is_array($node)) return; foreach ($node as $key => $value) { if (in_array($key, ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])) { $fullPath = rtrim($prefix, '/') . '/' . ltrim($currentPath, '/'); $fullPath = str_replace(':x', ':param', $fullPath); $router->add($key, $fullPath, $value); } elseif (is_array($value)) { $this->addGroupRoutes($router, $prefix, $key, $value, $currentPath); } } } public function run(): void { $this->context = new Context($this->cookie); try { $next = function() { $result = $this->router->lookup( $this->context->request->method, $this->context->request->path ); if ($result['code'] === 404) { $this->errorHandler->handle($this->context, 404); return; } if ($result['code'] === 405) { $this->errorHandler->handle($this->context, 405); return; } $this->context->request->params = $result['params']; $handler = $result['handler']; $response = $handler($this->context, ...$result['params']); if ($response instanceof Response) { $response->send(); } elseif (is_array($response) || is_object($response)) { $this->context->json($response); } elseif (is_string($response)) { $this->context->text($response); } }; $chain = array_reduce( array_reverse($this->middleware), function($next, $middleware) { return function() use ($middleware, $next) { $middleware($this->context, $next); }; }, $next ); $chain(); } catch (\Exception $e) { $this->errorHandler->handleException($this->context, $e); } } }