Skip to main content

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:

  1. 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'
];
  1. Asegúrate de que las solicitudes incluyan las cabeceras Origin o Referer correctas.

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:

  1. Verifica que el archivo de rutas existe en la ubicación correcta y sigue la convención de nombres.
  2. Asegúrate de que las rutas están registradas correctamente usando Route::get(), Route::post(), etc.
  3. 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:

  1. Registra el servicio en src/Services/services.php:
return [
Services\Interfaces\MyServiceInterface::class => Services\MyService::class
];
  1. 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:

  1. 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
  1. Verifica las constantes de ruta en bootstrap.php para 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:

  1. Verifica la sintaxis de tus reglas de validación.
  2. Asegúrate de que las reglas personalizadas están implementadas correctamente.
  3. 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:

  1. Crear adaptadores específicos para cada base de datos
  2. Implementar clases de modelo que usen estos adaptadores
  3. 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.