5.2 KiB
Router
Novaconium\Router resolves the current HTTP request to a controller file, based on a route table defined in PHP config files. It supports exact-match routes and simple parameterized routes (e.g. /users/{id}).
How it works
On construction, the router runs through this pipeline:
- Load routes — merges framework-level routes with app-level routes.
- Prepare path — normalizes
REQUEST_URIinto a clean path string. - Prepare query — parses the query string into an array.
- Determine request type —
getorpost. - Find controller — matches the path against the route table.
- Resolve controller file — turns the matched controller string into an actual file path, falling back to a 404 controller if needed.
Properties
| Property | Type | Description |
|---|---|---|
$routes |
array | Combined route table (framework + app routes), keyed by path pattern. |
$query |
array | Parsed query string parameters. |
$path |
string | Normalized request path. |
$controller |
string | Resolved controller identifier (e.g. Users/show or NOVACONIUM/Errors). |
$controllerPath |
string | Absolute file path to the controller. |
$parameters |
array | Named parameters extracted from a parameterized route match. |
$requestType |
string | 'get' or 'post'. |
Route table format
Routes are defined as an associative array, keyed by URL path. Each entry maps HTTP methods to a controller string:
$routes = [
'/' => [
'get' => 'Home/index',
],
'/users/{id}' => [
'get' => 'Users/show',
],
'/login' => [
'get' => 'Auth/loginForm',
'post' => 'Auth/login',
],
];
Controller strings starting with NOVACONIUM are resolved against the framework's controller directory (e.g. NOVACONIUM/Errors → FRAMEWORKPATH/controllers/Errors.php); all other controller strings are resolved against the app's controller directory (BASEPATH/App/controllers/).
Matching behavior
1. Exact match
The router first checks for an exact match between $this->path and a key in $this->routes. If found, and the current request type has a handler defined, that controller is returned immediately.
2. Parameterized match
If no exact match is found, the router scans the route table for patterns containing {. For each candidate:
- The static prefix of the pattern (everything before the first
{) must prefix-match the current path. - The pattern and the path must have the same number of
/-separated segments.
The first route pattern satisfying both conditions is treated as the match — the router does not keep searching for a "better" match after this point, even if the matched route turns out to have no handler for the current request method (see Known quirks below).
Once a candidate route is selected, the router walks its segments looking for the first {param} segment, extracts the corresponding path segment into $this->parameters[paramName], and returns immediately with the controller for the current request type.
3. No match
If neither an exact nor a parameterized match is found, $this->controller is set to '404', and setRouteFile() will fail to find a corresponding controller file, triggering the 404 fallback described below.
Controller file resolution (setRouteFile)
Given the resolved $this->controller string:
- If it starts with
NOVACONIUM, look inFRAMEWORKPATH/controllers/. - Otherwise, look in
BASEPATH/App/controllers/. - If the file exists, use it.
- If not, fall back to
BASEPATH/App/controllers/404.phpif it exists. - Otherwise, fall back to the framework's built-in
FRAMEWORKPATH/controllers/404.php.
Known quirks
These behaviors exist in the current implementation and are preserved intentionally for backward compatibility — they're documented here so they aren't mistaken for bugs during future changes.
- Only the first
{param}in a route pattern is captured. If a route pattern has multiple parameters (e.g./users/{id}/posts/{postId}), onlyidis extracted into$this->parameters;postIdis never processed, because the matching loop returns as soon as it finds the first parameter segment. - The first prefix+segment-count match wins, even without a method handler. If a parameterized route's static prefix and segment count match the request, but that route has no handler defined for the current request type (e.g. the route only defines
getbut the request ispost), the router still commits to that route and returnsnullas the controller (which then falls through to the 404 controller). It does not continue searching for another route that might have a valid handler. - No support for trailing wildcard or optional segments. Segment counts must match exactly between the pattern and the path; there's no support for
*or optional{param?}style segments.
Debugging
Call $router->debug() to dump the resolved path, controller path, extracted parameters, and full route table as an HTML table, then halt execution via die(). Intended for development use only.
Example
$router = new \Novaconium\Router();
include $router->controllerPath;
// Inside the controller, access route parameters via:
$router->parameters['id'];