# Auditoria Engine PHP y portabilidad Harbour Fecha: 2026-07-08 Alcance: `cliente/php`, `servidor/php`, `public/motor`, `public/php` y clases usadas por `preview.php`, `export_ir.php` y runtime. No se proponen cambios productivos en esta fase. Este documento describe el estado actual, riesgos y orden recomendado de limpieza antes de portar a Harbour. ## Resumen ejecutivo El Engine PHP ya tiene una separacion inicial valida entre plantilla, datos, contexto, evaluador, composicion, paginacion, documento renderizable y renderizador. La direccion arquitectonica es correcta, pero todavia no esta suficientemente limpio para portarlo a Harbour sin arrastrar deuda. Los puntos mas delicados son: - `TTable`: concentra modelo, normalizacion, runtime de tabla, paginacion interna, grupos, acumuladores y composicion de celdas. Es la clase mas dificil de portar. - `TEvaluadorFormulas`: mezcla parser, evaluador, resolucion de variables y funciones internas de paginacion/runtime. - `TFuncFormulas`: biblioteca de funciones LL12/Dominus con responsabilidades heterogeneas, incluyendo fechas, transformacion, barcode y lectura de ficheros. - `TPreviewPHP`: mezcla fachada servidor, paginacion previa, creacion de ficheros temporales, progreso, ejecucion del engine, HTML/CSS/JS de viewer y resolucion de rutas. - `TSalidaHTML`: esta correctamente aislada como renderer HTML, pero es demasiado grande y mezcla estilos, conversion de unidades y render de todos los tipos. - `public/php` es modelo compartido, pero tambien contiene metadatos de UI (`getProperties`) y generacion de renderizables (`generarRenderizable`). Para Harbour conviene aislar esas responsabilidades aunque se mantenga compatibilidad en PHP. Conclusion: no conviene portar directamente. Primero hay que extraer un nucleo minimo que haga: ```text .lbl / plantilla normalizada + datos -> contexto runtime -> IR / TDocumentoRenderizable ``` Sin web, sin HTML, sin importador y sin diseñador. ## Diagrama de capas objetivo ```text Client API TLLDominusPHP | Engine Facade TEngineRuntime / TPreviewRuntime / TIRRuntime | Template Model TDocument, TObjectBase, TText, TRectangle, TEllipse, TLine, TImage, TBarcode TTableModel, TTableSection, TTableLine, TTableCell | Runtime Context TContextoEjecucion, TConectorDatos, TEstadoEjecucion, TAvisosRuntime | Formula Engine TEvaluadorFormulas, TFormulaParser, TFormulaAst, TFormulaRuntimeFunctions, TFuncFormulas | Table Runtime TTableRuntime, TTablePaginator, TTableComposer, TAccumulatorRuntime, TGroupRuntime | Pagination Engine TMotorPaginacion, TLabelPaginator, TReportPaginator | IR Builder TMotorEjecucion, TMotorComposicion, TDocumentoRenderizable | Renderers TRenderizador + TSalidaHTML futuro Harbour/GDI Renderer futuro Printer Renderer ``` Regla objetivo: todo lo que este por encima de `IR Builder` puede existir en PHP sin portarse a Harbour. Todo lo que este por debajo de `Client API` no debe depender de `$_POST`, `php://input`, rutas web, HTML, CSS, JS ni `tempnam`. ## Inventario de clases | Clase | Archivo | Clasificacion | Responsabilidad actual | Metodos principales | Dependencias | Problemas detectados | SRP | Dividir | Port Harbour | |---|---|---|---|---|---|---|---|---|---| | `TLLDominusPHP` | `cliente/php/TLLDominusPHP.php` | Cliente | API cliente: abre job, filtra variables usadas, recibe datos y lanza preview. | `OpenJob`, `CloseJob`, `Preview`, `SendDataVar`, `SendDetalle`, `IsUsedVar`, `SetEtiquetaInicial` | Plantillas en `lbl`, `TPreviewPHP`, estructura JSON del job | Analisis de variables por regex dentro del cliente; dependencia de ruta `lbl`; `Preview` instancia servidor directo. | Parcial | Si | Parcial | | `TPreviewPHP` | `servidor/php/TPreviewPHP.php` | Servidor/Fachada | Ejecuta jobs del cliente y genera HTML de preview multipagina. | `Preview`, `generarPreviewHtml`, `generarPaginasRuntime`, `ejecutarMotor`, `renderizarPaginas` | Todo el engine, rutas de proyecto, ficheros temporales, `TSalidaHTML`, JS/CSS embebido | Mezcla fachada, runtime, pre-paginacion, viewer HTML, progreso, rutas y temporales. Clase demasiado grande. | No | Si | No | | `TObjectBase` | `public/php/TObjectBase.php` | Modelo de plantilla | Propiedades comunes, serializacion base, UI de propiedades y visibilidad runtime. | `getProperties`, `save`, `load`, `generarBaseRenderizable`, `esVisibleEnEjecucion` | `TContextoEjecucion` por contrato dinamico | Mezcla modelo, metadatos UI y ayuda de composicion runtime. | Parcial | Si | Si, sin UI | | `TDocument` | `public/php/TDocument.php` | Modelo de plantilla | Documento/plantilla: papel, objetos, variables, label layout, carga/guarda. | `save`, `load`, `createObjectByType`, `normalizeZIndex`, `isLabelDocument` | Clases de objetos `T*` | Modelo bastante claro, pero normaliza layout y crea objetos por switch. `isListDocument` devuelve siempre false. | Si | No urgente | Si | | `TRectangle` | `public/php/TRectangle.php` | Modelo de plantilla | Rectangulo visual y renderizable. | `getProperties`, `generarRenderizable` | `TObjectBase`, contexto runtime | Correcta, aunque comparte el problema modelo/UI/renderizable. | Parcial | No urgente | Si | | `TEllipse` | `public/php/TEllipse.php` | Modelo de plantilla | Elipse visual y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, contexto runtime | Correcta, problema comun modelo/UI/renderizable. | Parcial | No urgente | Si | | `TLine` | `public/php/TLine.php` | Modelo de plantilla | Linea visual y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, contexto runtime | Correcta, problema comun modelo/UI/renderizable. | Parcial | No urgente | Si | | `TText` | `public/php/TText.php` | Modelo de plantilla | Texto, propiedades tipograficas, normalizacion y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, contexto runtime | Mezcla metadatos UI, evaluacion de color y composicion IR. | Parcial | Recomendable | Si | | `TBarcode` | `public/php/TBarcode.php` | Modelo de plantilla | Codigo de barras, propiedades y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, `TBarcodeUtil`, contexto runtime | Correcta, pero debe separar modelo y generacion IR para port limpio. | Parcial | Recomendable | Si | | `TImage` | `public/php/TImage.php` | Modelo de plantilla | Imagen, origen, propiedades y renderizable. | `getProperties`, `save`, `load`, `generarRenderizable` | `TObjectBase`, `TImageUtil`, contexto runtime | `TImageUtil` resuelve rutas/contenido; riesgo de dependencia filesystem. | Parcial | Recomendable | Si, parcial | | `TTable` | `public/php/TTable.php` | Tabla/Paginacion | Tabla completa: modelo, normalizacion, secciones, grupos, acumuladores, paginacion interna y renderizables. | `save`, `load`, `generarRenderizable`, `renderSectionLines`, `pushRecordVariables`, `acumularDetalle`, normalizadores | `TRectangle`, `TText`, `TBarcode`, `TImage`, contexto runtime | Clase gigante. Mezcla modelo, runtime, paginacion, composicion, acumuladores, grupos y reglas visuales. Principal bloqueo para Harbour. | No | Si, obligatorio | Si, tras dividir | | `TPlantilla` | `public/motor/clases/TPlantilla.php` | Modelo de plantilla | Carga/normaliza plantilla JSON y expone pagina, objetos, vars y layout de etiquetas. | `create`, `fromData`, `getPagina`, `getObjetos`, `getUserVars`, `getAcumVars`, `getLabelLayout` | `LLDominus\TDocument`, filesystem JSON | Mezcla loader de fichero y wrapper de modelo; normalizacion legacy minima. | Parcial | Recomendable | Si, como loader separado | | `TConectorDatos` | `public/motor/clases/TConectorDatos.php` | Runtime Context | Carga datos JSON y expone variables/registro detalle normalizados. | `create`, `getVariables`, `getData`, `getRegistrosDetalle`, `normalizarDatosRuntime` | Filesystem, JSON, estructura LL12 `DataVar`/`DetalleVar` | Mezcla carga de fichero, normalizacion LL12, validacion, variables binarias y adaptador runtime. | Parcial | Si | Si, sin filesystem | | `TContextoEjecucion` | `public/motor/clases/TContextoEjecucion.php` | Runtime Context | Estado runtime: variables, pagina, registros, acumuladores, avisos y evaluacion. | `getVariables`, `pushRegistroDetalle`, `setEstadoPagina`, `acumularDetalle`, `evaluarFormula`, `evaluarCondicion` | `TConectorDatos`, `TEvaluadorFormulas` | Bastante central; mezcla estado, acumuladores y puente al evaluador. Puede crecer demasiado. | Parcial | Recomendable | Si | | `TEvaluadorFormulas` | `public/motor/clases/TEvaluadorFormulas.php` | Formulas | Evalua expresiones sin `eval`, texto, condiciones, aritmetica, comparaciones y funciones runtime. | `evaluarFormula`, `evaluarTexto`, `evaluarCondicion`, separadores, funciones internas | `TFuncFormulas`, estado runtime | Mezcla parser, evaluador, resolucion de variables, funciones internas `PageBy`/grupo. Dificil de validar formalmente. | No | Si, obligatorio | Si, tras parser claro | | `TFuncFormulas` | `public/motor/clases/TFuncFormulas.php` | Formulas | Biblioteca de funciones Dominus/LL12. | `ejecutar`, `Abs`, `Transform`, `DToC`, `FStr`/equivalentes, `Barcode`, etc. | `TBarcodeUtil`, `DateTimeImmutable`, filesystem en funciones tipo memo | Clase grande y heterogenea; algunas funciones tienen efectos/entorno. | Parcial | Si | Si, parcial | | `TBarcodeUtil` | `public/motor/clases/TBarcodeUtil.php` | Utilidad | Normaliza y calcula barcode, especialmente EAN13. | `crear`, `normalizarTipo`, `crearEAN13` | Ninguna externa relevante | Correcta y pequena. | Si | No | Si | | `TImageUtil` | `public/motor/clases/TImageUtil.php` | Utilidad | Resuelve imagen desde contenido/ruta y MIME. | `resolver`, `detectarMime`, `resolverRuta` | Filesystem, rutas relativas al proyecto | Utilidad mezcla contenido y resolucion de rutas PHP/web. | Parcial | Recomendable | Parcial | | `TMotorComposicion` | `public/motor/clases/TMotorComposicion.php` | Engine Core | Delega composicion en objetos con `generarRenderizable`. | `componer` | Objetos modelo con metodo runtime | Muy simple, pero la responsabilidad real esta en objetos. | Si | No | Si | | `TMotorPaginacion` | `public/motor/clases/TMotorPaginacion.php` | Pagination Engine | Paginacion actual simple: crea una pagina con objetos. | `paginar` | `TDocumentoRenderizable` | Es placeholder; la paginacion real vive en `TTable` y `TPreviewPHP`. | Parcial | Si | Si, tras mover logica | | `TMotorEjecucion` | `public/motor/clases/TMotorEjecucion.php` | Engine Core | Coordina plantilla, datos, composicion, paginacion y etiquetas. | `ejecutar`, `ejecutarEtiquetas`, `agregarRenderizableCompuesto` | `TPlantilla`, `TConectorDatos`, `TMotorComposicion`, `TMotorPaginacion`, `TContextoEjecucion` | Mezcla flujo general con layout/paginacion de etiquetas. | Parcial | Recomendable | Si | | `TDocumentoRenderizable` | `public/motor/clases/TDocumentoRenderizable.php` | IR Builder | Documento intermedio con paginas y objetos resueltos. | `setTamano`, `addPagina`, `getPaginas` | Ninguna relevante | Correcta, aunque necesita schema mas explicito para port. | Si | No | Si | | `TRenderizador` | `public/motor/clases/TRenderizador.php` | Renderer HTML | Recorre IR y delega en salida concreta. | `render`, `renderObjeto` | `TDocumentoRenderizable`, salida con metodos `texto`, `rectangulo`, etc. | Correcta. Switch por tipo aceptable; podria formalizar interfaz. | Si | No urgente | Parcial | | `TSalidaHTML` | `public/motor/clases/TSalidaHtml.php` | Renderer HTML | Convierte IR a HTML/CSS. | `iniciarDocumento`, `iniciarPagina`, `texto`, `rectangulo`, `barcode`, `imagen`, helpers CSS | HTML/CSS, escaping, unidades CSS | Grande y monolitica. Esta bien que sea no portable, pero conviene dividir por objeto. | Parcial | Recomendable | No | | `TNormalizadorFuncionesLL12` | `public/motor/herramientas/TBaseLenguajeLL12.php` | Importador LL12 | Normaliza nombres de funciones LL12. | metodos de normalizacion | Herramientas LL12 | Herramienta, no runtime. | Si | No | No | | `TBaseLenguajeLL12` | `public/motor/herramientas/TBaseLenguajeLL12.php` | Importador LL12 | Carga/manualiza base de lenguaje LL12. | `create`, lectores, generadores | PDF/texto/JSON de herramientas | Fuera del engine runtime. | Si | No | No | | `TExtractorPdfTextoLL12` | `public/motor/herramientas/TBaseLenguajeLL12.php` | Importador LL12 | Extrae texto de PDF/manual LL12. | `extraerTexto` | Sistema/PDF externo segun implementacion | Herramienta no portable al engine. | Si | No | No | | `TAnalizadorLenguajeLST` | `public/motor/herramientas/TAnalizadorLenguajeLST.php` | Importador LL12 | Analiza LST antiguos para extraer uso de funciones. | `create`, `analizar`, recolectores | `TBaseLenguajeLL12`, filesystem | Grande, pero es herramienta de migracion, no engine. | Parcial | Puede esperar | No | | `TAnalizadorExpresionesLST` | `public/motor/herramientas/TAnalizadorLenguajeLST.php` | Importador LL12 | Analiza expresiones LST y funciones usadas. | analizadores de expresion | Regex/parser propio | Util para importador, no runtime. | Parcial | Puede esperar | No | | `TInformeLenguajeLST` | `public/motor/herramientas/TAnalizadorLenguajeLST.php` | Importador LL12 | Genera informe HTML/JSON del analisis LST. | `generar` | HTML, filesystem | Renderer de herramienta. No engine. | Si | No | No | | `TLenguajeDominusBuilder` | `public/motor/herramientas/generar_lenguaje_dominus.php` | Herramientas/tests | Genera catalogo de lenguaje Dominus desde datos LL12. | `create`, `guardar`, `crearFuncionesDominus` | JSON, docs | Herramienta de build/documentacion. | Si | No | No | | `TGeneradorManualFunciones` | `public/motor/herramientas/generar_manual_funciones.php` | Herramientas/tests | Genera manual HTML de funciones. | `create`, `generarHtml` | JSON, HTML, docs | Herramienta de documentacion. | Si | No | No | | `TTablePaginationTestContext` | `public/motor/tests/table_pagination/run_tests.php` | Herramientas/tests | Contexto falso para tests de tabla/paginacion. | metodos stub de contexto | Tests, `TTable` | Solo test. | Si | No | No | ## Scripts y endpoints auditados | Archivo | Clasificacion | Responsabilidad actual | Problemas | Port Harbour | |---|---|---|---|---| | `public/motor/index.php` | Herramientas/tests | Demo manual del motor: carga plantilla/datos y renderiza HTML. | Repite bootstrap de clases. Depende de rutas demo. | No | | `public/motor/preview.php` | Servidor/Fachada + Designer/UI | Endpoint POST para preview real desde diseñador. Prepara datos demo, ejecuta engine y renderiza HTML integrado. | Mezcla `php://input`, HTTP, preparacion de datos diseñador, engine y renderer. No debe ser nucleo. | No | | `public/motor/export_ir.php` | Servidor/Fachada + IR Builder | Endpoint POST para generar y guardar IR JSON. | Construccion/guardado de IR esta dentro del endpoint; necesita clase `TIRBuilder`/`TIRExporter`. | Parcial, solo logica IR | | `public/motor/validar_formula.php` | Servidor/Fachada + Formulas | Endpoint para validar formulas del diseñador. | Depende de POST y HTML de barcode para preview. La validacion core debe ir a clase. | Parcial | | `public/motor/demo_data.php` | Herramientas/tests | Devuelve datos demo. | Endpoint demo. | No | | `public/motor/recurso_existe.php` | Utilidad web | Comprueba existencia de recurso. | Web/filesystem, no core. | No | | `cliente/php/preview_demo.php` | Cliente + demo UI | Demo web/CLI de runtime, progreso y seleccion visual de etiqueta inicial. | Mezcla UI HTML, cliente, demo, seleccion de etiquetas y progreso. | No | | `public/motor/tests/*/run_tests.php` | Herramientas/tests | Tests de formulas, datos, etiquetas y paginacion. | Correctos como proteccion; no forman engine. | No | ## Clases que forman realmente el Engine Engine core actual: - `TPlantilla` - `TConectorDatos` - `TContextoEjecucion` - `TEvaluadorFormulas` - `TFuncFormulas` - `TMotorComposicion` - `TMotorPaginacion` - `TMotorEjecucion` - `TDocumentoRenderizable` - Modelo compartido: `TDocument`, `TObjectBase`, `TText`, `TRectangle`, `TEllipse`, `TLine`, `TImage`, `TBarcode`, `TTable` - Utilidades runtime: `TBarcodeUtil`, `TImageUtil` Renderer HTML: - `TRenderizador` - `TSalidaHTML` No son nucleo del engine: - `TLLDominusPHP` como API cliente PHP. - `TPreviewPHP` como fachada/preview server. - Endpoints `preview.php`, `export_ir.php`, `validar_formula.php`, `index.php`. - Herramientas LL12 y generadores de documentacion. - Tests. ## Problemas encontrados ### 1. `TTable` concentra demasiada logica Es el principal riesgo de portabilidad. Deberia dividirse en: - `TTableModel`: estructura persistente de secciones, lineas, celdas y opciones. - `TTableNormalizer`: migracion/normalizacion de estructuras. - `TTableRuntime`: recorrido de registros, grupos y acumuladores. - `TTablePaginator`: decisiones de salto, keep-with-previous, repeat header/footer. - `TTableComposer`: conversion de lineas/celdas a objetos IR. ### 2. La paginacion real no vive en `TMotorPaginacion` `TMotorPaginacion` solo empaqueta una pagina. La paginacion de detalle/tablas se hace en `TTable` y la paginacion previa de totales se coordina en `TPreviewPHP`. Para Harbour debe existir un motor de paginacion real sin dependencia de preview HTML. ### 3. `TPreviewPHP` no debe guiar el diseno del core Hace tareas utiles, pero no es portable: - resuelve rutas de `lbl`; - crea ficheros temporales; - repite ejecuciones para pre-paginacion; - emite progreso; - renderiza y envuelve HTML con toolbar CSS/JS; - parsea HTML con regex para insertar viewer. La logica de pre-paginacion y generacion de paginas debe salir a una fachada de engine sin HTML. ### 4. Formula engine sin AST explicito `TEvaluadorFormulas` separa expresiones por operadores top-level y evalua recursivamente. Funciona para el alcance actual, pero para Harbour conviene definir un parser/AST sencillo para evitar divergencias entre lenguajes. ### 5. Modelo compartido mezcla UI y runtime `getProperties()` pertenece al diseñador. `generarRenderizable()` pertenece al engine. En PHP se puede mantener por compatibilidad, pero el port Harbour deberia recibir modelos limpios y compositores separados. ### 6. Carga de datos acoplada a filesystem `TConectorDatos` carga JSON, resuelve rutas, carga binarios y normaliza runtime. El core portable deberia aceptar arrays/estructuras ya cargadas; un loader separado puede encargarse del filesystem. ### 7. IR existe pero no esta formalizado como contrato `TDocumentoRenderizable` es simple y bueno, pero el JSON de `export_ir.php` se construye en funciones globales del endpoint. Falta `TIRBuilder` con schema versionado. ### 8. Bootstrap duplicado `index.php`, `preview.php`, `export_ir.php` y `TPreviewPHP::cargarMotor()` repiten `require`. Antes del port conviene tener un bootstrap/autoload de engine. ## Refactor obligatorio antes de Harbour 1. Extraer una fachada core sin web: `TEngineRuntime`. - Entrada: plantilla ya cargada o ruta abstracta, datos ya cargados, opciones runtime. - Salida: `TDocumentoRenderizable`/IR. - Sin HTML, sin `$_POST`, sin `php://input`, sin `tempnam`. 2. Extraer `TIRBuilder`. - Mover desde `export_ir.php` la construccion del IR. - Definir schema estable: paginas, objetos, metadata, warnings, unidades mm. 3. Dividir `TTable`. - Minimo antes del port: sacar runtime/paginacion/acumuladores a clases nuevas. - Mantener `TTable` como modelo/compatibilidad. 4. Separar parser/evaluador de formulas. - `TFormulaTokenizer` o parser top-level. - `TFormulaEvaluator`. - `TFormulaRuntimeFunctions` para `Page`, `PageBy`, `GroupChanged`, etc. 5. Separar carga de datos de adaptador runtime. - `TDatosRuntime` o `TDataSetRuntime` desde array. - `TConectorDatosJson`/loader PHP para fichero. 6. Mover paginacion previa fuera de `TPreviewPHP`. - Clase `TPaginacionPreviaRuntime` o metodo de `TEngineRuntime`. - `TPreviewPHP` debe solo orquestar request/progreso/render HTML. ## Refactor recomendable 1. Separar `getProperties()` del modelo. - Crear metadata UI en diseñador o provider PHP separado. 2. Dividir `TSalidaHTML` por tipo de objeto. - `THtmlTextRenderer`, `THtmlShapeRenderer`, `THtmlImageRenderer`, `THtmlBarcodeRenderer`. 3. Formalizar interfaz de salida para `TRenderizador`. - Aunque PHP no lo requiera, Harbour se beneficiara de contrato claro. 4. Separar `TImageUtil` en resolver de contenido y resolver de rutas. 5. Crear bootstrap unico de engine PHP. 6. Crear tests de contrato IR. ## Refactor que puede esperar 1. Limpieza de herramientas LL12. 2. Generadores de documentacion de funciones. 3. UI del preview demo. 4. Mejoras de `TSalidaHTML` que no afecten IR. 5. Sustituir todos los `require` por autoload completo. ## Nucleo minimo portable para Harbour Para `.lbl + datos -> IR`, sin diseñador, sin importador y sin web, Harbour necesita estas piezas equivalentes: ### Imprescindibles - `TDocument` - `TObjectBase` - `TText` - `TRectangle` - `TEllipse` - `TLine` - `TImage` - `TBarcode` - `TTableModel` (extraido desde `TTable`) - `TPlantilla` o `TTemplateLoader` desde estructura ya cargada - `TDatosRuntime` / `TConectorDatos` sin filesystem - `TContextoEjecucion` - `TEvaluadorFormulas` - `TFuncFormulas` con subconjunto usado - `TBarcodeUtil` - `TImageUtil` parcial, sin rutas web - `TMotorComposicion` - `TMotorPaginacion` - `TTableRuntime` - `TTablePaginator` - `TTableComposer` - `TMotorEjecucion` - `TDocumentoRenderizable` - `TIRBuilder` ### Parciales o mas adelante - `TRenderizador`: solo si se quiere un renderer Harbour/GDI con el mismo contrato. - `TSalidaHTML`: no se porta; se reemplaza por `TSalidaHarbourGDI`/`TSalidaPrinter`. - `TLLDominusPHP`: se porta conceptualmente como API Harbour, no literal. - `TPreviewPHP`: no se porta; solo se reutiliza la idea de fachada. ### No portar - `preview.php` - `export_ir.php` como endpoint - `validar_formula.php` - `index.php` - `preview_demo.php` - `demo_data.php` - `recurso_existe.php` - Herramientas LL12: `TBaseLenguajeLL12`, `TAnalizadorLenguajeLST`, `TAnalizadorExpresionesLST`, `TInformeLenguajeLST`, `TLenguajeDominusBuilder`, `TGeneradorManualFunciones` - Tests PHP como clases runtime ## Orden recomendado 1. Crear tests de contrato para `.lbl + datos -> IR`. 2. Extraer `TIRBuilder` desde `export_ir.php`. 3. Crear `TEngineRuntime` y hacer que `preview.php`, `export_ir.php` y `TPreviewPHP` lo usen. 4. Extraer `TDatosRuntime` para aceptar datos en memoria. 5. Mover pre-paginacion desde `TPreviewPHP` al runtime/fachada core. 6. Dividir `TTable` en modelo, runtime, paginador y compositor. 7. Separar `TEvaluadorFormulas` en parser/evaluador/funciones runtime. 8. Congelar schema IR. 9. Portar a Harbour el nucleo minimo. 10. Implementar renderer Harbour/GDI contra IR. ## Riesgos para Harbour - Diferencias de fechas y formato numerico entre PHP y Harbour. - Diferencias de precision flotante en mm y redondeos. - Regex/parser de formulas dificil de replicar exactamente si no hay AST. - `TTable` contiene muchos casos de salto de pagina; port directo puede introducir regresiones. - `TImageUtil` y funciones tipo `hb_MemoRead` dependen de filesystem. - Colores, opacidades, sombras y bordes pueden no mapear 1:1 a GDI/impresora. - El HTML renderer tolera CSS; Harbour/GDI necesitara medidas explicitas, clipping y fuentes reales. ## Primera prueba minima recomendada Crear una prueba de contrato, independiente de HTML: ```text Entrada: lbl/prueba_texto.lbl o plantilla minima equivalente public/motor/datos/datos_prueba.json Proceso: TEngineRuntime(.lbl, datos, opciones).ejecutarIR() Asserts: - devuelve 1 pagina; - ancho/alto en mm coinciden con plantilla; - contiene texto evaluado; - respeta cCondition; - no contiene HTML; - IR serializa a JSON estable. ``` Despues repetir con: - etiqueta A4 con `nEtiquetaInicial`; - tabla con detalle que corta pagina; - tabla con grupo y acumuladores; - formula `Page()`, `Pages()`, `PageBy()` y `TotalPagesBy()`. ## Decision de portabilidad Estado actual: portable conceptualmente, no recomendable para port literal. Debe portarse primero el contrato de IR y el flujo core limpio. El HTML, endpoints, preview web, importador LL12 y herramientas deben quedar fuera del primer port.