11. Solución de problemas comunes
11.1. Errores frecuentes y soluciones
Al trabajar con el framework, es posible encontrarse con varios tipos de errores comunes. A continuación se presentan los más frecuentes junto con sus soluciones:
11.1.1. Error "Validations is not set"
Problema:
Exception: Validations is not set
Causa: Este error ocurre cuando intentas usar un DomainController pero no has definido la propiedad $validations en el constructor.
Solución: Define la propiedad $validations en el constructor de tu controlador:
public function __construct(ProductsService $service)
{
parent::__construct($service);
$this->validations = [
'headers' => [], // Puede estar vacío, pero debe existir
'body' => [] // Puede estar vacío, pero debe existir
];
}
11.1.2. Error "Non same origin"
Problema:
NotSameOriginException: La solicitud no proviene del mismo origen
Causa: Por seguridad, el framework verifica que las solicitudes provengan del mismo origen (mismo dominio). Este error ocurre cuando intentas hacer una solicitud desde un dominio diferente.
Solución:
- Configura CORS correctamente en
App\Config\allowedOrigins.php:
// Para permitir todos los orígenes (no recomendado para producción)
return "*";
// O para permitir orígenes específicos
return [
'https://tu-aplicacion.com',
'http://localhost:5173'
];
- Asegúrate de que las solicitudes incluyan las cabeceras
OriginoReferercorrectas.
11.1.3. Error "No route matched"
Problema:
Exception: No route matched
Causa: El router no pudo encontrar una coincidencia para la ruta solicitada, o no pudo encontrar el archivo de rutas correspondiente.
Solución:
- Verifica que el archivo de rutas existe en la ubicación correcta y sigue la convención de nombres.
- Asegúrate de que las rutas están registradas correctamente usando
Route::get(),Route::post(), etc. - Confirma que la ruta coincide exactamente con la que estás solicitando (incluidas mayúsculas/minúsculas).
11.1.4. Error "Target binding does not exist"
Problema:
Exception: Target binding [Services\Interfaces\MyServiceInterface] does not exist
Causa: Estás intentando obtener un servicio del contenedor que no ha sido registrado.
Solución:
- Registra el servicio en
src/Services/services.php:
return [
Services\Interfaces\MyServiceInterface::class => Services\MyService::class
];
- O registra el servicio directamente en el contenedor antes de usarlo:
$container = QuApp::getContainer();
$container->set(Services\Interfaces\MyServiceInterface::class, function() {
return new Services\MyService();
});
11.1.5. Error "No se pudo crear el directorio"
Problema:
Error creando directorio /ruta/al/directorio
Causa: El framework intenta crear un directorio para logs u otro propósito, pero no tiene permisos suficientes.
Solución:
- Asegúrate de que los directorios necesarios existan y tengan permisos adecuados:
mkdir -p /ruta/logs
chmod 755 -R /ruta/logs
chown www-data:www-data -R /ruta/logs # Ajusta según tu servidor web
- Verifica las constantes de ruta en
bootstrap.phppara asegurarte de que apuntan a los lugares correctos.
11.1.6. Errores de validación no capturados
Problema: Las validaciones no funcionan como se esperaba, pero no se lanzan excepciones.
Causa: Es posible que estés usando una sintaxis incorrecta en las reglas de validación.
Solución:
- Verifica la sintaxis de tus reglas de validación.
- Asegúrate de que las reglas personalizadas están implementadas correctamente.
- Activa el modo de desarrollo para ver errores más detallados:
// En bootstrap.php o index.php
define('ENVIRONMENT', 'DEV');
11.2. Depuración de aplicaciones
El framework ofrece varias herramientas y técnicas para depurar aplicaciones eficazmente.
11.2.1. Función de depuración ddd()
El framework incluye la función ddd() (dump, die, debug) que muestra información detallada sobre variables y detiene la ejecución:
// En cualquier parte del código
ddd($variable1, $variable2, 'mensaje de depuración');
Esta función es especialmente útil para inspeccionar variables complejas y seguir el flujo de ejecución.
11.2.2. Habilitando el modo de desarrollo
El modo de desarrollo muestra mensajes de error detallados y activa otras herramientas de depuración:
// En bootstrap.php
QuApp::setEnvironment('DEV');
En este modo, los errores mostrarán información detallada incluyendo la pila de llamadas, lo que facilita la identificación del origen del problema.
11.2.3. Depurando middlewares
Para depurar middlewares, puedes usar la función ddd() o agregar logs específicos:
public function handle(Request $request, callable $next)
{
// Inspeccionar el request
Log::info([
'uri' => $request->getUri(),
'method' => $request->getMethod(),
'headers' => $request->headers->all(),
'body' => $request->request->all()
], 'middleware_debug');
$response = $next($request);
// Inspeccionar la respuesta
Log::info([
'status' => $response->getStatusCode(),
'headers' => $response->headers->all(),
'content' => json_decode($response->getContent(), true)
], 'middleware_debug');
return $response;
}
11.2.4. Depurando el sistema de rutas
Si tienes problemas con las rutas, puedes mostrar todas las rutas registradas:
// En un controlador o middleware
use App\Core\Router\Route;
ddd(Route::getAllRoutes());
Esto te mostrará todas las rutas registradas, sus métodos HTTP, controladores y middlewares.
11.2.5. Depurando el contenedor DI
Para verificar las dependencias registradas en el contenedor:
$container = QuApp::getContainer();
$reflection = new ReflectionClass($container);
$property = $reflection->getProperty('bindings');
$property->setAccessible(true);
ddd($property->getValue($container));
11.2.6. Depuración de SQL
Para depurar consultas SQL, puedes habilitar el logging de consultas:
// En un repositorio o servicio
use App\Helpers\Log;
// Antes de ejecutar la consulta
Log::info("Ejecutando consulta: $sql", 'sql');
// Después de ejecutar la consulta
Log::info("Resultado: " . json_encode($result), 'sql');
11.3. Logging y seguimiento de errores
El framework proporciona un sistema de logging robusto que permite el seguimiento detallado de errores y eventos.
11.3.1. Sistema de logging
El sistema de logging está implementado en App\Helpers\Log y ofrece varios métodos para registrar información:
use App\Helpers\Log;
// Registrar información general
Log::info("Operación completada con éxito", 'general');
// Registrar un error
Log::error("Error al conectar con el servicio externo: " . $e->getMessage());
// Registrar datos estructurados
Log::info([
'user_id' => $userId,
'action' => 'login',
'ip' => $request->getClientIp()
], 'user_activity');
Los logs se almacenan en el directorio definido por la constante LOG_DIR en archivos separados según el tipo y la fecha.
11.3.2. Estructura del archivo de logs
Los archivos de log tienen la siguiente estructura:
[YYYY-MM-DD HH:MM:SS] Información del mensaje
Para logs estructurados, la información se codifica en JSON para facilitar el análisis.
11.3.3. Registro de transacciones
El framework registra automáticamente información detallada sobre cada transacción HTTP en archivos JSON:
[
{
"method": "POST",
"url": "/api/products",
"timestamp": "2023-08-15T14:32:45+0000",
"host": "api.example.com",
"origin": "https://app.example.com",
"referer": "https://app.example.com/products",
"user_agent": "Mozilla/5.0...",
"ip": "192.168.1.1",
"nombre_usuario": "John Doe",
"cod_usuario_ext": "jdoe",
"num_usuario": "123",
"actions": [
{
"maesarti": {
"stored": {
"id": "456",
"name": "Nuevo Producto"
}
}
}
],
"payload": {
"body": {
"name": "Nuevo Producto",
"price": 99.99
},
"query": {
"lang": "es"
}
},
"request_id": "f8c3a4d2-e0e1-4d5b-9a6c-7b8d9e2f1c0a"
}
]
Estos registros son muy útiles para:
- Auditoría de acciones de usuario
- Seguimiento de problemas
- Reconstrucción de eventos para debugging
- Análisis de patrones de uso
11.3.4. Configuración de logging avanzado
Para casos especiales, puedes configurar opciones de logging avanzadas:
// En bootstrap.php o algún archivo de configuración
define('LOG_LEVEL', 'DEBUG'); // DEBUG, INFO, WARN, ERROR
define('LOG_ROTATION_SIZE', 10 * 1024 * 1024); // 10MB
define('LOG_MAX_FILES', 10);
11.3.5. Captura centralizada de excepciones
El framework captura todas las excepciones no manejadas en index.php y las procesa de manera consistente:
try {
$response = $kernel->handle($request);
QuApp::setSuccessResponse($response);
} catch (\Throwable $th) {
if (ENVIRONMENT === "DEV") {
QuApp::setTraceErrors(true);
}
QuApp::setErrorResponse($th);
}
QuApp::sendResponseAndEnd();
Esto garantiza que todas las excepciones:
- Se registran en los logs
- Se transforman en respuestas HTTP apropiadas con códigos de estado correctos
- Incluyen información de depuración en el entorno de desarrollo
11.4. Preguntas frecuentes
11.4.1. ¿Cómo puedo cambiar el formato de respuesta de error?
R: El formato de respuesta de error se controla en App\Helpers\ErrorResponse. Puedes crear tu propia clase que extienda o reemplace esta funcionalidad y configurarla en QuApp::setErrorResponse().
11.4.2. ¿Cómo puedo agregar middleware solo para ciertas rutas?
R: Los middlewares específicos de ruta se definen en el archivo de rutas:
$middlewares = [
'before' => [AuthMiddleware::class, RateLimitMiddleware::class],
'after' => [LogResponseMiddleware::class]
];
Route::group(ProductsController::class, function () use ($middlewares) {
Route::get('products/', 'index', $middlewares);
// Otras rutas...
});
11.4.3. ¿Cómo puedo validar solo ciertos campos cuando actualizo un recurso?
R: El método action('update') en la validación relaja la regla required para actualizaciones parciales. Solo se validarán los campos que estén presentes en la solicitud.
11.4.4. ¿Por qué recibo "Non same origin" aunque mis URL son correctas?
R: Este error puede ocurrir si:
- El servidor está detrás de un proxy y las cabeceras no se están transmitiendo correctamente
- Estás usando HTTPS en producción pero HTTP en desarrollo
- La URL tiene subdominios diferentes (api.ejemplo.com vs ejemplo.com)
Asegúrate de configurar correctamente allowedOrigins.php y verificar las cabeceras Origin y Referer.
11.4.5. ¿Cómo puedo implementar paginación en mis respuestas?
R: La paginación está integrada en el método collection() de los repositorios. Usa los parámetros page y itemsPerPage en la solicitud:
GET /products?page=2&itemsPerPage=25
La respuesta incluirá metadatos de paginación:
{
"collection": [...],
"totalRows": 100,
"totalFilteredRows": 50,
"pages": 5,
"page": 2,
"itemsPerPage": 10
}
11.4.6. ¿Cómo puedo implementar filtros personalizados?
R: Los filtros se pasan como parámetro filters en formato JSON:
GET /products?filters={"name":{"like":"Producto"},"price":{">":100}}
Para filtros más complejos:
GET /products?filters={"$or":[{"status":{"=":"active"}},{"featured":{"=":true}}]}
11.4.7. ¿Puedo usar transacciones en operaciones que afectan a múltiples tablas?
R: Sí, puedes usar el método transaction() en los repositorios:
return $this->repository->transaction(function() use ($data) {
$order = $this->orderRepository->store($data);
foreach ($data['items'] as $item) {
$item['order_id'] = $order['id'];
$this->orderItemRepository->store($item);
}
return $order;
});
11.4.8. ¿Cómo puedo usar el framework con bases de datos diferentes a MySQL?
R: El framework está diseñado principalmente para trabajar con MySQL a través de Quartup. Para usar otras bases de datos, necesitarías:
- Crear adaptadores específicos para cada base de datos
- Implementar clases de modelo que usen estos adaptadores
- Registrar los adaptadores en el contenedor
11.4.9. ¿Cómo manejar archivos subidos?
R: Los archivos subidos están disponibles en $request->files:
public function uploadImage(Request $request)
{
$file = $request->files->get('image');
if (!$file) {
throw new BadRequestException('No se proporcionó el archivo');
}
// Validar el archivo
if (!in_array($file->getClientMimeType(), ['image/jpeg', 'image/png'])) {
throw new BadRequestException('Tipo de archivo no permitido');
}
// Mover el archivo a su ubicación final
$filename = uniqid() . '.' . $file->getClientOriginalExtension();
$file->move('/ruta/almacenamiento', $filename);
return response()->json(['filename' => $filename], 201);
}
11.4.11. ¿Cómo implementar búsquedas de texto completo?
R: Para búsquedas simples, puedes usar el operador like:
GET /products?filters={"name":{"like":"termo"}}
Para búsquedas más avanzadas, puedes usar el parámetro simpleSearch:
GET /products?simpleSearch={"search":"termo","fields":["name","description","sku"]}
Este enfoque permite buscar un término en múltiples campos simultáneamente.
Con estas herramientas y conocimientos, deberías poder solucionar la mayoría de los problemas comunes que surgen al trabajar con el framework. Recuerda que el logging y la depuración adecuados son fundamentales para identificar y resolver problemas rápidamente.