*/ private array $namedRoutes = []; public function __construct() { $this->root = new PathSegment(type: PathSegmentType::Root); $this->strategy = new BasicStrategy(); } public function getStrategy(): Strategy { return $this->strategy; } public function setStrategy(Strategy $strategy): void { $this->strategy = $strategy; } public function root(): PathSegment { return $this->root; } /** @return string[] */ private function splitPath(string $path): array { $split = explode('/', rtrim($path, '/')); array_shift($split); return $split; } public function findSegment(string $path): ?PathSegmentMatch { $pathSplit = $this->splitPath($path); $seg = $this->root(); $params = []; while (($v = array_shift($pathSplit)) !== null && null !== $seg) { $seg = $seg->findChild($v); if (PathSegmentType::Parameter === $seg?->getType()) { $params[$seg->getValue() ?? ''] = $v; } } return null === $seg ? null : new PathSegmentMatch( segment: $seg, parameters: $params ); } public function findRoute(HttpMethod|string $method, string $path): ?RouteMatch { $match = $this->findSegment($path); if (null === $match) { return null; } $method = ( $method instanceof HttpMethod ? $method : HttpMethod::tryFrom(strtolower($method)) ); if (null === $method) { return null; } $segment = $match->segment; $route = $segment->getRoute($method); $route ??= $segment->getRoute(HttpMethod::Any); if (null === $route) { return null; } return new RouteMatch( $match, $route, ); } public function dispatch(RequestInterface $request): ResponseInterface { $uri = $request->getUri(); $match = $this->findRoute($request->getMethod(), $uri->getPath()); if (null === $match) { return $this->strategy->notFound($request); } $call = new RouteCall( $request, $match->route, $match->segmentMatch->parameters, ); return $this->strategy->runRoute($call); } public function make( HttpMethod $method, string $path, callable $handler, ): RouteDefinition { $pathSplit = $this->splitPath($path); $seg = $this->root(); while (($v = array_shift($pathSplit)) !== null) { $seg = $seg->child($v); } $route = new Route($method, $handler); $seg->addRoute($route); return new RouteDefinition($this, $route); } public function get(string $path, callable $handler): RouteDefinition { return $this->make(HttpMethod::Get, $path, $handler); } public function post(string $path, callable $handler): RouteDefinition { return $this->make(HttpMethod::Post, $path, $handler); } public function put(string $path, callable $handler): RouteDefinition { return $this->make(HttpMethod::Put, $path, $handler); } public function patch(string $path, callable $handler): RouteDefinition { return $this->make(HttpMethod::Patch, $path, $handler); } public function delete(string $path, callable $handler): RouteDefinition { return $this->make(HttpMethod::Delete, $path, $handler); } public function any(string $path, callable $handler): RouteDefinition { return $this->make(HttpMethod::Any, $path, $handler); } public function addNamedRoute(string $name, Route $route): void { $this->namedRoutes[$name] = $route; } public function getNamedRoute(string $name): ?Route { return $this->namedRoutes[$name] ?? null; } }