Bootstrap & Dispatcher
How a Nibiru request flows from index.php through the dispatcher to your controller.
A Nibiru request takes one trip through three files: index.php, core/framework.php, and core/c/dispatcher.php. Reading them in that order tells you everything.
index.php
Section titled “index.php”<?phprequire_once 'core/framework.php';That’s the whole file. index.php exists only to give the web server a target.
core/framework.php
Section titled “core/framework.php”framework.php requires the framework’s classes in dependency order — settings, registry, router, engine, autoloader, all DB drivers, all 28 form types, view, controller, modules, auth, debug, display — and finishes with:
Nibiru\Dispatcher::getInstance()->run();That single call is your application’s heartbeat.
Dispatcher::run()
Section titled “Dispatcher::run()”The simplified flow:
public function run() { date_default_timezone_set(Config::getInstance()->getConfig() [View::NIBIRU_SETTINGS]['timezone']);
if (Config::getInstance()->getConfig() [self::CONFIG_GENERATOR_SECTION][self::GENERATOR_DATABASE]) { new Model(false); / 1. (re)generate models from schema }
Router::getInstance()->route(); / 2. parse the URL Auto::loader()->loadModelFiles(); / 3. load model files Auto::loader()->loadModules(); / 4. load module classes
$tpl = Router::getInstance()->tplName(); $controllerFile = __DIR__ . "/../../application/controller/{$tpl}Controller.php";
if (is_file($controllerFile)) { / 5. controller file exists require_once $controllerFile; $class = "Nibiru\\{$tpl}Controller"; $controller = new $class();
if (array_key_exists('_action', $_REQUEST)) { $action = $_REQUEST['_action'] . 'Action'; $controller->navigationAction(); if (method_exists($controller, $action)) { $controller->$action(); / 6. optional named action } $controller->pageAction(); } else { $controller->navigationAction(); $controller->pageAction(); }
Display::getInstance()->display(); / 7. render Smarty } else { / 8. soft 404 — render the configured error controller }}The action sequence
Section titled “The action sequence”Every request goes through the same three steps if ?_action=foo is set:
navigationAction()— populate menus, breadcrumbs.fooAction()— run the named action.pageAction()— last chance to assign template data.
Without _action, only steps 1 and 3 run.
This means stateless render-time logic belongs in pageAction(), and navigation data belongs in navigationAction(), even if it feels like duplicating effort. Two controllers in the same project will both have a navigationAction(); that’s correct.
Soft 404
Section titled “Soft 404”If the matched controller file doesn’t exist, Nibiru renders a soft 404 — it returns a 200 OK and renders the controller named in [ENGINE] error.controller (default: error). This is intentional: it lets you serve nice error pages without server-level configuration.
If you want a real 404 Not Found HTTP code, set it in your error controller:
public function pageAction() { http_response_code(404); View::assign(['title' => 'Lost in the void']);}Auto::loader()
Section titled “Auto::loader()”Two auto-loaders run before the controller is constructed:
loadModelFiles()scansapplication/model/and includes every.phpfile there. Generated models are flat files, not namespaced packages, so this is a simplerequire_onceloop.loadModules()walksapplication/module/<name>/and loads each module’s main class plus its trait, plugin and interface files. The Registry indexes each module’s settings INI at the same time.
Both use the configured paths in [SETTINGS] modules.path etc., so you can override them per environment.
SEO URL handling
Section titled “SEO URL handling”Before the controller resolution, Router::route() runs handleSeoUrls() which detects URLs of the form /controller/<slug>/<id> (where the second segment is not a known action and the third is numeric). Those get rewritten internally to /controller/detail/ with $_REQUEST['id'] and $_REQUEST['slug'] populated. Read more in Routing.
When to override the dispatcher
Section titled “When to override the dispatcher”Almost never. The cleaner extension points are:
- Custom error controller — set
[ENGINE] error.controller. - Pre-controller hooks — load a module that registers an observer, then attach it inside
navigationAction(). - Cron-style entry — run the framework headless via the
nibiruCLI rather thanindex.php.