helpers.php Funciones auxiliares y matriz ISAD(G) 1 líneas
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',
    ];
}
?>