El framework PHP detrás de SitioYa

Documentación de Koshkil

Núcleo

Ruteo y reescritura de URLs

De la URL al controlador

Route::parseURI() descompone la URL sin necesidad de declarar rutas:

  1. Pasa todo a minúsculas y reemplaza - por _ (/reset-passwordreset_password).
  2. Si el primer segmento es admin y hay más segmentos, lo quita y marca la ruta como del panel (se busca en Controllers/Admin/).
  3. Si el siguiente segmento es el nombre de un plugin activo, lo quita y busca los controladores en plugins/<plugin>/src/Controllers/.
  4. Mientras los segmentos coincidan con subcarpetas de Controllers/, los consume como carpeta.
  5. Lo que queda es controlador/acción/argumentos….
URL Controlador Acción Argumentos
/ IndexController index
/cuentas CuentasController index
/cuentas/reset-password CuentasController resetPassword
/productos/ver/15/rojo ProductosController ver 15, rojo
/ajax/cuentas/login Ajax/CuentasController login
/admin/sistema/usuarios/editar/7 Admin/Sistema/UsuariosController editar 7
/noticias/listado (plugin noticias) plugins/noticias/…/ListadoController index

Los argumentos llegan como parámetros de la acción, en orden:

public function ver($id = null, $color = null) {
    $producto = TMProductos::find(intval($id));
    if (!$producto) {
        $this->Response->setCode(404);
        return;
    }
    $this->set(['producto' => $producto]);
}

Nombres de acción

La acción se pasa a camelCase (reset_passwordresetPassword). La plantilla, en cambio, usa el nombre original en minúsculas: cuentas/reset_password.tpl.

Parámetros especiales

  • ?action=nombre en la consulta (o en el POST) reemplaza la acción de la URL.
  • ?subaction=nombre queda disponible en Route::get()['subaction'].

Consultar la ruta actual

$route = Route::get();
// ['uri'=>'productos/ver/15', 'qs'=>'', 'plugin'=>'', 'controller'=>'Productos',
//  'action'=>'ver', 'raw_action'=>'ver', 'arguments'=>['15']]

Route::getDomain();     // 'https://misitio.com'
Route::setAction('otra');

Archivos estáticos de plugins

Si la URL empieza con el nombre de un plugin y termina en .js, .css, .map o una imagen, Koshkil entrega el archivo desde plugins/<plugin>/webroot/ directamente. Un .js que no existe como archivo se trata como la acción javascript del controlador, útil para generar JavaScript desde PHP.

Reglas de reescritura

Para URLs que no siguen la convención, se definen reglas en config/rewrite.php (o la del dominio) bajo System.Web.Rewrite. Se evalúan antes del ruteo, en orden, contra la URL sin la barra inicial.

<?php
$CONFIG = [
    'System' => [
        'Web' => [
            'Rewrite' => [
                // /negocios/panaderia-lopez  ->  /negocios?nombre=panaderia-lopez
                ['rule' => '^negocios/([a-z\-0-9]*)$', 'target' => '/negocios?nombre=$1', 'flags' => 'L,NC'],
                // alias de una sección del panel
                ['rule' => '^admin/usuarios/(editar|listado)$', 'target' => '/admin/sistema/usuarios/$1?subusuarios=1', 'flags' => 'L,NC'],
            ],
        ],
    ],
];
Parte Significado
rule Expresión regular (delimitador ~).
target Nueva URL. $1, $2… se reemplazan por los grupos capturados. La consulta del destino se agrega a $_GET.
flags L: última regla, deja de evaluar. NC: no distingue mayúsculas. RW: sigue evaluando las siguientes reglas sobre la URL ya reescrita.

Las reglas también se pueden agregar desde código, antes del ruteo:

RewriteManager::addRule('^ofertas$', '/productos/listado?oferta=1', 'L,NC');
RewriteManager::addRule('^promo$', '/productos/promo', 'L', true); // true: al principio

Los plugins declaran sus reglas en plugins/<plugin>/config/rewrite.php (arreglo $RULES), y se agregan después de las globales. Con Debug.Rewrite en 5 o más, cada evaluación se registra en tmp/logs/rewrite.log.

Generar enlaces

Nunca escribas rutas absolutas a mano: el proyecto puede estar en una subcarpeta.

Método Devuelve
Koshkil::getLink('/productos/ver/15') URL de una página (antepone Web.Path).
Koshkil::getPath('/css/app.css') Ruta web de un archivo. Con true como segundo argumento, la ruta física en disco.
Koshkil::getThemePath('css/theme.css') Archivo dentro del theme activo.
Koshkil::redirect('/cuentas') Redirige y termina la ejecución.
<a href="{Koshkil::getLink('/productos/ver/'|cat:$producto->prd_codigo)}">Ver</a>
<link rel="stylesheet" href="{Koshkil::getThemePath('css/theme.css')}">