Migrar una base de código de TCPDF 6.x a NextPDF
De un vistazo
Sección titulada «De un vistazo»El paquete nextpdf/compat-legacy expone los nombres de método públicos, el orden de parámetros y los valores predeterminados de TCPDF 6.x sobre el motor del núcleo de NextPDF a través del adaptador NextPDF\Compat\Tcpdf\TCPDF. Migrar en este orden: pasar primero al motor con el cambio más pequeño posible, verificar lo que ya funciona, activar el modo estricto para listar lo que no funciona, corregir los puntos de llamada de uno en uno y, por último, retirar el adaptador para pasar a la API moderna. El adaptador es el andamiaje de la migración, no el punto de llegada.
Antes de empezar, requisitos previos:
- El núcleo de NextPDF y
nextpdf/compat-legacyestán instalados. - Contar con una base de código TCPDF 6.x existente y una suite de pruebas. Esa suite es la red de seguridad de cada una de las etapas descritas a continuación.
Esta es una guía práctica. Para consultar el comportamiento método por método de una llamada concreta de TCPDF, leer la página de cobertura por método. Para la estrategia completa archivo por archivo con código, leer la página de migración de origen. Ambas están enlazadas en Véase también.
Instalación
Sección titulada «Instalación»Instalar el adaptador junto al núcleo. No quitar todavía la biblioteca real de TCPDF: mantener ambas permite comparar la salida durante la migración.
composer require nextpdf/compat-legacyAntes de cambiar cualquier código, confirmar que el enlace del motor se resuelve (nextpdf/core ^3.0) y que la suite sigue ejecutándose.
Resumen conceptual
Sección titulada «Resumen conceptual»El adaptador es una capa de compatibilidad, no un fork de TCPDF ni un clon idéntico byte a byte. De los aproximadamente 120 métodos públicos de TCPDF 6.x estudiados, unos 94 se corresponden directamente con una operación de NextPDF\Core\Document y se comportan de forma compatible para los parámetros documentados. Una minoría concreta acepta parámetros heredados que el motor no respeta (los ignora en silencio) o no produce ninguna salida en absoluto (sin implementar o no aplicable). La matriz de cobertura canónica y verificada por pruebas vive en el repositorio del paquete, en docs/TCPDF_COVERAGE.md. Cuando esta guía y esa matriz no coincidan, siempre prevalece la matriz.
Dos hechos dan forma a toda la migración:
- Los bytes de salida difieren. El motor es una implementación independiente de PDF 2.0, así que los bytes generados difieren de la salida de TCPDF aunque el resultado visible parezca el mismo. Las pruebas que verifican los bytes exactos del PDF deben volver a basarse en el contenido renderizado o en propiedades estructurales.
- El modo estricto es la herramienta de auditoría. Con el modo estricto desactivado (valor predeterminado), los métodos que no pueden reproducir el comportamiento de TCPDF se degradan en silencio. Con el modo estricto activado, esas llamadas lanzan
TcpdfNotImplementedException, que nombra los parámetros exactos que se ignoran y una pista de migración. Ejecutar el modo estricto en una pasada de auditoría dedicada, nunca en producción.
El adaptador también expone el documento del motor envuelto a través de getDocument(), que devuelve el NextPDF\Core\Document. Esa es la vía de salida: migrar los puntos de llamada a la API moderna de uno en uno hasta que se pueda quitar el adaptador.
Superficie de la API
Sección titulada «Superficie de la API»| Aspecto | Superficie |
|---|---|
| Construcción | new NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4') |
| Alias globales opcionales | NextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases() |
| Activar la auditoría | TCPDF::setStrictMode(true) |
| Excepción de auditoría | NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException |
| Vía de escape a la API moderna | TCPDF::getDocument(): NextPDF\Core\Document |
| Salida | TCPDF::Output(string $name, string $dest) — S, F, E, I, D |
LegacyBootstrap::enableAliases() es idempotente. Registra \TCPDF, \TCPDF_STATIC, \TCPDF_FONTS, \TCPDF_COLORS y \TCPDF_IMAGES solo si esas clases aún no existen. La cobertura completa método por método y el comportamiento del destino de salida están en las páginas de cobertura por método y de inicio rápido, enlazadas en Véase también.
Ejemplo de código — Inicio rápido
Sección titulada «Ejemplo de código — Inicio rápido»Cambiar el import, conservar las llamadas al estilo de TCPDF y producir un PDF.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF('P', 'mm', 'A4');$pdf->SetCreator('Quickstart');$pdf->SetTitle('First Document');$pdf->SetFont('helvetica', '', 12);$pdf->AddPage();$pdf->Cell(0, 10, 'Hello from the NextPDF engine', 1, 1, 'C');
$pdf->Output(__DIR__ . '/quickstart.pdf', 'F');Output($name, 'F') escribe el archivo y devuelve una cadena vacía. A diferencia del TCPDF heredado, el Output() del adaptador no escribe en el búfer de salida activo, así que se puede llamar con seguridad dentro de un worker de cola o de un handler HTTP que controle su propia respuesta.
Cuando no sea posible tocar los puntos de llamada que construyen new \TCPDF(...) contra el espacio de nombres global, activar una vez los alias opcionales en el arranque.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\LegacyBootstrap;
LegacyBootstrap::enableAliases();
// Legacy code now resolves \TCPDF to the adapter:$pdf = new \TCPDF('P', 'mm', 'A4');$pdf->AddPage();$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Legacy call site, modern engine');$pdf->Output(__DIR__ . '/aliased.pdf', 'F');No activar los alias mientras la biblioteca real de TCPDF aún se pueda autocargar. El alias se omite cuando ya existe una clase \TCPDF, así que se podría seguir usando el TCPDF heredado sin darse cuenta. Durante la migración, preferir los imports por archivo.
Ejemplo de código — Producción
Sección titulada «Ejemplo de código — Producción»El paso seguro para la migración es la auditoría en modo estricto. Ejecutar una ruta de producción representativa, o la suite, con el modo estricto activado y recopilar cada TcpdfNotImplementedException. Cada una es un elemento de trabajo: indica el método, los parámetros que se ignoran y una pista.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
function renderInvoice(TCPDF $pdf): void{ // ... your existing rendering code, unchanged ...}
$pdf = new TCPDF('P', 'mm', 'A4');$pdf->setStrictMode(true);
try { renderInvoice($pdf); $pdf->Output(__DIR__ . '/audit.pdf', 'F');} catch (TcpdfNotImplementedException $exception) { // Each message names the method, the ignored parameters, and a hint. fwrite(STDERR, 'MIGRATION GAP: ' . $exception->getMessage() . "\n");}Para cada diferencia, elegir la corrección correcta más barata: descartar un parámetro del que nunca se dependió o volver a expresar la intención mediante la API moderna a través de getDocument(). La vía de escape cubre cualquier cosa que la superficie de TCPDF no pueda expresar.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->AddPage();
// Legacy path stays for the parts that already work:$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here —// for example a clickable image (the legacy Image() link parameter// is one of the silently ignored parameters):$document = $pdf->getDocument();$document->image('logo.png', 10, 30, 40, 0);$document->link(10, 30, 40, 20, 'https://example.com');Ejecutar el modo estricto como un job de CI dedicado y, luego, desactivarlo y desplegar la ruta de código auditada. Mantener un job de CI periódico en modo estricto para detectar regresiones a medida que avance la refactorización.
Casos límite y trampas
Sección titulada «Casos límite y trampas»MultiCell()devuelve1,Write()devuelve0. Son marcadores de compatibilidad, no valores calculados. Ajustar cualquier código que se ramifique en función de esos valores de retorno.Error()lanza en lugar de llamar adie(). El adaptador lanzaRuntimeException. El código que dependía de la terminación del proceso debe capturar la excepción.- Parámetros que se ignoran en silencio. Métodos como
Image(),writeHTML(),SetProtection()yBookmark()aceptan parámetros heredados que se ignoran. Usar el modo estricto para encontrarlos. Para una imagen en la que se pueda hacer clic, dibujar la imagen y, luego, añadirDocument::link()sobre el mismo rectángulo. - Métodos sin implementar.
setSignature(),addEmptySignatureAppearance()yendPage()son no-ops que lanzan en modo estricto;Open()es un no-op seguro que nunca lanza. QuitarendPage()yOpen(). La firma requiere una edición comercial de NextPDF a través de la API moderna de firma. - La versión del PDF es fija.
setPDFVersion()no puede reducir el objetivo a una versión de PDF más antigua; la salida es siempre PDF 2.0.setUserRights()está obsoleto en PDF 2.0 y se ignora con un aviso. - Conflicto de alias. Si algo sigue resolviéndose a la clase real de TCPDF después de quitar
tecnickcom/tcpdf, significa que se aplicó la condición de protección de los alias: importar el adaptador de forma explícita en esos puntos de llamada.
Rendimiento
Sección titulada «Rendimiento»El adaptador delega en el motor; el coste de construir el documento escala con el contenido, no con la capa del adaptador. Como el Output() del adaptador no escribe en el búfer de salida, es seguro dentro de un worker de cola: trasladar la generación pesada al estilo de TCPDF fuera del hilo de la solicitud, igual que con cualquier generación de NextPDF. Volver a basar las pruebas a nivel de bytes en el contenido renderizado es un coste único y produce pruebas que sobreviven a futuras actualizaciones del motor.
Notas de seguridad
Sección titulada «Notas de seguridad»- Cifrado.
SetProtection()ignora los parámetros heredadosmodeypubkeys; el motor usa AES-256 para el handler estándar. Para el cifrado basado en certificados, usar el punto de entrada moderno de cifrado de clave pública que expone el adaptador, no los parámetros heredados. - La firma está controlada. El soporte base de firma es una capacidad de la edición comercial a la que se accede a través de la API moderna de firma con un objeto de valor de certificado; el
setSignature()heredado es un no-op. Esta guía no hace ninguna afirmación sobre los perfiles de firma con validación a largo plazo ni con marca de tiempo para ninguna edición. - Falla de forma explícita durante la auditoría. El modo estricto hace visible la pérdida silenciosa de parámetros para que el código llamador sepa cuándo no se respetó su intención. Tratar las excepciones recopiladas como la lista de trabajo de la migración, no como comportamiento de producción.
- Nunca escribir un bloque
catchvacío. El ejemplo de auditoría capturaTcpdfNotImplementedExceptiony escribe una línea de elemento de trabajo definida.
La postura completa de cifrado y firma durante la migración está en la página de seguridad y operaciones de compat-legacy.
Conformidad
Sección titulada «Conformidad»Esta guía no hace ninguna afirmación normativa de estándares por sí misma. El adaptador escribe salida PDF 2.0 (ISO 32000-2) y no puede reducir la versión objetivo a una versión más antigua. Ese comportamiento y su cláusula correspondiente están fijados en la página de origen de cobertura por método, que también recoge el principio OWASP de fallar de forma explícita que hay detrás del modo estricto y el marco de completitud funcional según ISO/IEC 25023 de la auditoría de cobertura. Esta página del cookbook reformula el uso y remite esas citas a esa página.
Véase también
Sección titulada «Véase también»- Devolver un PDF generado desde un controlador — devolver la salida del adaptador como una respuesta HTTP.
- inicio rápido de compat-legacy — primer documento, destinos de salida y vía de escape.
- Cobertura de métodos de TCPDF — auditoría método por método y matriz canónica.
- Migrar de TCPDF 6.x a NextPDF — la estrategia completa de seis etapas con código.