Files
novaconium/docs/Router.md
2026-06-30 01:35:55 -07:00

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:

  1. Load routes — merges framework-level routes with app-level routes.
  2. Prepare path — normalizes REQUEST_URI into a clean path string.
  3. Prepare query — parses the query string into an array.
  4. Determine request typeget or post.
  5. Find controller — matches the path against the route table.
  6. 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/ErrorsFRAMEWORKPATH/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:

  1. If it starts with NOVACONIUM, look in FRAMEWORKPATH/controllers/.
  2. Otherwise, look in BASEPATH/App/controllers/.
  3. If the file exists, use it.
  4. If not, fall back to BASEPATH/App/controllers/404.php if it exists.
  5. 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}), only id is extracted into $this->parameters; postId is 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 get but the request is post), the router still commits to that route and returns null as 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'];