El archivoDocumentation 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.
includes/db_pdo.php proporciona dos interfaces complementarias sobre la extensión PDO de PHP para trabajar con la base de datos del panel. La primera es un conjunto de funciones procedurales (db_open, db_query, db_select, db_insert, db_update, db_delete_by_id, entre otras) que pueden usarse directamente en cualquier parte del código. La segunda es la clase Singleton DB, que envuelve esas mismas funciones bajo una interfaz orientada a objetos y garantiza que se reutilice una única conexión PDO durante todo el ciclo de vida de la petición HTTP.
Configuración de conexión
db_open() lee los parámetros de conexión desde las constantes definidas en config.php. El archivo config-ejemplo.php incluido en el repositorio muestra la estructura esperada:
| Constante | Descripción | Valor de ejemplo |
|---|---|---|
DB_TYPE | Motor de base de datos (mysql o sqlite) | 'mysql' |
DB_HOST | Host del servidor de base de datos | '127.0.0.1' |
DB_PORT | Puerto de conexión | 3308 |
DB_USER | Usuario de la base de datos | 'root' |
DB_PASS | Contraseña del usuario | 'example' |
DB_NAME | Nombre de la base de datos | 'empresa' |
DB_HOST, DB_PORT, DB_USER, DB_PASS y DB_NAME; en su lugar se usa la clave sqlite_path pasada directamente al array $conf.
Funciones procedurales
db_open
$conf es null, los parámetros se leen de las constantes de config.php. Si se proporciona un array, sus valores sobreescriben las constantes mediante extract().
La conexión se configura con los atributos:
PDO::ATTR_ERRMODE→PDO::ERRMODE_EXCEPTION(lanza excepciones en errores)PDO::ATTR_DEFAULT_FETCH_MODE→PDO::FETCH_ASSOC(resultados como arrays asociativos)PDO::ATTR_EMULATE_PREPARES→false(sentencias preparadas nativas)
$conf:
| Clave | Descripción |
|---|---|
db_type | 'mysql' o 'sqlite' |
db_host | Host del servidor |
db_port | Puerto |
db_user | Usuario |
db_pass | Contraseña |
db_name | Nombre de la base de datos |
sqlite_path | Ruta al archivo SQLite (solo cuando db_type = 'sqlite') |
PDO configurada, o null si la conexión falla.
db_query
| Tipo PHP | Constante PDO |
|---|---|
null | PDO::PARAM_NULL |
bool | PDO::PARAM_BOOL |
int | PDO::PARAM_INT |
| Cualquier otro | PDO::PARAM_STR |
PDO usa índice 1-based para marcadores de posición posicionales (
?). db_query gestiona esto internamente: si la clave del array $params es entera, le suma 1 automáticamente antes de llamar a bindValue().Conexión PDO activa obtenida con
db_open().Consulta SQL con marcadores
? para parámetros posicionales o :nombre para parámetros nombrados.Array de valores a vincular. Si es
null, se ejecuta la consulta sin parámetros.array con todos los resultados (fetchAll(FETCH_ASSOC)) o false en caso de error.
db_select
SELECT COUNT(*) FROM (<sql_base>) as t_count— para obtener el total.<sql_base> ORDER BY ... LIMIT ? OFFSET ?— para obtener los datos paginados.
Conexión PDO activa.
Consulta SQL base. No debe incluir
ORDER BY, LIMIT ni OFFSET ya que la función los añade.Parámetros de la consulta base (para los
WHERE o JOIN que ya tenga).Número de filas por página.
0 desactiva la paginación.Desplazamiento en número de filas.
Nombre de columna por la que ordenar.
null omite el ORDER BY.Dirección de orden:
'ASC' o 'DESC'. Por defecto 'ASC'.Número total de registros que cumple los criterios (sin paginación).
Array de filas correspondientes a la página solicitada.
db_get_by_id
is_valid_identifier() antes de construir la consulta.
Valor de retorno: array asociativo con el registro encontrado, o false si no existe o los identificadores son inválidos.
db_insert
id del array $dto antes de construir la sentencia INSERT, evitando conflictos con columnas AUTO_INCREMENT. Valida el nombre de tabla y todos los nombres de campo con is_valid_identifier().
Valor de retorno: el ID del nuevo registro (lastInsertId()) como string o int, o false si la inserción falla.
db_update
$dto debe incluir el campo identificador (por defecto id) para construir la cláusula WHERE. La función extrae ese valor del array, lo aparta de los campos a actualizar y lo añade al final de los parámetros vinculados.
Valor de retorno: true si la actualización se ejecutó correctamente, false en caso contrario.
db_delete_by_id
$id_name coincida con $id. La consulta se construye dinámicamente solo si los identificadores superan la validación de is_valid_identifier().
Valor de retorno: true si el registro fue eliminado, false en caso de error o identificador inválido.
Transacciones: db_begin, db_commit, db_rollback
beginTransaction, commit, rollback). db_commit y db_rollback comprueban $conn->inTransaction() antes de actuar para evitar errores si se llaman fuera de una transacción activa.
db_close
null a la variable pasada por referencia. PDO libera la conexión con la base de datos cuando todas las referencias al objeto se destruyen.
Parámetros:
Referencia a la variable que contiene la conexión PDO activa. Tras la llamada, la variable queda en
null.Clase Singleton DB
La clase DB es un wrapper orientado a objetos sobre las funciones procedurales de db_pdo.php. Implementa el patrón Singleton: la primera llamada a DB::open() crea la conexión PDO y guarda la instancia en la propiedad estática $instancia; todas las llamadas posteriores durante la misma petición devuelven esa misma instancia sin abrir una nueva conexión.
Método estático DB::open()
DB. Si todavía no existe, llama a db_open($conf) internamente para crear la conexión PDO. Si la conexión falla, retorna false.
El método
DB::filter() acepta los parámetros ($table, $filtro, $orden_campo, $orden_dir, $pagina, $items_por_pagina) pero internamente los pasa a db_filter en un orden distinto. Para filtrados complejos con control total sobre $campos y $filtro usa directamente la función procedural db_filter().Métodos de instancia
| Método | Delegación interna | Descripción |
|---|---|---|
begin() | db_begin($this->conn) | Inicia una transacción |
commit() | db_commit($this->conn) | Confirma la transacción activa |
query($sql, $params) | db_query($this->conn, ...) | Ejecuta una consulta preparada |
get_by_id($table, $id) | db_get_by_id($this->conn, ...) | Obtiene un registro por ID |
filter($table, $filtro, $orden_campo, $orden_dir, $pagina, $items_por_pagina) | db_filter($this->conn, ...) | Filtra, ordena y pagina sobre una tabla |
insert($table, $dto) | db_insert($this->conn, ...) | Inserta un registro |
update($table, $dto) | db_update($this->conn, ...) | Actualiza un registro |
delete_by_id($table, $id) | db_delete_by_id($this->conn, ...) | Elimina un registro por ID |
La clase
DB no expone db_rollback como método propio. Para revertir una transacción usa la función procedural db_rollback() pasándole la conexión PDO obtenida con db_open(), o bien abre la conexión de forma procedural con db_open() en lugar de usar el Singleton cuando necesites control completo de transacciones con rollback.Ejemplo completo con la clase DB
Seguridad: is_valid_identifier
is_valid_identifier() es una guarda de seguridad interna que se ejecuta antes de incluir cualquier nombre de tabla o columna en una consulta SQL construida dinámicamente. Valida que el identificador contenga únicamente caracteres alfanuméricos y guiones bajos (^[a-zA-Z0-9_]+$).
Las funciones que la utilizan son: db_get_by_id, db_insert, db_update y db_delete_by_id.
¿Por qué es necesaria? Los marcadores de posición PDO (?) protegen los valores de los parámetros contra inyección SQL, pero no pueden usarse para nombres de tablas o columnas. Un atacante que controlara esos argumentos podría inyectar SQL arbitrario como:
is_valid_identifier() rechaza esa cadena porque contiene caracteres fuera del patrón permitido (\``, espacios, ;), devolviendo falsey haciendo que la función llamante retornefalse` sin ejecutar ninguna consulta.
db_filter
WHERE a partir de un array de criterios estructurado, calcula el número total de páginas y devuelve los datos de la página solicitada.
Parámetros
Conexión PDO activa.
Nombre de la tabla sobre la que se realiza la consulta.
Array asociativo
['columna' => 'alias'] que define las columnas a seleccionar. Si el alias es null, se usa el nombre de columna directamente. Un array vacío o null equivale a SELECT *.Array de criterios de filtro (ver estructura más abajo).
Operador lógico entre criterios:
'or' (por defecto) o 'and'.Nombre de columna por la que ordenar. Por defecto
'id'.Dirección de orden:
'asc' o 'desc'. Cualquier otro valor hace que la función retorne false.Número de página (base 1). El valor
0 recupera todos los registros sin aplicar LIMIT/OFFSET.Registros por página. Por defecto
20.Estructura del array $filtro
Cada elemento del array $filtro es un array asociativo con las siguientes claves:
| Clave | Tipo | Descripción |
|---|---|---|
campo | string | Nombre de la columna a filtrar |
tipo | string | Tipo de filtro: texto, entero, id o intervalo |
valor | mixed | Valor del filtro (para texto, entero e id) |
min | mixed | Límite inferior exclusivo (solo para intervalo) |
max | mixed | Límite superior exclusivo (solo para intervalo) |
mine | mixed | Límite inferior inclusivo (solo para intervalo) |
maxe | mixed | Límite superior inclusivo (solo para intervalo) |
tipo | Operador SQL generado | Condición de activación |
|---|---|---|
texto | LOWER(campo) LIKE LOWER(?) con %valor% | Solo si el valor no es una cadena vacía |
entero | campo = ? | Solo si el valor es numérico |
id | campo = ? | Solo si el valor es numérico |
intervalo | campo > ?, campo < ?, campo >= ?, campo <= ? | Según las claves min, max, mine, maxe presentes |
Valor de retorno
Total de registros que cumplen los criterios de filtro.
Filas correspondientes a la página solicitada.
false si $db es falsy, si $orden_dir no es 'asc' ni 'desc', o si el número de página está fuera de rango.
Ejemplo: filtrado en el módulo de productos
db_select vs db_filter: usa db_select cuando ya tienes una consulta SQL base personalizada (con JOIN, subconsultas, etc.) y solo necesitas paginación automática. Usa db_filter cuando trabajas directamente sobre una tabla y quieres delegar la construcción del WHERE al motor de filtrado estructurado, pasando un array de criterios en lugar de SQL manual. Ambas devuelven la misma estructura ['total' => int, 'datos' => array].