public function route(string $method, string $uri, ...$actions) : Router
{
if ($this->state !== Server::STOPPED) {
throw new \LogicException("Cannot add routes once the server has started");
}
if ($method === "") {
throw new \DomainException(__METHOD__ . " requires a non-empty string HTTP method at Argument 1");
}
if (empty($actions)) {
throw new \DomainException(__METHOD__ . " requires at least one callable route action or middleware at Argument 3");
}
$actions = array_merge($this->actions, $actions);
$uri = "/" . ltrim($uri, "/");
// Special-case, otherwise we redirect just to the same URI again
if ($uri === "/?") {
$uri = "/";
}
if (substr($uri, -2) === "/?") {
$canonicalUri = substr($uri, 0, -2);
$redirectUri = substr($uri, 0, -1);
$this->routes[] = [$method, $canonicalUri, $actions];
$this->routes[] = [$method, $redirectUri, [static function (Request $request, Response $response) {
$uri = $request->getUri();
if (stripos($uri, "?")) {
list($path, $query) = explode("?", $uri, 2);
$path = rtrim($path, "/");
$redirectTo = "{$path}?{$query}";
} else {
$redirectTo = $path = substr($uri, 0, -1);
}
$response->setStatus(HTTP_STATUS["FOUND"]);
$response->setHeader("Location", $redirectTo);
$response->setHeader("Content-Type", "text/plain; charset=utf-8");
$response->end("Canonical resource URI: {$path}");
}]];
} else {
$this->routes[] = [$method, $uri, $actions];
}
return $this;
}