*/ private array $namedRoutes = []; public function __construct() { $this->root = new PathSegment(type: PathSegmentType::Root); $this->strategy = new BasicStrategy(); } private function getRouter(): self { return $this; } private function getGroup(): null { return null; } 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 { if (in_array($path, ['', '/'], true)) { $split = []; } else { $split = explode('/', trim($path, '/')); } 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); } return $this->strategy->runMiddleware( $request, [], fn ($request) => $this->strategy->runRoute(new RouteCall( $request, $match->route, $match->segmentMatch->parameters, )) ); } public function make( HttpMethod $method, string $path, callable $handler, ): RouteDefinition { $pathSplit = $this->splitPath($path); $seg = $this->root(); while (($v = array_shift($pathSplit)) !== null) { $typeMatch = PathSegmentType::matchRouteString($v); $seg = $seg->child($typeMatch->value, $typeMatch->type); } $route = new Route($method, $handler); $seg->addRoute($route); return new RouteDefinition($this, $route); } public function addNamedRoute(string $name, Route $route): void { $this->namedRoutes[$name] = $route; } public function getNamedRoute(string $name): ?Route { return $this->namedRoutes[$name] ?? null; } /** @param array $params */ public function route(string $name, array $params = []): ?string { $route = $this->getNamedRoute($name); $params = $this->strategy->parseParameters($params); return $route?->getPath($params); } }