Controladores
Escribiendo controladores de Nibiru — el ciclo de vida de la acción, View::assign y patrones del código de producción.
Un controlador de Nibiru es una clase que extiende Nibiru\Adapter\Controller, reside en application/controller/<nombre>Controller.php, y se carga automáticamente por el Dispatcher cuando llega una URL como /<nombre>/....
Anatomía de un controlador
Sección titulada «Anatomía de un controlador»<?phpnamespace Nibiru;use Nibiru\Adapter\Controller;
class productsController extends Controller{ public function pageAction() { View::assign([ 'title' => 'Products', 'products' => $this->loadProducts(), ]); }
public function navigationAction() { JsonNavigation::getInstance()->loadJsonNavigationArray(); }
public function detailAction() { $id = (int) ($_REQUEST['id'] ?? 0); View::assign(['product' => $this->loadProduct($id)]); }
private function loadProducts(): array { /* ... */ return []; } private function loadProduct(int $id): array { /* ... */ return []; }}El ciclo de vida de la acción
Sección titulada «El ciclo de vida de la acción»Cuando el despachador invoca un controlador, llama a los métodos en este orden fijo:
navigationAction()— poblar menús globales, migas de pan, navegación consciente del rol.<verb>Action()— solo si?_action=<verb>está establecido o la URL tiene un segundo segmento que nombra una acción.pageAction()— último llamado antes del renderizado.
Tanto navigationAction() como pageAction() son siempre llamados, incluso para acciones desconocidas. Esto es conveniente (nunca necesitas verificarlo), pero puede sorprenderte si asumes que las acciones son exclusivas.
Hablando con la vista
Sección titulada «Hablando con la vista»View::assign(['key' => $value, ...]) es cómo llega la información a las plantillas. Es estático y puede llamarse tantas veces como desees — las llamadas posteriores sobrescriben a las anteriores.
View::assign(['title' => 'Products']);View::assign(['products' => $list]);
// In templates/products.tpl:// {$title} → "Products"// {$products} → the arrayAyudantes de conveniencia del controlador base:
$this->getRequest('id', false); / $_REQUEST['id'] ?? false$this->getPost('email', ''); / $_POST['email'] ?? ''$this->getGet('page', 1); / $_GET['page'] ?? 1$this->getServer('REQUEST_URI'); / $_SERVER['REQUEST_URI']$this->getFiles('upload'); / $_FILES['upload']$this->getSession('auth'); / $_SESSION['auth']Estos existen porque Controller es amigable con final: puedes simularlos en pruebas sustituyendo una clase hija.
Reenvío
Sección titulada «Reenvío»Para redirigir dentro de una acción:
View::forwardTo('/login'); / 302 to the URL, exitsView::forwardToJsonHeader(); / sets Content-Type: application/jsonforwardToJsonHeader() es el patrón canónico para puntos finales JSON — establece la cabecera, asigna data, y devuelve. La capa de vista se encarga del resto.
Múltiples acciones por controlador
Sección titulada «Múltiples acciones por controlador»Nibiru está feliz de alojar cualquier número de acciones por controlador. El TPMS erpController de producción tiene pageAction, navigationAction, además de syncAction, statusAction, dryRunAction, cancelAction, etc. — cada una invocada a través de ?_action=sync o /erp/sync.
// /erp/sync → $_REQUEST['_action'] = 'sync'public function syncAction(): void{ View::forwardToJsonHeader(); if ($_SERVER['REQUEST_METHOD'] !== 'POST') { View::assign(['data' => ['success' => false, 'error' => 'POST method required']]); return; } $result = AlphaplanSyncService::getInstance()->syncAbDocuments(); View::assign(['data' => $result]);}Trabajando con módulos
Sección titulada «Trabajando con módulos»Los controladores son delgados. La mayoría de la lógica debe residir en los módulos y sus complementos:
namespace Nibiru;use Nibiru\Adapter\Controller;use Nibiru\Module\Users\Plugin\User;
class loginController extends Controller{ private User $user;
public function __construct() { parent::__construct(); $this->user = new User(); }
public function authAction() { if (!$this->user->isAuthorized()) { View::assign(['loginForm' => $this->user->loginForm()]); } else { View::forwardTo('/index'); } }}Este patrón de delegación es consistente en todas las aplicaciones de demostración: los controladores orquestan y los módulos realizan el trabajo.
Contenido multilingüe / gestionado por CMS
Sección titulada «Contenido multilingüe / gestionado por CMS»Un patrón de prod.maschinen-stockert.de — carga todo el texto en página desde una tabla CMS claveada por la ruta del controlador:
public function pageAction() { $controllerPath = $this->getController() . '/' . $this->getRequest('_action', 'page');
$texts = Cms::init($this->getController()) ->loadCmsTemplateTextsByControllerPath($controllerPath, $this->language);
foreach ($texts as $t) { View::assign([ $t['cms_template_texts_text_identifier'] => $t['cms_template_texts_text_content'] ]); }}Resultado: los no desarrolladores pueden cambiar el texto sin tocar el código. El módulo de CMS posee la tabla y la interfaz de edición; el controlador solo carga las cadenas.
Generando controladores
Sección titulada «Generando controladores»La CLI genera un controlador y su plantilla en un solo paso:
./nibiru -c products→ application/controller/productsController.php
→ application/view/templates/products.tpl
Ambos están poblados con el esqueleto canónico. Estás listo para escribir.