Skip to main content

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:

  1. ValidaRequest: Clase principal para validar solicitudes HTTP
  2. RuleFactory: Fábrica para crear instancias de reglas de validación
  3. RuleInterface: Interfaz que todas las reglas de validación deben implementar
  4. 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:

  1. RequiredRule: Valida que un campo esté presente y no esté vacío
  2. NumericRule: Valida que un valor sea numérico
  3. EmailRule: Valida direcciones de correo electrónico
  4. StringRule: Valida que un valor sea una cadena de texto
  5. LengthRule: Valida la longitud exacta de una cadena
  6. MinRule: Valida la longitud mínima de una cadena
  7. MaxRule: Valida la longitud máxima de una cadena
  8. 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 ValidaRequest en el namespace App\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

  1. Se crea una instancia de ValidaRequest con la solicitud HTTP
  2. Se definen las reglas de validación para headers y body
  3. Se especifica la acción (store/update) que afecta cómo se aplican ciertas reglas
  4. Se ejecuta el método handle() que procesa la validación
  5. Si hay errores de validación, se lanza una excepción ValidationException
  6. 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

  1. Las reglas se pueden combinar con el operador | para aplicar múltiples validaciones a un mismo campo
  2. Algunas reglas aceptan parámetros que se especifican después de : y se separan por ,
  3. La acción update hace que las reglas required sean opcionales para permitir actualizaciones parciales
  4. Se pueden crear validadores personalizados implementando la interfaz RuleInterface

Decisiones de diseño

  1. Patrón Factory: Se eligió el patrón Factory para permitir la creación dinámica de reglas de validación, facilitando la extensibilidad
  2. Interfaces: El uso de interfaces permite el desacoplamiento y facilita las pruebas unitarias
  3. Método fluido: La API de validación utiliza el método fluido para mejorar la legibilidad y mantener un estilo declarativo
  4. 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:

  1. Crear una clase que implemente RuleInterface
  2. Implementar el método validate
  3. Colocar la clase en el directorio App\Validations\Rules con 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'