Ir al contenido
Nibiru docsv0.9.2

Controladores

Escribiendo controladores de Nibiru — el ciclo de vida de la acción, View::assign y patrones del código de producción.

Stable Reading time ~ 3 min Edit on GitHub

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>/....

<?php
namespace 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 []; }
}

Cuando el despachador invoca un controlador, llama a los métodos en este orden fijo:

  1. navigationAction() — poblar menús globales, migas de pan, navegación consciente del rol.
  2. <verb>Action() — solo si ?_action=<verb> está establecido o la URL tiene un segundo segmento que nombra una acción.
  3. 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.

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 array

Ayudantes 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.

Para redirigir dentro de una acción:

View::forwardTo('/login'); / 302 to the URL, exits
View::forwardToJsonHeader(); / sets Content-Type: application/json

forwardToJsonHeader() 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.

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]);
}

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.

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.

La CLI genera un controlador y su plantilla en un solo paso:

Ventana de terminal
./nibiru -c products

application/controller/productsController.phpapplication/view/templates/products.tpl

Ambos están poblados con el esqueleto canónico. Estás listo para escribir.