---
title: "Bootstrap y Dispatcher"
description: "Cómo fluye una solicitud de Nibiru desde index.php a través del despachador hasta tu controlador."
---

Una solicitud de Nibiru realiza un viaje a través de tres archivos: `index.php`, `core/framework.php` y `core/c/dispatcher.php`. Leerlos en ese orden te dice todo lo que necesitas saber.

## index.php
```php
<?php
require_once 'core/framework.php';
```
Ese es todo el archivo. `index.php` existe solo para darle un objetivo al servidor web.

## core/framework.php

`framework.php` requiere las clases del framework en orden de dependencia — configuración, registro, enrutador, motor, cargador automático, todos los controladores de base de datos, todos los 28 tipos de formulario, vista, controlador, módulos, autenticación, depuración, visualización — y termina con:
```php
Nibiru\Dispatcher::getInstance()->run();
```
Esa única llamada es el latido del corazón de tu aplicación.

## Dispatcher::run()

El flujo simplificado:
```php
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
    }
}
```
## La secuencia de acción

Cada solicitud pasa por los mismos tres pasos si se establece `?_action=foo`:

1. `navigationAction()` — poblar menús, migas de pan.
2. `fooAction()` — ejecutar la acción nombrada.
3. `pageAction()` — última oportunidad para asignar datos de plantilla.

Sin `_action`, solo se ejecutan los pasos 1 y 3.

Esto significa que la **lógica de tiempo de renderizado sin estado pertenece en `pageAction()`**, y los **datos de navegación pertenecen en `navigationAction()`**, incluso si siente que está duplicando esfuerzos. Dos controladores en el mismo proyecto tendrán ambos un `navigationAction()`; eso es correcto.

## Soft 404

Si el archivo de controlador coincidente no existe, Nibiru renderiza un *404 suave* — devuelve un 200 OK y renderiza el controlador nombrado en `[ENGINE] error.controller` (por defecto: `error`). Esto es intencional: permite servir páginas de error agradables sin configuración de nivel de servidor.

Si quieres un código HTTP real de `404 Not Found`, configúralo en tu controlador de errores:
```php
public function pageAction() {
    http_response_code(404);
    View::assign(['title' => 'Lost in the void']);
}
```
## Auto::loader()

Dos auto-cargadores se ejecutan antes de que se construya el controlador:

- **`loadModelFiles()`** escanea `application/model/` e incluye cada archivo `.php` ahí. Los modelos generados son archivos planos, no paquetes con espacios de nombres, por lo que es un simple bucle `require_once`.
- **`loadModules()`** recorre `application/module/<name>/` y carga la clase principal de cada módulo, así como sus archivos de traza, complemento e interfaz. El Registro indexa las configuraciones INI de cada módulo al mismo tiempo.

Ambos utilizan las rutas configuradas en `[CONFIGURACIÓN] modules.path` etc., por lo que puedes sobrescribirlas por entorno.

## Manejo de URLs para SEO

Antes de la resolución del controlador, `Router::route()` ejecuta `handleSeoUrls()`, que detecta URLs con el formato `/controller/<slug>/<id>` (donde el segundo segmento *no* es una acción conocida y el tercero es numérico). Estas se reescriben internamente como `/controller/detail/` con `$_REQUEST['id']` y `$_REQUEST['slug']` poblados. Leer más en [Routing](/core/routing/).

## Cuando anular el despachador

Casi nunca. Los puntos de extensión más limpios son:

- **Controlador de errores personalizado** — establece `[ENGINE] error.controller`.
- **Ganchos pre-controlador** — carga un módulo que registra un observador, luego átalo dentro de `navigationAction()`.
- **Entrada estilo crontab** — ejecuta el framework en modo sin cabeza a través de la CLI `nibiru` en lugar de `index.php`.
