8. Validación de datos
Descripción General
El sistema de validación implementa un mecanismo robusto para verificar y validar los datos de entrada en las solicitudes HTTP antes de procesarlas en la lógica de negocio. Utiliza un enfoque basado en reglas con un diseño modular que facilita la extensibilidad y la reutilización.
Arquitectura
La arquitectura del sistema de validación sigue el patrón Factory para la creación de reglas de validación y utiliza interfaces para desacoplar la implementación de las reglas de su uso. Se compone principalmente de:
- ValidaRequest: Clase principal para validar solicitudes HTTP
- RuleFactory: Fábrica para crear instancias de reglas de validación
- RuleInterface: Interfaz que todas las reglas de validación deben implementar
- Reglas específicas: Implementaciones concretas de reglas de validación
ValidaRequest -> RuleFactory -> RuleInterface <- Implementaciones de reglas
Implementación actual
ValidaRequest en Validations
La implementación actual se encuentra en App\Validations\ValidaRequest y utiliza el patrón Factory para crear instancias de reglas de validación. Esta clase proporciona métodos fluidos para definir y aplicar reglas de validación a los campos de solicitud HTTP.
// Ejemplo de cómo se instancia y utiliza
ValidaRequest::make($request)
->validateHeaders(['x-tienda' => 'required|numeric'])
->validateBody(['user_id' => 'required|numeric'])
->action('store')
->handle();
RuleFactory
La clase App\Validations\Rules\RuleFactory implementa el patrón Factory y es responsable de crear instancias de reglas de validación basadas en el nombre de la regla.
public static function make(string $rule): RuleInterface
{
$ruleClass = __NAMESPACE__ . '\\' . ucfirst($rule) . 'Rule';
if (!class_exists($ruleClass)) {
throw new Exception("Regla de validación no encontrada: $rule");
}
return new $ruleClass();
}
RuleInterface
La interfaz App\Validations\Contracts\RuleInterface define el contrato que todas las reglas de validación deben implementar:
interface RuleInterface
{
public function validate(string $field, $value, array $params): bool;
}
Reglas de validación disponibles
El sistema incluye varias reglas de validación implementadas que pueden ser utilizadas para validar diferentes tipos de datos:
- RequiredRule: Valida que un campo esté presente y no esté vacío
- NumericRule: Valida que un valor sea numérico
- EmailRule: Valida direcciones de correo electrónico
- StringRule: Valida que un valor sea una cadena de texto
- LengthRule: Valida la longitud exacta de una cadena
- MinRule: Valida la longitud mínima de una cadena
- MaxRule: Valida la longitud máxima de una cadena
- FiscalRule: Valida identificadores fiscales según el país
Validadores especializados
TaxIdentifierValidator
El sistema incluye validadores especializados como TaxIdentifierValidator para la validación de identificadores fiscales específicos por país:
namespace App\Validations\TaxValidations;
class TaxIdentifierValidator {
private $validator;
private $taxId;
public function __construct(string $countryCode, string $taxId) {
$this->validator = TaxValidatorFactory::create($countryCode);
$this->taxId = trim($taxId);
}
public function validate(): void {
$this->validator->validate($this->taxId);
}
public function getType(): string {
return $this->validator->type($this->taxId);
}
}
Este validador utiliza el patrón Factory para crear validadores específicos según el código de país proporcionado.
Implementación deprecated
Nota: Existe una implementación deprecated de
ValidaRequesten el namespaceApp\Helpers. Esta versión antigua no debe utilizarse en nuevos desarrollos y se mantiene por compatibilidad con código legado.
La versión deprecated no utiliza el patrón Factory y maneja la validación de manera más monolítica, lo que dificultaba la extensibilidad y el mantenimiento.
Uso en controladores
El sistema de validación se utiliza principalmente en controladores, particularmente en los métodos store y update:
public function store(Request $request)
{
ValidaRequest::make($request)
->validateHeaders($this->validations['headers'])
->validateBody($this->validations['body'])
->action('store')
->handle();
$response = $this->service->store($request->all());
return response()->json($response, 200);
}
Tipos de validación
El sistema admite dos categorías principales de validación:
Validación de headers
Valida los encabezados HTTP requeridos para la solicitud, como tokens de autenticación, identificadores de tienda, etc.
Validación de body
Valida el cuerpo de la solicitud, asegurando que los datos enviados cumplan con las reglas de negocio antes de procesarlos.
Sintaxis de reglas
Las reglas de validación utilizan una sintaxis simple basada en cadenas, similar a otros frameworks populares:
campo => 'regla1|regla2:param1,param2|regla3'
Por ejemplo:
'user_id' => 'required|numeric'
'email' => 'required|email'
'name' => 'required|string|min:3|max:50'
Flujo de validación
- Se crea una instancia de
ValidaRequestcon la solicitud HTTP - Se definen las reglas de validación para headers y body
- Se especifica la acción (store/update) que afecta cómo se aplican ciertas reglas
- Se ejecuta el método
handle()que procesa la validación - Si hay errores de validación, se lanza una excepción
ValidationException - Si la validación es exitosa, el flujo continúa normalmente
Excepciones
El sistema utiliza App\Exceptions\ValidationException para manejar errores de validación:
class ValidationException extends Exception
{
protected $errors;
public function __construct($message = "", $errors = [], $code = 0, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
$this->errors = $errors;
}
public function getErrors()
{
return $this->errors;
}
}
Consideraciones técnicas
- Las reglas se pueden combinar con el operador
|para aplicar múltiples validaciones a un mismo campo - Algunas reglas aceptan parámetros que se especifican después de
:y se separan por, - La acción
updatehace que las reglasrequiredsean opcionales para permitir actualizaciones parciales - Se pueden crear validadores personalizados implementando la interfaz
RuleInterface
Decisiones de diseño
- Patrón Factory: Se eligió el patrón Factory para permitir la creación dinámica de reglas de validación, facilitando la extensibilidad
- Interfaces: El uso de interfaces permite el desacoplamiento y facilita las pruebas unitarias
- Método fluido: La API de validación utiliza el método fluido para mejorar la legibilidad y mantener un estilo declarativo
- Validación por acción: La distinción entre acciones (store/update) permite que las reglas se apliquen de manera contextual
Ejemplos de extensión
Para crear una nueva regla de validación:
- Crear una clase que implemente
RuleInterface - Implementar el método
validate - Colocar la clase en el directorio
App\Validations\Rulescon el nombre[Regla]Rule.php
namespace App\Validations\Rules;
use App\Validations\Contracts\RuleInterface;
class CustomRule implements RuleInterface
{
public function validate(string $field, $value, array $params): bool
{
// Implementación de la validación
return true; // o false si la validación falla
}
}
Luego se puede usar en las validaciones como:
'campo' => 'required|custom'