| 1 |
<?php
// ============================================================
// SIDE - ARC 1.0
// Archivo: helpers.php
// Propósito: Funciones compartidas del sistema
// ============================================================
// --- Seguridad de output ---
function h($valor): string {
return htmlspecialchars((string)($valor ?? ''), ENT_QUOTES, 'UTF-8');
}
// --- Texto truncado ---
function texto_corto($texto, $limite = 220): string {
$texto = (string)($texto ?? '');
if (mb_strlen($texto, 'UTF-8') > $limite) {
return mb_substr($texto, 0, $limite, 'UTF-8') . '…';
}
return $texto;
}
// --- Verificar sesión admin ---
function es_admin(): bool {
return isset($_SESSION['admin_id']) && !empty($_SESSION['admin_id']);
}
// --- Requerir admin o redirigir ---
function requerir_admin(): void {
if (!es_admin()) {
header('Location: /apps/side-arc/index.php');
exit;
}
}
// --- Matriz ISAD(G) ---
function matriz_isadg(): array {
return [
'RAIZ' => [
'Fondo'
],
'Fondo' => [
'1era División de Fondo',
'Subfondo',
'Serie',
'Unidad Documental Compuesta',
'Unidad Documental Simple',
],
'1era División de Fondo' => [
'2da División de Fondo',
'Serie',
'Unidad Documental Compuesta',
'Unidad Documental Simple',
],
'2da División de Fondo' => [
'Serie',
'Unidad Documental Compuesta',
'Unidad Documental Simple',
],
'Subfondo' => [
'Serie',
'Unidad Documental Compuesta',
'Unidad Documental Simple',
],
'Serie' => [
'Subserie',
'Unidad Documental Compuesta',
'Unidad Documental Simple',
],
'Subserie' => [
'Unidad Documental Compuesta',
'Unidad Documental Simple',
],
'Unidad Documental Compuesta' => [
'Unidad Documental Simple',
],
'Unidad Documental Simple' => [],
];
}
// --- Todos los niveles como lista plana ---
function todos_los_niveles(): array {
$matriz = matriz_isadg();
$niveles = [];
foreach ($matriz as $padre => $hijos) {
if ($padre !== 'RAIZ') {
$niveles[$padre] = true;
}
foreach ($hijos as $hijo) {
$niveles[$hijo] = true;
}
}
return array_keys($niveles);
}
// --- Niveles permitidos bajo un padre ---
function niveles_permitidos_bajo(?string $nivel_padre): array {
$matriz = matriz_isadg();
if ($nivel_padre === null) {
return $matriz['RAIZ'];
}
return $matriz[$nivel_padre] ?? [];
}
// --- Validar si un nivel es permitido bajo un padre ---
function nivel_es_valido(string $nivel_hijo, ?string $nivel_padre): bool {
return in_array($nivel_hijo, niveles_permitidos_bajo($nivel_padre), true);
}
// --- Prefijo corto por nivel ---
function prefijo_nivel(string $nivel): string {
$mapa = [
'Fondo' => 'F',
'1era División de Fondo' => '1D',
'2da División de Fondo' => '2D',
'Subfondo' => 'SF',
'Serie' => 'S',
'Subserie' => 'Ss',
'Unidad Documental Compuesta' => 'UDC',
'Unidad Documental Simple' => 'US',
];
return $mapa[$nivel] ?? strtoupper(substr($nivel, 0, 3));
}
// --- Obtener registro por ID ---
function obtener_registro(mysqli $conexion, int $id): ?array {
$stmt = mysqli_prepare($conexion,
"SELECT * FROM descripcion_isadg WHERE id = ? LIMIT 1");
mysqli_stmt_bind_param($stmt, 'i', $id);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$fila = mysqli_fetch_assoc($res);
mysqli_stmt_close($stmt);
return $fila ?: null;
}
// --- Niveles permitidos consultando el padre en BD ---
function obtener_niveles_para_padre(mysqli $conexion, ?int $parent_id, ?array &$padre = null, string &$error = ''): array {
$padre = null;
$error = '';
if ($parent_id === null || $parent_id === 0) {
return matriz_isadg()['RAIZ'];
}
$padre = obtener_registro($conexion, $parent_id);
if (!$padre) {
$error = 'El registro padre especificado no existe.';
return [];
}
return niveles_permitidos_bajo($padre['nivel_descripcion']);
}
// --- Validar nivel contra BD ---
function nivel_valido_bajo_padre(mysqli $conexion, ?int $parent_id, string $nivel, string &$mensaje = ''): bool {
$padre = null;
$error = '';
$permitidos = obtener_niveles_para_padre($conexion, $parent_id, $padre, $error);
if ($error !== '') {
$mensaje = $error;
return false;
}
if (!in_array($nivel, $permitidos, true)) {
$contexto = $padre ? $padre['nivel_descripcion'] : 'Raíz';
$mensaje = "El nivel '{$nivel}' no está permitido bajo '{$contexto}'.";
return false;
}
return true;
}
// --- Contar hijos directos ---
function contar_hijos(mysqli $conexion, int $id): int {
$stmt = mysqli_prepare($conexion,
"SELECT COUNT(*) AS total FROM descripcion_isadg WHERE parent_id = ?");
mysqli_stmt_bind_param($stmt, 'i', $id);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$fila = mysqli_fetch_assoc($res);
mysqli_stmt_close($stmt);
return (int)($fila['total'] ?? 0);
}
// --- Obtener hijos directos ---
function obtener_hijos(mysqli $conexion, int $parent_id): array {
$stmt = mysqli_prepare($conexion,
"SELECT * FROM descripcion_isadg WHERE parent_id = ? ORDER BY codigo_referencia ASC, titulo ASC");
mysqli_stmt_bind_param($stmt, 'i', $parent_id);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$hijos = [];
while ($fila = mysqli_fetch_assoc($res)) {
$hijos[] = $fila;
}
mysqli_stmt_close($stmt);
return $hijos;
}
// --- Obtener IDs de ancestros (para árbol acordeón) ---
function ids_ancestros(mysqli $conexion, int $id): array {
$sql = "WITH RECURSIVE ancestros AS (
SELECT id, parent_id
FROM descripcion_isadg
WHERE id = ?
UNION ALL
SELECT d.id, d.parent_id
FROM descripcion_isadg d
INNER JOIN ancestros a ON d.id = a.parent_id
)
SELECT id FROM ancestros";
$stmt = mysqli_prepare($conexion, $sql);
mysqli_stmt_bind_param($stmt, 'i', $id);
mysqli_stmt_execute($stmt);
$res = mysqli_stmt_get_result($stmt);
$ids = [];
while ($fila = mysqli_fetch_assoc($res)) {
$ids[] = (int)$fila['id'];
}
mysqli_stmt_close($stmt);
return $ids;
}
// --- Valor POST saneado ---
function valor_post(string $clave): string {
return trim((string)($_POST[$clave] ?? ''));
}
// --- Normalizar entero o null ---
function normalizar_entero_nulo($valor): ?int {
if ($valor === null || $valor === '') {
return null;
}
return is_numeric($valor) ? (int)$valor : null;
}
// --- Campos ISAD(G) ---
function obtener_campos_isadg(): array {
return [
'nivel_descripcion',
'codigo_referencia',
'titulo',
'fechas',
'fecha_inicial_filtro',
'fecha_final_filtro',
'volumen_soporte',
'nombre_productor',
'historia_institucional',
'alcance_contenido',
'valoracion_eliminacion',
'organizacion',
'condiciones_acceso',
'condiciones_reproduccion',
'lengua_escritura',
'caracteristicas_fisicas',
'unidades_relacionadas',
'notas',
'fecha_ingreso_registro',
'fechas_descripciones',
'estado',
'nombre_descriptor',
'nota_archivero',
'fecha_creacion_revision',
'reglas_normas',
'pa_nombre',
'pa_geografico',
'pam_materia',
];
}
?>
|