# 🚨 Análisis: Manejo de Excepciones MoodleDB

> **Problema:** Excepciones crudas de RuntimeException cuando Moodle no está disponible  
> **Impacto:** 34 archivos, usuario ve error técnico en lugar de mensaje amigable  
> **Severidad:** 🔴 CRÍTICO

---

## 📊 Resumen Ejecutivo

| Métrica | Valor |
|---------|-------|
| **Archivos afectados** | 34 |
| **Excepciones sin captura** | RuntimeException (MoodleDB) |
| **Puntos de fallo** | getCourse(), createCourse(), getUserProfile() |
| **Riesgo de usuario** | Ven error técnico crudo (credenciales, conexión) |
| **Vistas críticas** | Views/Courses/Other/Tabs/moodle.php (línea 54-55) |
| **Soluciones posibles** | 2 (Inline try-catch o Helper centralizado) |

---

## 🔴 El Problema en 30 Segundos

```php
// ❌ ACTUAL (línea 54-55 en moodle.php)
$moodle = new App\Modules\Sie\Libraries\MoodleDB();
$courseResult = $moodle->getCourse($course_code);  // Puede lanzar RuntimeException

// ✅ SOLUCIÓN
try {
    $moodle = new App\Modules\Sie\Libraries\MoodleDB();
    $courseResult = $moodle->getCourse($course_code);
    $moodleAvailable = true;
} catch (RuntimeException $e) {
    // Capturar y mostrar mensaje amigable
    $moodleError = "Base de datos de Moodle no disponible o mal configurada";
    error_log("MoodleDB: " . $e->getMessage());
}
```

---

## 🌳 Tipos de Excepciones RuntimeException

| Caso | Error | Mensaje Técnico | Mensaje Amigable |
|------|-------|-----------------|------------------|
| **Credenciales inválidas** | Access denied | `Excepción MySQLi: Access denied for user` | "Credenciales de Moodle inválidas" |
| **Host no disponible** | Connection refused | `Excepción MySQLi: Connection refused` | "Servidor de Moodle no disponible" |
| **BD no existe** | Unknown database | `Excepción MySQLi: Unknown database` | "BD de Moodle no configurada" |
| **No configurado** | Config error | `Error al inicializar MoodleDB:...` | "Moodle no está configurado" |
| **Timeout** | Lost connection | `Excepción MySQLi: Lost connection` | "Se perdió la conexión con Moodle" |

---

## 📁 Archivos por Criticidad

### 🔴 CRÍTICOS (Vistas con interfaz directa)
```
Views/Courses/Other/Tabs/moodle.php       (línea 54-55)  → getCourse()
Views/Courses/European/Tabs/moodle.php    (?)            → getCourse()
Views/Courses/American/Tabs/moodle.php    (?)            → getCourse()
Views/Teachers/View/Tabs/moodle.php       (?)            → Múltiples
Views/Teachers/Edit/Tabs/moodle.php       (?)            → Múltiples
Views/Students/View/Tabs/moodle.php       (?)            → Múltiples
```

### 🟡 ALTOS (Processors y API)
```
Views/Courses/Create/processor.php        (?)            → createCourse()
Views/Courses/Edit/processor.php          (?)            → Múltiples
Views/Courses/Delete/processor.php        (?)            → Múltiples
Controllers/Api.php                       (?)            → Múltiples
```

---

## ✅ Dos Opciones de Solución

### Opción A: Inline Try-Catch (Más Simple)

**Ventajas:**
- Rápido de implementar
- Específico para cada vista

**Desventajas:**
- Código repetido en 34 archivos
- Difícil de mantener

**Ejemplo:**
```php
<?php
$moodleAvailable = false;
$moodleError = null;
$courseResult = false;

try {
    $moodle = new App\Modules\Sie\Libraries\MoodleDB();
    if (!$moodle->isConfigured()) {
        throw new RuntimeException("Moodle no configurado");
    }
    $courseResult = $moodle->getCourse($course_code);
    $moodleAvailable = true;
} catch (RuntimeException $e) {
    $moodleError = "Base de datos de Moodle no disponible";
    error_log($e->getMessage());
}
?>

<?php if ($moodleAvailable): ?>
    <!-- Mostrar datos normales -->
<?php else: ?>
    <div class="alert alert-danger">
        <i class="fas fa-exclamation-circle me-2"></i>
        <strong>Moodle No Disponible</strong>
        <p><?php echo $moodleError; ?></p>
    </div>
<?php endif; ?>
```

---

### Opción B: Helper Centralizado (Recomendado)

**Ventajas:**
- Reutilizable en 34 archivos
- Fácil de mantener
- Parseo de errores centralizado

**Desventajas:**
- Requiere crear helper nuevo
- Requiere refactoring

**Estructura:**
```
Helpers/MoodleDB_helper.php
├─ get_moodle_course_safe($code)
├─ parse_moodle_exception($msg)
└─ render_moodle_status($result)
```

**Uso en vista:**
```php
<?php
helper('MoodleDB_helper');
$result = get_moodle_course_safe($course_code);

if ($result['available']) {
    echo render_moodle_status($result, $course_code);
} else {
    echo '<div class="alert alert-danger">' . $result['error'] . '</div>';
}
?>
```

---

## 📊 Comparación de Opciones

| Aspecto | Opción A (Inline) | Opción B (Helper) |
|--------|-------------------|-------------------|
| **Tiempo implementación** | 30 min - 1 hora | 2-3 horas |
| **Líneas de código por archivo** | 10-15 | 2-3 |
| **Reutilización** | No | Sí |
| **Mantenibilidad** | Baja | Alta |
| **Consistencia** | Baja | Alta |
| **Recomendación** | Parches rápidos | Solución definitiva |

---

## 🎯 Plan de Acción Recomendado

### Fase 1: Crear Helper Centralizado
```bash
# 1. Crear archivo
Helpers/MoodleDB_helper.php

# 2. Implementar funciones:
- get_moodle_course_safe()
- get_moodle_user_profile_safe()
- parse_moodle_exception()
- render_moodle_status()
- render_moodle_error()

# Tiempo: 1-2 horas
```

### Fase 2: Refactorizar Vistas Críticas (3 vistas)
```
Views/Courses/Other/Tabs/moodle.php
Views/Courses/European/Tabs/moodle.php
Views/Courses/American/Tabs/moodle.php

# Cambios: Reemplazar try-catch por helper
# Tiempo: 1-2 horas
```

### Fase 3: Refactorizar Vistas Restantes (31 archivos)
```
Processors, Controllers, APIs, etc.

# Cambios: Usar helper en lugar de try-catch inline
# Tiempo: 3-4 horas
```

### Fase 4: Testing
```
- Simular Moodle caído
- Simular credenciales inválidas
- Verificar mensajes amigables
- Revisar logs

# Tiempo: 1 hora
```

---

## 🛡️ Patrón de Error Handling

### Para Vistas
```php
try {
    $moodle = new MoodleDB();
    $data = $moodle->getCourse($code);
    $available = true;
} catch (RuntimeException $e) {
    $error = parse_moodle_exception($e->getMessage());
    $available = false;
}

// Mostrar datos o error en HTML
```

### Para Processors/API
```php
try {
    $moodle = new MoodleDB();
    $data = $moodle->createCourse($params);
    return $this->response->setJSON(['success' => true, 'data' => $data]);
} catch (RuntimeException $e) {
    return $this->response->setJSON([
        'success' => false,
        'message' => "Moodle no disponible",
        'error' => ENVIRONMENT === 'development' ? $e->getMessage() : null
    ])->setStatusCode(503);
}
```

---

## 📋 Checklist Rápido

### Verificación Pre-Implementación
- [ ] Entender dónde se llama a `MoodleDB`
- [ ] Identificar todos los métodos que lanzan excepciones
- [ ] Decidir: Opción A (Inline) o Opción B (Helper)
- [ ] Crear plan de refactoring

### Validación Post-Implementación
- [ ] Simular fallo de conexión a Moodle
- [ ] Simular credenciales incorrectas
- [ ] Verificar que se muestra mensaje amigable
- [ ] Revisar que se loguea el error técnico
- [ ] Probar en navegadores múltiples

---

## 💡 Notas Importantes

### Información Sensible
⚠️ **NUNCA mostrar en UI del usuario:**
- Contraseñas reales
- Nombres de usuarios internos
- Direcciones IP/puertos
- Rutas de archivos completas

### Logging
✅ **SIEMPRE loguear:**
- Excepción completa con stack trace
- Hora y contexto
- Usuario que causó el error

### Configuración Faltante
Si `isConfigured()` retorna false:
```
MOODLE-DB-HOST
MOODLE-DB-PORT
MOODLE-DB-USER
MOODLE-DB-PASSWORD
MOODLE-DB-NAME
```

---

## 📞 Próximos Pasos

### Si quieres implementar AHORA:
```bash
# Opción A (30 min):
# Editar 3 archivos con try-catch inline

# Opción B (3-4 horas):
# Crear helper + refactorizar 34 archivos
```

### Si quieres investigar primero:
- Lee el análisis completo: `/memory/analysis_moodledb_exception_handling.md`
- Revisa MoodleDB.php línea 100-170 (generación de excepciones)
- Revisa Views/Courses/Other/Tabs/moodle.php línea 54-60 (punto de fallo)

---

**Documento:** 2026-05-13  
**Análisis completo:** `/memory/analysis_moodledb_exception_handling.md`  
**Complejidad:** Media-Alta  
**Recomendación:** Opción B (Helper centralizado) para solución definitiva
