---
title: "Vistas & Smarty"
description: "Cómo se resuelven las plantillas .tpl, el flujo de trabajo View::assign, la caché y las partes parciales compartidas."
---

Las vistas en Nibiru son plantillas de **Smarty 3**. Cada controlador tiene una plantilla predeterminada; las acciones anidadas pueden tener sus propias plantillas. El singleton `View` envuelve el motor Smarty y expone un ayudante global: `View::assign()`.

## Donde viven las plantillas
```
application/view/
├── templates/                # source .tpl files (you write these)
│   ├── index.tpl             # → indexController::pageAction()
│   ├── products.tpl          # → productsController::pageAction()
│   ├── products/
│   │   └── detail.tpl        # → productsController::detailAction()
│   ├── shared/
│   │   ├── header.tpl
│   │   ├── footer.tpl
│   │   └── meta.tpl
│   ├── navigation.tpl
│   └── pageination.tpl       # (note the spelling)
├── templates_c/              # Smarty compile cache (auto)
├── cache/                    # rendered HTML cache (when caching=true)
└── mockup/                   # static design mockups
```
`templates_c/` es creado y gestionado por Smarty. **Debe ser escribible por el usuario de su servidor web.** `cache/` solo se utiliza cuando `[ENGINE] caching = true`.

## Reglas de resolución

La capa de presentación resuelve la ruta de la plantilla desde el controlador coincidente:

- Para `pageAction()` → `plantillas/<controlador>.tpl`.
- Para una acción nombrada `fooAction()` → `plantillas/<controlador>/foo.tpl` si existe, de lo contrario `plantillas/<controlador>.tpl`.

Si ninguna de las dos soluciones funciona, se renderiza la plantilla de error [soft 404](/core/dispatcher/#soft-404).

## Una plantilla mínima
```smarty
{include 'shared/header.tpl'}
<body>
{include file="navigation.tpl"}

<main class="container">
  <h1>{$title|escape}</h1>
  <ul>
    {foreach $products as $p}
      <li><a href="/products/detail/{$p.id}">{$p.name|escape}</a></li>
    {/foreach}
  </ul>
</main>

{include 'shared/footer.tpl'}
</body>
```
`{include 'shared/header.tpl'}` y `{include file="navigation.tpl"}` son ambos formas válidas de inclusión en Smarty.

## View::asignar

`View::assign()` es cómo los datos de PHP llegan a las plantillas. Es estática, idempotente y amigable con arrays:
```php
View::assign(['title' => 'Products']);
View::assign([
    'products' => $list,
    'count'    => count($list),
]);
```
Las llamadas posteriores sobrescriben a las anteriores para la misma clave. Dentro de las plantillas, estas se convierten en `{$title}`, `{$products}`, `{$count}`.

No hay un `View::display()` que llames manualmente — el despachador invoca automáticamente `Display::display()` después de que `pageAction()` retorna.

## Inyección compartida de CSS/JS

La convención utilizada en las aplicaciones de demostración es insertar la lista de activos configurados en la plantilla:
```php
View::assign([
    'css' => Config::getInstance()->getConfig()[View::NIBIRU_SETTINGS]['smarty.css'],
    'js'  => Config::getInstance()->getConfig()[View::NIBIRU_SETTINGS]['smarty.js'],
]);
``````smarty
{* shared/header.tpl *}
<head>
  <meta charset="utf-8">
  <title>{$title|escape}</title>
  {foreach $css as $stylesheet}
    <link rel="stylesheet" href="{$stylesheet}">
  {/foreach}
</head>
```
Entonces `[CONFIGURACIONES] smarty.css[]` en el archivo INI es la única fuente de verdad para las hojas de estilo.

## Caché

El almacenamiento en caché es opcional:
```ini
[ENGINE]
caching = true
```
Cuando está habilitado, Smarty almacena en caché el HTML renderizado en `application/view/cache/` con la vida útil `Smarty::CACHING_LIFETIME_CURRENT` (por defecto ≈ 1 hora). Limpia la caché con:
```bash
./nibiru -cache-clear
```
Esto borra tanto `templates_c/` como `cache/` de manera segura.

:::advertencia
Las páginas en caché no ejecutan su controlador. No cachees páginas con contenido específico del usuario o tokens CSRF.
:::

## Esenciales de Smarty

Cosas que alcanzarás diariamente:
```smarty
{* variables *}
{$user.name}
{$products[0].title}

{* iteration *}
{foreach $items as $item}
  ...
{foreachelse}
  No items.
{/foreach}

{* conditionals *}
{if $count > 0}…{else}…{/if}

{* string filters *}
{$body|escape}              {* HTML escape *}
{$date|date_format:"%Y-%m-%d"}
{$price|string_format:"%.2f"}

{* includes *}
{include file="shared/header.tpl" title=$title}

{* assigning *}
{assign var="now" value=time()}
```
## Respuestas JSON

Cuando una acción llama a `View::forwardToJsonHeader()`, se omite Smarty y Nibiru emite la clave asignada `data` como JSON. Útil para puntos finales AJAX:
```php
public function searchAction() {
    View::forwardToJsonHeader();
    $results = $this->index->search($_REQUEST['q'] ?? '');
    View::assign(['data' => $results]);
}
```
## Incluye navegación

`{include file="navigation.tpl"}` lee desde el archivo JSON configurado en `[SETTINGS] navigation`. Las aplicaciones de producción a menudo cargan **múltiples** matrices de navegación con nombres.
```php
public function navigationAction() {
    JsonNavigation::getInstance()->loadJsonNavigationArray('headnavigation');
    JsonNavigation::getInstance()->loadJsonNavigationArray('mainnavigation');
    JsonNavigation::getInstance()->loadJsonNavigationArray('footer');
}
```
Cada matriz nombrada se convierte en una variable de Smarty del mismo nombre, lista para renderizar en la plantilla correspondiente.

## Problemas comunes

- **Permisos de `templates_c/`** — si Smarty no puede escribir ahí, obtendrás un error fatal. Ejecuta `./nibiru -s` una vez para solucionarlo.
- **`{$variable}` sin valor** — en el modo predeterminado, Smarty no renderiza nada en lugar de lanzar un error. Activa `error_reporting = E_ALL` y `[ENGINE] debug = true` durante el desarrollo para detectar errores tipográficos.
- **Escapado de HTML** — Smarty no autoescapa. Usa `|escape` para cualquier cadena controlada por el usuario.
