El framework PHP detrás de SitioYa

Documentación de Koshkil

Núcleo

Vistas, themes y widgets

Themes

Un theme es una carpeta de webroot/themes/ con las plantillas Smarty y los recursos de una apariencia. El sitio público usa el de Templates.Theme; el panel usa inspinia (lo fija AdminSuperController).

webroot/themes/<theme>/
├── css/  js/  img/             recursos (Koshkil::getThemePath('css/theme.css'))
└── templates/
    ├── front/                  plantillas del sitio ($templateFolder = "front")
    │   ├── main.tpl            layout
    │   ├── index/index.tpl     IndexController::index()
    │   └── cuentas/…
    ├── admin/                  plantillas del panel
    ├── widgets/
    │   └── front/header.tpl    widget THeader del grupo "front"
    └── error/                  error.tpl, error404.tpl, error4xx.tpl, error500.tpl

Para crear un theme nuevo, copiá uno existente (por ejemplo brillare) y cambiá Templates.Theme en la configuración del dominio.

Dónde se buscan las plantillas

La vista busca primero en templates/<templateFolder>/ y después en templates/. Así, index/index.tpl se resuelve en templates/front/index/index.tpl y error/error404.tpl en templates/error/. Dentro de un plugin, se usan las plantillas de plugins/<plugin>/webroot/templates/.

Las plantillas compiladas se guardan en tmp/cache/view/<theme>/.

El layout

Controller::$templateFile (normalmente main.tpl) es la página completa. Recibe en $template la plantilla de la acción y la incluye:

{* templates/front/main.tpl *}
<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="utf-8">
  <title>{if $webpageTitle}{$webpageTitle} · {/if}{Configure::read('Web.SiteName')}</title>
  <link rel="stylesheet" href="{Koshkil::getThemePath('css/theme.css')}">
  {foreach Configure::read('styles') as $style}<link rel="stylesheet" href="{$style}">{/foreach}
  <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
  <script>var MAIN_URL='{Koshkil::GetLink('/')}';</script>
</head>
<body>
  {html_widget type="front.header"}
  <main{if $data_controller} data-controller="{$data_controller}"{/if}>
    {html_include file="{$template}"}
  </main>
  {html_widget type="front.footer"}
  {html_widget type="front.scripts"}
</body>
</html>

En las plantillas están disponibles todas las variables asignadas con $this->set(), además de $usuario (si hay sesión), $Response y $_SERVER. Las clases estáticas se pueden llamar directamente: {Koshkil::getLink('/')}, {Configure::read('Web.SiteName')}.

Scripts y estilos por página

Desde el controlador se agregan archivos que el layout y el widget de scripts imprimen:

WebElements::addScript(Koshkil::getThemePath('js/productos.js'));
WebElements::addScript('https://www.google.com/recaptcha/api.js');
WebElements::addScript('/js/primero.js', true);    // al principio de la lista
WebElements::addStyle('/css/plugins/datatables.css');

Se acumulan en Configure::read('scripts') y Configure::read('styles') sin duplicados. Con Debug.Javascript en false, si existe archivo.min.js se usa esa versión.

Widgets

Un widget es un componente de interfaz con su propia lógica y plantilla: cabecera, pie, menú, buscador…

{html_widget type="front.header"}
{html_widget type="admin.uploads" name="galeria"}
{html_widget type="plugins.noticias.front.noticias"}   {* widget de un plugin *}
type Clase Archivo Plantilla
front.header THeader src/Widgets/front/THeader.php templates/widgets/front/header.tpl
admin.uploads TUploads src/Widgets/admin/TUploads.php templates/widgets/admin/uploads.tpl
plugins.noticias.front.noticias TNoticias plugins/noticias/src/Widgets/Front/TNoticias.php plugins/noticias/webroot/templates/widgets/front/noticias.tpl
<?php
// src/Widgets/front/TDestacados.php
Koshkil::Uses('sys.web.TWidget');
Koshkil::UsesModel('productos');

class TDestacados extends TWidget {
    public function run() {
        $cantidad = intval($this->parameters['cantidad'] ?? 4);
        $this->set([
            'destacados' => TMProductos::where('prd_destacado', '1')->take($cantidad)->get(),
        ]);
    }
}
{html_widget type="front.destacados" cantidad=6}

El widget ejecuta create(), init() y run(); init() configura las carpetas de plantillas, así que si lo sobrescribís llamá a parent::init(). Los parámetros de la etiqueta llegan en $this->parameters y la plantilla recibe también todas las variables del controlador.

Plugins de Smarty incluidos

Están en src/Smarty/plugins/ y se registran solos.

Etiqueta Tipo Uso
{html_include file="…"} función Incluye una plantilla relativa a la carpeta del theme; si no existe, muestra error/error404.tpl. Acepta plugin="nombre".
{html_widget type="…"} función Ejecuta un widget.
{t key="…" domain="…"} función Traducción (ver Internacionalización).
{trans}clave{/trans} bloque Traducción de bloque.
{rule_or_role roles="…" rules="…"}…{/rule_or_role} bloque Muestra el contenido solo si el usuario tiene el rol o la regla.
{field_maxlength model="…" field="…"} función Imprime maxlength="N" según el largo de la columna.
{call_method name="…"} función Llama a un método público del controlador.
{include_plugins folder="…"} función Incluye las plantillas de esa carpeta de todos los plugins activos.
{include_plugins_scripts file="…"} función Imprime los <script> de ese archivo en todos los plugins activos.
|t modificador Traducción: {'save'|t} (dominio common).
|formatdate:"DD/MM/YYYY" modificador Formato de fecha con nombres en español (DDDD, MMMM, HH, mm…).
|elapsed modificador Tiempo transcurrido desde una fecha.
|excerpt:120 modificador Resumen de un texto.
|slug modificador Texto apto para URL.
|decamelize, |php_strtolower, |php_ucwords, |replace_str modificadores Utilidades de texto.
|php_json_encode, |php_base64_encode modificadores Codificación.
|gravatar modificador URL del avatar de Gravatar de un email.

Para agregar los tuyos, creá src/Smarty/plugins/function.mifuncion.php (o modifier., block.) con la función smarty_function_mifuncion($params, $template).

Escapá lo que viene del usuario

Smarty no escapa por defecto. Usá {$variable|escape} para todo texto ingresado por usuarios.