Claude redid the router
This commit is contained in:
101
docs/Router.md
Normal file
101
docs/Router.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# 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 type** — `get` 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:
|
||||
|
||||
```php
|
||||
$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](#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
|
||||
|
||||
```php
|
||||
$router = new \Novaconium\Router();
|
||||
|
||||
include $router->controllerPath;
|
||||
|
||||
// Inside the controller, access route parameters via:
|
||||
$router->parameters['id'];
|
||||
```
|
||||
Reference in New Issue
Block a user