Skip to content
Nibiru docsv0.9.2

Routing

How Nibiru maps URLs to controllers, actions and parameters — including SEO-friendly URL forms.

Stable Reading time ~ 2 min Edit on GitHub

Nibiru routing is convention-based with optional regex routes from settings.<env>.ini for special cases. There’s no big route file to maintain.

/<controller>/<action>/<param1>/<param2>/...

Examples:

URLControllerAction$_REQUEST
/indexController(none)
/productsproductsController(none)
/products/detailproductsControllerdetailAction
/products/detail/42productsControllerdetailActionid => 42
/users/edit/42usersControllereditActionid => 42

Without an _action, only navigationAction() and pageAction() run. With _action, the named action runs in between.

Nibiru auto-detects SEO-friendly URLs without any configuration. The pattern:

/<controller>/<slug>/<numeric-id>

If the second segment is not a method name on the controller and the third segment is numeric, Nibiru rewrites the request internally to:

/<controller>/detail/?id=<numeric-id>&slug=<slug>

So a URL like /maschine/marduk-gold-plating/42 reaches maschineController::detailAction() with $_REQUEST['id'] === '42' and $_REQUEST['slug'] === 'marduk-gold-plating'. This is exactly how the production e-commerce site prod.maschinen-stockert.de produces clean URLs without a custom router.

Anything past the action segment becomes a $_REQUEST key paired by position:

// /users/edit/42 → $_REQUEST['id'] = '42'
public function editAction() {
$id = (int) ($_REQUEST['id'] ?? 0);
/ ...
}

For non-numeric or named parameters, prefer query strings:

/users/search?q=marduk&page=2

The [NIBIRU_ROUTING] section in settings.<env>.ini lets you map regex URL patterns to controller/action pairs and named params:

[NIBIRU_ROUTING]
; Map /api/v1/products/42 to apiController::productsAction with id=42
api.v1.products.pattern = "^/api/v1/products/(\d+)$"
api.v1.products.controller = "api"
api.v1.products.action = "products"
api.v1.products.params[] = "id"

When a URL matches the pattern, capture groups are assigned to the named params[] keys (in order) as $_REQUEST entries.

Router::getInstance()->currentPage(); / 'products'
Router::getInstance()->tplName(); / 'products' (controller stem for templates)
Router::getInstance()->getController(); / alias for currentPage()

These are useful inside controllers and templates:

<a href="/products" class="{if Router::currentPage() == 'products'}active{/if}">
Products
</a>

(In Smarty you’d use a Smarty plugin or a pre-assigned variable; the helper itself is for PHP.)

To redirect at the framework level (sets the right HTTP headers and exits):

View::forwardTo('/login');

For a JSON response (sets Content-Type: application/json):

View::forwardToJsonHeader();
View::assign(['data' => ['ok' => true]]);

This pattern is used heavily by API endpoints in production — see the apiController in data.maschinen-stockert.de.

Nibiru’s pagination expects URLs of the form:

/<controller>/<action>/page/<N>

The Pageination class parses the trailing page/N segment, so any route format that preserves it is fine.

URLs are matched case-sensitively. /Users/edit and /users/edit will hit different controllers (the second exists, the first 404s). Trailing slashes are tolerated.

  • Action collision with SEO URL. If you name a method aboutAction() and try to use /products/about/42 as an SEO URL, the SEO rewrite won’t trigger, because about is a known action. Pick slugs that don’t collide with action names.
  • Action without _action. Just typing /products/detail/ does not call detailAction()_action must be set. The dispatcher does this automatically when the URL has at least two segments, but a stripped query string won’t.
  • index is the root controller. /indexController. There is no separate “home” route.