Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/jpbarbatic/webapp/llms.txt

Use this file to discover all available pages before exploring further.

El panel de administración agrupa en tres archivos helper las operaciones transversales que se repiten en todos los módulos CRUD: cálculo de paginación y offset, generación segura de controles HTML, comprobación de permisos de sesión y acceso al sistema de roles y permisos de la base de datos. Estos archivos se cargan automáticamente desde includes/backend.php en cada controlador de módulo, por lo que sus funciones están disponibles en cualquier vista del panel sin necesidad de importaciones adicionales.

includes/utilidades.php

Este archivo concentra las funciones de uso más frecuente: paginación de resultados SQL, construcción de elementos <option> para selectores HTML, lectura segura de valores de formulario y verificación de visibilidad de secciones del menú.

paginacion()

Lee los parámetros p, orden y orden_dir de la superglobal $_GET y devuelve un array asociativo con los cinco valores necesarios para paginar cualquier consulta SQL. Código fuente:
function paginacion()
{
    $p = isset($_GET['p']) ? $_GET['p'] : 1;
    $items_pagina = 10;
    $offset = ($p - 1) * $items_pagina;
    $orden = isset($_GET['orden']) ? $_GET['orden'] : 'id';
    $orden_dir =  isset($_GET['orden_dir']) ? $_GET['orden_dir'] : 'asc';
    return compact('p', 'items_pagina', 'offset', 'orden', 'orden_dir');
}
Valores devueltos:
ClaveTipoDescripción
pintNúmero de página actual leído de $_GET['p']. Valor por defecto: 1.
items_paginaintNúmero fijo de registros por página. Siempre 10.
offsetintDesplazamiento SQL calculado como ($p - 1) * 10.
ordenstringColumna de ordenación leída de $_GET['orden']. Valor por defecto: 'id'.
orden_dirstringDirección de ordenación leída de $_GET['orden_dir']. Valor por defecto: 'asc'.
Ejemplo de uso en un controlador:
extract(paginacion());
// Variables disponibles tras extract():
// $p            → página actual (por defecto 1)
// $items_pagina → 10
// $offset       → ($p - 1) * 10
// $orden        → 'id' (por defecto)
// $orden_dir    → 'asc' (por defecto)

$sql = "SELECT * FROM productos ORDER BY $orden $orden_dir LIMIT ? OFFSET ?";
$res = db_query($db, $sql, [$items_pagina, $offset]);
extract(paginacion()) crea las variables en el ámbito local del controlador. Las vistas de paginación (paginacion.html.php) esperan que $p, $total e $items_pagina existan en su ámbito de inclusión.

html_opciones($opciones, $seleccion, $id, $valor)

Genera una cadena de elementos <option> a partir de un array de filas de base de datos. Marca automáticamente como selected la opción cuyo campo $id coincida con el valor actual $seleccion. Código fuente:
function html_opciones($opciones, $seleccion, $id, $valor)
{
    $html = '';
    foreach ($opciones as $opcion) {
        $selected = $seleccion == $opcion[$id] ? 'selected' : '';
        $html .= "<option value='" . $opcion[$id] . "' $selected>" . $opcion[$valor] . "</option>\n";
    }
    return $html;
}
Parámetros:
ParámetroTipoDescripción
$opcionesarrayArray de filas devueltas por db_query(). Cada fila es un array asociativo.
$seleccionmixedValor actualmente seleccionado (se compara con $opcion[$id] usando ==).
$idstringClave del array de fila que se usará como atributo value del <option>.
$valorstringClave del array de fila que se usará como texto visible del <option>.
Ejemplo de uso en un formulario de productos:
$categorias = db_query($db, 'SELECT * FROM categorias');

echo '<select name="id_categoria">';
echo html_opciones($categorias, $producto['id_categoria'], 'id', 'nombre');
echo '</select>';
Esto renderiza algo similar a:
<select name="id_categoria">
  <option value='1'>Electrónica</option>
  <option value='2' selected>Ropa</option>
  <option value='3'>Alimentación</option>
</select>

html_input_valor($formulario, $campo, $defecto = '')

Devuelve el valor escapado de un campo dentro de un array de formulario (típicamente $_POST o $_GET). Si el campo no existe, devuelve el valor por defecto. Aplica htmlspecialchars con las opciones ENT_QUOTES | ENT_SUBSTITUTE en codificación UTF-8 para prevenir inyecciones XSS en atributos HTML. Código fuente:
function html_input_valor($formulario, $campo, $defecto = '')
{
    return isset($formulario[$campo])
        ? htmlspecialchars($formulario[$campo], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true)
        : $defecto;
}
Parámetros:
ParámetroTipoDescripción
$formularioarrayArray de datos del formulario: $_POST, $_GET o un array personalizado.
$campostringNombre de la clave a leer dentro de $formulario.
$defectostringValor devuelto si $campo no existe en $formulario. Por defecto ''.
Ejemplo de uso en una plantilla de formulario:
<input
  type="text"
  name="nombre"
  value="<?= html_input_valor($_POST, 'nombre') ?>"
  class="form-control">

<input
  type="email"
  name="email"
  value="<?= html_input_valor($_POST, 'email', $usuario['email']) ?>"
  class="form-control">
En el segundo ejemplo, si $_POST['email'] no existe (primera carga del formulario), se muestra el valor que ya tenía el usuario en la base de datos.

es_visible($vista)

Comprueba si el array de permisos almacenado en $_SESSION['permisos'] contiene al menos un permiso cuyo nombre comience por $vista. (notación punto). Se usa en nav.html.php para mostrar u ocultar elementos del menú de navegación según los permisos del rol del usuario en sesión. Código fuente:
function es_visible($vista){
  return preg_grep("/^$vista\.*/", array_column($_SESSION['permisos'], 'nombre'));
}
Internamente extrae la columna nombre del array de permisos de la sesión y aplica preg_grep con el patrón /^$vista\.*/. Si existe alguna coincidencia, la función devuelve un array no vacío (truthy); si no existe ninguna, devuelve un array vacío (falsy). Ejemplo de uso en la barra de navegación:
<?php if (es_visible('usuarios')): ?>
    <li class="nav-item">
        <a class="nav-link" href="usuarios/">Usuarios</a>
    </li>
<?php endif; ?>
Un usuario que tenga los permisos usuarios.ver y usuarios.editar verá el enlace; uno que solo tenga productos.ver no lo verá.

includes/permisos.php

Este archivo contiene las cuatro funciones que gestionan el sistema de control de acceso basado en roles (RBAC): consulta de roles, consulta de permisos disponibles, obtención de los permisos asignados a un rol y actualización del conjunto de permisos de un rol.

obtener_roles($db)

Devuelve todos los roles definidos en la tabla roles.
function obtener_roles($db){
  $sql = 'select * from roles';
  $roles = db_query($db, $sql);
  return $roles;
}
Retorna: Array de filas de la tabla roles.

obtener_todos_permisos($db)

Devuelve todos los permisos disponibles en la tabla permisos, ordenados alfabéticamente por nombre. Se usa en el formulario de edición de roles para mostrar el listado completo de permisos que pueden asignarse.
function obtener_todos_permisos($db){
  $sql = 'select * from permisos order by nombre';
  $permisos = db_query($db, $sql);
  return $permisos;
}
Retorna: Array de filas de la tabla permisos, ordenadas por el campo nombre.

obtener_permisos_rol($db, $id_rol)

Obtiene los permisos actualmente asignados a un rol concreto mediante un JOIN entre roles_permisos y permisos. También es invocada por backend.php para refrescar $_SESSION['permisos'] en cada petición.
function obtener_permisos_rol($db, $id_rol){
  $sql = 'select p.id, p.nombre
  from roles_permisos rp
  join permisos p on rp.id_permiso = p.id
  where rp.id_rol = ?
  order by p.nombre';

  $res = db_query($db, $sql, [$id_rol]);
  return $res;
}
Parámetros:
ParámetroTipoDescripción
$dbPDOConexión activa a la base de datos.
$id_rolintIdentificador del rol cuyos permisos se quieren obtener.
Retorna: Array de filas con las columnas id y nombre de cada permiso asignado al rol, ordenadas por nombre.

actualizar_permisos_rol($db, $permisos, $id_rol)

Reemplaza el conjunto completo de permisos de un rol. Primero borra todas las filas existentes en roles_permisos para ese rol y luego inserta las nuevas filas, una por cada permiso del array recibido.
function actualizar_permisos_rol($db, $permisos, $id_rol){
  // 1. Eliminar todos los permisos actuales del rol
  $sql = 'delete from roles_permisos where id_rol = ?';
  $res = db_query($db, $sql, [$id_rol]);

  // 2. Insertar los nuevos permisos seleccionados
  foreach($permisos as $permiso){
    $sql = 'insert into roles_permisos (id_rol, id_permiso) values (?, ?)';
    $res = db_query($db, $sql, [$id_rol, $permiso]);
  }
}
Parámetros:
ParámetroTipoDescripción
$dbPDOConexión activa a la base de datos.
$permisosarrayArray de IDs de permiso a asignar al rol. Puede ser un array vacío para quitar todos los permisos.
$id_rolintIdentificador del rol que se va a actualizar.
La operación es destructiva: primero borra todos los permisos del rol y luego inserta los nuevos. Si $permisos es un array vacío, el rol quedará sin ningún permiso asignado. No existe una operación de rollback implícita; asegúrate de validar el array antes de llamar a esta función.

includes/usuarios.php

Este archivo declara tres funciones relacionadas con la gestión del perfil de usuario y el cambio de contraseña: obtener_perfil, guardar_perfil y actualizar_password. Sin embargo, en la versión actual todas tienen el cuerpo vacío — son stubs pendientes de implementación:
function obtener_perfil($db, $id_usuario){

}

function guardar_perfil($db, $perfil){

}

function actualizar_password($db, $id_usuario, $password){

}
La lógica de lectura y actualización de datos de usuario (nombre, apellidos, email, teléfono) está gestionada directamente en los controladores del módulo usuarios/ (editar.php, nuevo.php). Si en el futuro se extrae esa lógica a funciones reutilizables, este archivo es el lugar previsto para alojarlas.
Diferencia entre es_visible() y el guard de backend.php:
  • es_visible($vista) es una función de presentación: lee $_SESSION['permisos'] y decide si mostrar un enlace en el menú de navegación. No impide el acceso directo a una URL.
  • El guard en backend.php es una comprobación de seguridad en backend: verifica que el permiso requerido ($permiso) esté presente en la sesión antes de ejecutar cualquier lógica del controlador. Si no se cumple, detiene la ejecución con die('No tienes permiso').
Ambas capas son complementarias: la primera mejora la experiencia de usuario ocultando opciones no autorizadas; la segunda garantiza que aunque alguien acceda directamente a una URL no pueda ejecutar operaciones sin el permiso correspondiente.

Build docs developers (and LLMs) love