ADR-005 - Patrón de Middleware PSR-15
ADR-005: Patrón de Middleware PSR-15 para XOOPS 4.0
Sección titulada «ADR-005: Patrón de Middleware PSR-15 para XOOPS 4.0»Adoptar controladores de solicitud del servidor HTTP PSR-15 (middleware) para mejorar la canalización de procesamiento de solicitudes.
Propuesto - Bajo evaluación para lanzamiento XOOPS 4.0
Contexto
Sección titulada «Contexto»Enfoque Actual
Sección titulada «Enfoque Actual»XOOPS 2.5 usa un enfoque monolítico de manejo de solicitudes:
// Current: Sequential processingrequire_once 'mainfile.php';// → Kernel initialization// → User authentication// → Module loading// → Page rendering
// All in one flow, mixed concernsProblemas con el Enfoque Actual
Sección titulada «Problemas con el Enfoque Actual»- Responsabilidades Mixtas - Autenticación, registro, enrutamiento todos entrelazados
- Difícil de Probar - Difícil hacer pruebas unitarias de pasos individuales de procesamiento de solicitud
- Difícil de Extender - Los módulos solo pueden enganchar a través de preload/events
- Separación Pobre - Lógica de procesamiento de solicitud dispersa en toda la base de código
- No Componible - No se pueden encadenar o reordenar fácilmente los pasos de procesamiento
¿Qué es PSR-15 Middleware?
Sección titulada «¿Qué es PSR-15 Middleware?»PSR-15 define una interfaz estándar para middleware HTTP:
<?phpinterface RequestHandlerInterface { public function handle(ServerRequestInterface $request): ResponseInterface;}
interface MiddlewareInterface { public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface;}Cadena de Middleware:
Request ↓[Logger] → logs request ↓[Auth] → validates user session ↓[CORS] → checks cross-origin ↓[Router] → dispatches to handler ↓[Handler] → generates response ↓ResponseDecisión
Sección titulada «Decisión»Adoptar Pila de Middleware PSR-15 para XOOPS 4.0
Sección titulada «Adoptar Pila de Middleware PSR-15 para XOOPS 4.0»Implementar una canalización de procesamiento de solicitud basada en middleware siguiendo el estándar PSR-15.
Architecture Overview
Sección titulada «Architecture Overview»graph TD subgraph "Request Processing Pipeline" A["HTTP Request<br/>(PSR-7 ServerRequest)"] B["Middleware Stack<br/>(PSR-15)"] C["Logger Middleware"] D["Session Middleware"] E["Auth Middleware"] F["CORS Middleware"] G["Router Middleware"] H["Handler<br/>(Controller/Action)"] I["Response<br/>(PSR-7 Response)"] end
A --> B B --> C C --> D D --> E E --> F F --> G G --> H H --> ICore Middleware Components
Sección titulada «Core Middleware Components»1. Application Middleware (Core Layer)
Sección titulada «1. Application Middleware (Core Layer)»<?phpdeclare(strict_types=1);
namespace XoopsCore;
use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ServerRequestInterface;use Psr\Http\Server\MiddlewareInterface;use Psr\Http\Server\RequestHandlerInterface;
class SessionMiddleware implements MiddlewareInterface{ public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { // 1. Retrieve session (or start new) $sessionId = $request->getCookieParams()['PHPSESSID'] ?? null; $session = $this->sessionManager->load($sessionId);
// 2. Attach session to request $request = $request->withAttribute('session', $session);
// 3. Pass to next middleware $response = $handler->handle($request);
// 4. Set session cookie if needed if ($session->isModified()) { $response = $response->withAddedHeader( 'Set-Cookie', 'PHPSESSID=' . $session->getId() . '; HttpOnly; SameSite=Strict' ); }
return $response; }}2. Authentication Middleware
Sección titulada «2. Authentication Middleware»<?phpclass AuthMiddleware implements MiddlewareInterface{ public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { // Get session from previous middleware $session = $request->getAttribute('session');
// Authenticate user from session $user = $this->authenticate($session);
// Attach user to request $request = $request->withAttribute('user', $user);
return $handler->handle($request); }
private function authenticate(?Session $session): User { if ($session && $session->has('uid')) { return $this->userRepository->findById($session->get('uid')); }
return new AnonymousUser(); }}3. Authorization Middleware
Sección titulada «3. Authorization Middleware»<?phpclass AuthorizationMiddleware implements MiddlewareInterface{ public function __construct(private AuthorizationChecker $checker) { }
public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { $user = $request->getAttribute('user'); $route = $request->getAttribute('route');
// Check if user has permission for this route if (!$this->checker->isGranted($user, $route)) { return new JsonResponse( ['error' => 'Unauthorized'], 403 ); }
return $handler->handle($request); }}4. Module Middleware
Sección titulada «4. Module Middleware»<?php// Modules can provide their own middlewareclass PublisherAccessMiddleware implements MiddlewareInterface{ public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { $user = $request->getAttribute('user');
// Module-specific access control if (!$user->hasPermission('publisher_view')) { return new HtmlResponse('Access denied', 403); }
return $handler->handle($request); }}Implementation Example
Sección titulada «Implementation Example»<?php// bootstrap.php - Application setup
use Psr\Http\Message\ServerRequestInterface;use Psr\Http\Server\RequestHandlerInterface;use Xoops\Core\Middleware\{ LoggerMiddleware, SessionMiddleware, AuthMiddleware, CorsMiddleware, ErrorHandlingMiddleware};
// Create middleware pipeline$middlewareStack = [ // 1. Error handling (outermost) new ErrorHandlingMiddleware(),
// 2. Logging new LoggerMiddleware($logger),
// 3. CORS handling new CorsMiddleware($corsConfig),
// 4. Session management new SessionMiddleware($sessionManager),
// 5. Authentication new AuthMiddleware($userRepository),
// 6. Authorization new AuthorizationMiddleware($authChecker),
// 7. Routing and dispatching new RoutingMiddleware($router),
// 8. Module middleware (dynamic) ...$this->loadModuleMiddleware(),];
// Process request through middleware stack$request = ServerRequestFactory::fromGlobals();$dispatcher = new MiddlewareDispatcher($middlewareStack);$response = $dispatcher->dispatch($request);
// Send responsehttp_response_code($response->getStatusCode());foreach ($response->getHeaders() as $name => $values) { foreach ($values as $value) { header("$name: $value", false); }}echo $response->getBody();Module Integration
Sección titulada «Module Integration»Modules can provide middleware:
<?php// Publisher module - xoops_version.php
$modversion['middleware'] = [ 'PublisherAccessMiddleware' => true, // Auto-load 'PublisherLogMiddleware' => true,];
// Or custom:$modversion['middleware_factory'] = function() { return [ new PublisherCacheMiddleware(), new PublisherPermissionMiddleware(), ];};Consecuencias
Sección titulada «Consecuencias»Efectos Positivos
Sección titulada «Efectos Positivos»- Separación de Responsabilidades - Cada middleware maneja una responsabilidad
- Testeabilidad - Fácil hacer pruebas unitarias de componentes individuales de middleware
- Componibilidad - El middleware se puede mezclar y reordenar
- Conforme a Estándares - Usa estándares PSR-15 y PSR-7
- Extensibilidad - Los módulos pueden agregar fácilmente middleware personalizado
- Depuración - Flujo de solicitud claro a través de la canalización
- Rendimiento - Puede optimizar capas de middleware específicas
- Interoperabilidad - Puede usar middleware PSR-15 de terceros
Efectos Negativos
Sección titulada «Efectos Negativos»- Curva de Aprendizaje - Los desarrolladores deben entender PSR-15
- Sobrecarga de Rendimiento - Más llamadas de función en la canalización
- Complejidad - Más partes móviles que el enfoque monolítico
- Esfuerzo de Migración - Requiere refactorizar código existente
- Dependencias - Requiere biblioteca HTTP PSR-7
Riesgos y Mitigaciones
Sección titulada «Riesgos y Mitigaciones»| Riesgo | Severidad | Mitigación |
|---|---|---|
| Cadenas de middleware complejas | Media | Documentación clara, ejemplos |
| Degradación de rendimiento | Media | Punto de referencia, optimizar rutas críticas |
| Mal uso del desarrollador | Media | Revisión de código, guía de mejores prácticas |
| Cambios importantes de migración | Alta | Período de deprecación, ayudantes |
| Problemas de orden de middleware | Media | Gráfico de dependencia claro |
Plan de Implementación
Sección titulada «Plan de Implementación»Fase 1: Fundación (Q2 2026)
Sección titulada «Fase 1: Fundación (Q2 2026)»- Implementar envoltorio de mensaje HTTP PSR-7
- Crear MiddlewareDispatcher
- Implementar middleware central (sesión, auth)
- Actualizar kernel para usar middleware
Fase 2: Integración (Q3 2026)
Sección titulada «Fase 2: Integración (Q3 2026)»- Migrar funcionalidad existente a middleware
- Agregar soporte de middleware de módulo
- Crear utilidades de prueba de middleware
- Escribir documentación completa
Fase 3: Migración (Q4 2026)
Sección titulada «Fase 3: Migración (Q4 2026)»- Proporcionar capa de compatibilidad para código antiguo
- Ayudar a módulos a actualizar a nuevo middleware
- Optimización de rendimiento
- Auditoría de seguridad
Fase 4: Lanzamiento (Q1 2027)
Sección titulada «Fase 4: Lanzamiento (Q1 2027)»- Lanzamiento XOOPS 4.0 con middleware
- Deprecar sistema de preload/hook antiguo
- Retroalimentación de la comunidad y actualizaciones
Criterios de Éxito
Sección titulada «Criterios de Éxito»- Toda funcionalidad central migrada a middleware
- Cobertura de pruebas 90%+ para middleware
- Documentación completa con ejemplos
- Rendimiento dentro del 10% de versión anterior
- Módulos usan exitosamente nuevo sistema de middleware
- Tasa de adopción de comunidad >80%
Mejores Prácticas de Middleware
Sección titulada «Mejores Prácticas de Middleware»- Mantener middleware enfocado (responsabilidad única)
- Usar inmutabilidad (crear nueva solicitud/respuesta)
- Manejar errores correctamente
- Documentar dependencias
- Agregar type hints
- Escribir pruebas para middleware
- Usar interfaces PSR-15 estándar
No Hacer
Sección titulada «No Hacer»- No modificar objetos de solicitud/respuesta compartidos
- No acceder a globales directamente
- No crear dependencias en orden de middleware
- No captar todas las excepciones
- No mezclar lógica de negocio con middleware
- No hacer que middleware haga demasiado
Ejemplos
Sección titulada «Ejemplos»Middleware Personalizado
Sección titulada «Middleware Personalizado»<?php// Example: Rate limiting middleware
use Psr\Http\Message\ResponseInterface;use Psr\Http\Message\ServerRequestInterface;use Psr\Http\Server\MiddlewareInterface;use Psr\Http\Server\RequestHandlerInterface;
class RateLimitMiddleware implements MiddlewareInterface{ public function __construct( private RateLimiter $limiter, private int $limit = 100, private int $window = 3600 ) { }
public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { $user = $request->getAttribute('user'); $identifier = $user->getId() ?? $request->getClientIp();
// Check rate limit $remaining = $this->limiter->check($identifier, $this->limit, $this->window);
if ($remaining < 0) { return new JsonResponse( ['error' => 'Rate limit exceeded'], 429 ); }
// Add rate limit headers $response = $handler->handle($request); return $response ->withAddedHeader('X-RateLimit-Limit', (string)$this->limit) ->withAddedHeader('X-RateLimit-Remaining', (string)$remaining); }}Decisiones Relacionadas
Sección titulada «Decisiones Relacionadas»- ADR-001: Arquitectura Modular - Fundación
- ADR-004: Sistema de Seguridad - Usa middleware para auth
- ADR-006: Autenticación de Dos Factores - Puede ser middleware
Referencias
Sección titulada «Referencias»Estándares PSR
Sección titulada «Estándares PSR»Marcos de Middleware
Sección titulada «Marcos de Middleware»- Slim Framework - Ejemplos de middleware
- Zend Expressive - Marco PSR-15
- Guzzle - Middleware de cliente HTTP
Herramientas
Sección titulada «Herramientas»- RelayPHP - Biblioteca de middleware
- PSR-15 Middleware - Colección de middlewares
Historial de Versiones
Sección titulada «Historial de Versiones»| Versión | Fecha | Cambios |
|---|---|---|
| 1.0.0 | 2024-01-28 | Propuesta inicial |
#xoops #adr #psr-15 #middleware #architecture #psr-7