El trait monolítico PointOfSaleTrait (414 líneas) ha sido refactorizado en una arquitectura basada en servicios con responsabilidades separadas.
Responsabilidad: Validaciones de permisos y tokens
validateDelete()- Valida permisos de eliminaciónvalidatePermissions()- Valida permisos de actualizaciónvalidateToken()- Valida tokens anti-duplicaciónvalidateRequest()- Validación completa de requestvalidateSettings()- Validación de configuración del POS
Responsabilidad: Construcción y envío de respuestas HTTP
setToken()- Establece el token de respuestaaddResponseData()- Añade datos a la respuestasetSuccessResponse()- Establece respuesta de éxitobuildResponse()- Construye respuesta completa con mensajessetResponse()- Envía la respuesta al clientegetMessages()- Obtiene mensajes de log del sistema
Responsabilidad: Gestión de hooks y elementos personalizados
addCustomDocumentField()- Añade campos personalizadosgetCustomDocumentFields()- Obtiene campos personalizadosaddCustomMenuElement()- Añade elementos de menúgetCustomMenuElements()- Obtiene elementos de menúaddHookAction()- Añade acciones de hookgetHookActions()- Obtiene acciones de hookgetPrintSaleTicketActions()- Acciones de impresión de ticketgetPrintDraftTicketActions()- Acciones de impresión de borradorgetPrintClosingTicketActions()- Acciones de impresión de cierre
Responsabilidad: Acceso a datos (solo getters legítimos)
getParentFamilies()- Obtiene familias padregetCashPaymentMethod()- Obtiene método de pago en efectivogetDefaultCustomer()- Obtiene cliente por defectogetDefaultDocument()- Obtiene documento por defectogetSupportedDocuments()- Obtiene documentos soportadosgetDenominations()- Obtiene denominaciones de monedagetFieldOptions()- Obtiene opciones de camposgetCartColumnCount()- Cuenta columnas del carritogetHomeProducts()- Obtiene productos inicialesgetPaymentMethods()- Obtiene métodos de pagogetDefaultWarehouse()- Obtiene almacén por defectogetSession()- Obtiene sesión actualgetTerminal()- Obtiene terminal actualgetTerminalFromCompany()- Obtiene terminales de la empresasetFamilyFilter()- Establece filtro de familia
Responsabilidad: Clase base abstracta con inyección de servicios
- Extiende
Controller - Usa
ExtensionsTraityPointOfSaleDataAccessTrait - Inyecta los servicios:
validator,responseBuilder,hookManager - Proporciona métodos delegadores a los servicios
setupServices()- Inicializa todos los servicios
Cada clase tiene una única responsabilidad bien definida.
Puedes hacer unit tests de cada servicio de forma independiente.
// Ejemplo de test
$validator = new PointOfSaleValidator($mockController);
$result = $validator->validateToken();Los servicios se pueden mockear fácilmente para testing.
Solo se cargan las clases que realmente se usan (autoloading).
Cada archivo es más pequeño y enfocado en una tarea específica.
Fácil añadir nuevos servicios sin modificar código existente.
Aprovecha PHP 8.1+ con tipado estricto en propiedades y métodos.
use FacturaScripts\Plugins\POS\Lib\PointOfSaleTrait;
class MiControladorPOS extends Controller
{
use PointOfSaleTrait;
public function miMetodo()
{
$this->validateRequest(); // Desde el trait
}
}use FacturaScripts\Plugins\POS\Lib\BasePointOfSaleController;
class MiControladorPOS extends BasePointOfSaleController
{
public function privateCore(&$response, $user, $permissions): void
{
parent::privateCore($response, $user, $permissions);
$this->setupServices(); // Inicializar servicios
}
public function miMetodo()
{
$this->validateRequest(); // Ahora delegado a validator
}
}El PointOfSaleTrait original se mantiene pero está marcado como @deprecated.
Esto permite que código existente siga funcionando mientras se migra gradualmente.
Prácticamente CERO con OPcache habilitado:
- Los archivos se compilan una vez a bytecode
- Se cachean en memoria
- Peticiones posteriores usan el bytecode cacheado
- Autoloading solo carga clases necesarias
- ✅ Creado:
Lib/PointOfSaleValidator.php - ✅ Creado:
Lib/PointOfSaleResponseBuilder.php - ✅ Creado:
Lib/PointOfSaleHookManager.php - ✅ Creado:
Lib/PointOfSaleDataAccessTrait.php - ✅ Creado:
Lib/BasePointOfSaleController.php - ✅ Modificado:
Controller/POS.php- Ahora extiendeBasePointOfSaleController - ✅ Modificado:
Lib/PointOfSaleTrait.php- Marcado como deprecated
- Testing: Crear tests unitarios para cada servicio
- Migración gradual: Actualizar otros controladores que usen el trait antiguo
- Documentación: Añadir ejemplos de uso en el README principal
- Deprecation warning: En una versión futura, emitir warnings cuando se use el trait
- Eliminación: Remover el trait antiguo en v3.0
namespace MiPlugin\Extension\Controller;
class MiExtensionPOS
{
public function loadCustomDocumentFields()
{
// El hookManager está disponible en el controlador
$this->addCustomDocumentField('cart', [
'name' => 'mi_campo',
'label' => 'Mi Campo Personalizado',
'type' => 'text'
]);
}
}- Refactorización realizada el: 2025-12-13
- Basado en el código original de Juan José Prieto Dzul
Nota: Este refactor sigue los principios SOLID y las mejores prácticas de PHP moderno.