Migrate some improvements to the router.

This commit is contained in:
Sky Johnson 2024-12-14 18:44:33 -06:00
parent 02533addb4
commit 3bc53c1a31
3 changed files with 13 additions and 31 deletions

View File

@ -45,7 +45,7 @@ $r->form('/babblebox', 'babblebox');
// [code, handler, params, middleware]
$l = $r->lookup($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
if ($l['code'] !== 200) exit("Error: {$l['code']}");
if (is_int($l)) exit("Error: $l");
if (!empty($l['middleware'])) foreach ($l['middleware'] as $middleware) $middleware();
$l['handler'](...$l['params'] ?? []);

View File

@ -24,7 +24,6 @@ function move()
$town = get_town_by_xy($longitude, $latitude);
if ($town !== false) {
require_once __DIR__ . '/towns.php';
Towns\travelto($town['id'], false);
return;
}

View File

@ -33,23 +33,20 @@ class Router
$this->validateMethod($method);
$this->validateRoute($route);
// Expand the route into segments and make dynamic segments into a common placeholder
$segments = array_map(function($segment) {
return str_starts_with($segment, ':') ? ':x' : $segment;
}, explode('/', trim($route, '/')));
$segments = $route === '/' ? [''] : explode('/', trim($route, '/'));
// Push each segment into the routes array as a node, except if this is the root node
$node = &$this->routes;
foreach ($segments as $segment) {
// skip an empty segment, which allows us to register handlers for the root node
$segment = str_starts_with($segment, ':') ? ':x' : $segment;
if ($segment === '') continue;
$node = &$node[$segment]; // build the node tree as we go
$node = &$node[$segment];
}
// Add the handler to the last node
$node[$method] = ['handler' => $handler, 'middleware' => []];
$node[$method] = [
'handler' => $handler,
'middleware' => []
];
// Store a reference to the node so we can add middleware to it.
$this->last_inserted_node = &$node[$method];
return $this;
@ -62,44 +59,30 @@ class Router
*
* @return array ['code', 'handler', 'params']
*/
public function lookup(string $method, string $uri): array
public function lookup(string $method, string $uri): array|int
{
// node is a reference to our current location in the node tree
$node = $this->routes;
// params will hold any dynamic segments we find
$params = [];
// if the URI is just a slash, we can return the handler for the root node
if ($uri === '/') {
return isset($node[$method])
? ['code' => 200, 'handler' => $node[$method]['handler']]
: ['code' => 405];
}
if ($uri === '/') return $node[$method] ?? 405;
// We'll split up the URI into segments and traverse the node tree
foreach (explode('/', trim($uri, '/')) as $segment) {
// if there is a node for this segment, move to it
if (isset($node[$segment])) {
$node = $node[$segment];
continue;
}
// if there is a dynamic segment, move to it and store the value
if (isset($node[':x'])) {
$params[] = $segment;
$node = $node[':x'];
continue;
}
// if we can't find a node for this segment, return 404
return ['code' => 404];
return 404;
}
// if we found a handler for the method, return it and any params. if not, return a 405
return isset($node[$method])
? ['code' => 200, 'handler' => $node[$method]['handler'], 'params' => $params ?? [], 'middleware' => $node[$method]['middleware']]
: ['code' => 405];
$node[$method]['params'] = $params;
return $node[$method] ?? 405;
}
/**