Ir al contenido

Migración de TCPDF 6.x a NextPDF

La migración sigue un orden claro: pasar primero al motor de NextPDF con el cambio más pequeño posible; validar lo que ya funciona; auditar lo que no; corregirlo punto de llamada por punto de llamada; y, después, eliminar el adaptador. La capa de compatibilidad sirve de apoyo en los pasos dos a cuatro; no es el destino.

Esta página explica la estrategia. Para conocer el comportamiento exacto de cualquier método concreto, consultar /integrations/tcpdf-compat/method-coverage/ junto con la matriz canónica del repositorio docs/TCPDF_COVERAGE.md.

TCPDF 6.x codebase

Swap dependency: install compat-legacy

Run existing suite unchanged

Strict-mode audit: enumerate behavioral gaps

Fix call sites: drop ignored params or move to modern API

Re-baseline byte-level test assertions

Remove the TCPDF dependency

Incrementally retire the adapter onto Document

Diagram

Cada etapa mantiene la aplicación en un estado listo para entrega. No hace falta una conmutación completa de una sola vez.

Instalar nextpdf/compat-legacy (consulte /integrations/tcpdf-compat/install/). No eliminar todavía tecnickcom/tcpdf: mantener ambos permite ejecutar una comparación.

Definir cómo deben resolver la clase los puntos de llamada heredados:

  • Preferido: cambiar use/require a use NextPDF\Compat\Tcpdf\TCPDF; por archivo. Es explícito y localizable con grep.
  • Cuando todavía no sea posible tocar los puntos de llamada: habilitar los alias globales opcionales una vez en el arranque con LegacyBootstrap::enableAliases() (consulte /integrations/tcpdf-compat/boot-and-discovery/). Esto resuelve \TCPDF y las cuatro clases auxiliares al adaptador.

Las dos estrategias son mutuamente excluyentes en la práctica. Si la biblioteca TCPDF real sigue siendo autocargable y se habilitan los alias globales, el alias se omite cuando ya existe una clase \TCPDF. En ese caso, se podría seguir usando TCPDF heredado de forma silenciosa. Durante la Etapa 1, conviene priorizar las importaciones por archivo para saber exactamente qué clase usa cada punto de llamada. Consulte /integrations/tcpdf-compat/troubleshooting/.

Etapa 2 — Ejecutar el conjunto de pruebas existente sin cambios

Sección titulada «Etapa 2 — Ejecutar el conjunto de pruebas existente sin cambios»

Ejecutar todo el conjunto de pruebas contra el adaptador sin ningún otro cambio de código. La mayoría de los métodos delegados (94 de los ~120 examinados) se comportan de forma compatible. Esperar dos tipos de fallo previsibles:

  1. Aserciones a nivel de byte. Las pruebas que comparan bytes exactos del PDF fallarán porque el motor es una implementación independiente. Esto es lo esperado, no un defecto. Aplazar esas aserciones hasta la Etapa 4.
  2. Ramas según valor de retorno. Unos pocos métodos devuelven marcadores de posición de compatibilidad en lugar de valores calculados: en particular, MultiCell() devuelve 1, y Write() devuelve 0. El código que toma ramas según esos valores de retorno necesita ajustes.

Catalogar cada fallo. Clasificar cada uno como byte-baseline, valor de retorno o brecha de comportamiento real.

Esta es la etapa que hace segura la migración. Ejecutar el conjunto de pruebas (o una ruta de producción representativa) con el modo estricto habilitado:

examples/migration-audit.php
<?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 $e) {
// Each message names the method, the ignored parameters, and a hint.
fwrite(STDERR, 'MIGRATION GAP: ' . $e->getMessage() . "\n");
}

Cada TcpdfNotImplementedException es un elemento de trabajo. El mensaje contiene el método, la lista exacta de parámetros ignorados y una pista de migración. El conjunto de métodos que la lanzan está enumerado y verificado con pruebas en tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php. La justificación de cada uno está en docs/TCPDF_COVERAGE.md.

Ejecutar el modo estricto como un trabajo de CI dedicado, no en producción. El objetivo es exponer las brechas, no provocar excepciones en producción.

Para cada brecha, elegir la corrección correcta de menor coste:

Patrón de brechaCorrección
El parámetro ignorado no importa (e.g. un $align de TCPDF del que nunca dependió)Eliminar el parámetro. La llamada se vuelve exactamente compatible.
El parámetro ignorado importaba (e.g. un enlace de Image() en el que se puede hacer clic)Reformularlo mediante la API moderna. Dibujar la imagen y, después, añadir Document::link() sobre el rectángulo.
El método no está implementado (setSignature(), endPage())endPage() / Open(): elimine la llamada. Firma: consulte /integrations/tcpdf-compat/security-and-operations/: requiere una edición comercial.
Método no aplicable (setPDFVersion(), setUserRights())Elimínelo. La salida siempre es PDF 2.0; los derechos de usuario están obsoletos en PDF 2.0.
Rama según valor de retornoCalcular el valor directamente, o mover esa lógica a la API moderna.

Usar la vía de escape para cualquier cosa que la superficie de TCPDF no pueda expresar:

examples/migration-escape-hatch.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
// Legacy path stays as-is for the parts that work:
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here:
$document = $pdf->getDocument();
$document->image('logo.png', 10, 30, 40, 0);
$document->link(10, 30, 40, 20, 'https://example.com');

Volver a fijar la referencia de las pruebas a nivel de byte

Sección titulada «Volver a fijar la referencia de las pruebas a nivel de byte»

Sustituir las aserciones de bytes exactos por aserciones sobre lo que realmente importa:

  • La salida comienza con %PDF y se analiza correctamente (nivel de humo).
  • El contenido de texto representado está presente (extraer el texto y hacer aserciones sobre él).
  • Las propiedades estructurales (número de páginas, tamaño de página, presencia de un esquema) coinciden.

Es un coste único y produce pruebas que resisten futuras actualizaciones del motor.

Etapa 5 — Eliminar la dependencia de TCPDF

Sección titulada «Etapa 5 — Eliminar la dependencia de TCPDF»

Una vez que la auditoría en modo estricto pasa con el modo estricto desactivado en producción y el conjunto de pruebas está en verde con las aserciones ajustadas a las nuevas referencias, eliminar tecnickcom/tcpdf:

Ventana de terminal
composer remove tecnickcom/tcpdf

Volver a ejecutar el conjunto de pruebas. Si algo todavía se resuelve a la clase TCPDF real, se aplica la advertencia sobre alias de la Etapa 1: corregir los puntos de llamada restantes para que importen el adaptador de forma explícita.

El adaptador es una ayuda para la migración, no una capa permanente. Con TCPDF eliminado y el motor validado, retirar el adaptador de forma incremental:

  1. En cada módulo, sustituir new TCPDF(...) por la construcción moderna de NextPDF\Core\Document.
  2. Sustituir las llamadas a métodos de TCPDF por sus equivalentes modernos (las llamadas a getDocument() que ya se añadieron en la Etapa 4 sirven de plantilla).
  3. Cuando un módulo ya no haga referencia al adaptador, eliminar sus importaciones de compatibilidad.
  4. Cuando ningún módulo haga referencia al adaptador, eliminar nextpdf/compat-legacy de composer.json.

Entonces la base quedará sobre la API moderna de PDF 2.0 sin capa de compatibilidad.

  • nextpdf/compat-legacy instalado; enlace con el motor verificado.
  • Los puntos de llamada importan el adaptador explícitamente (o los alias están habilitados con el TCPDF real eliminado de la ruta de autocarga).
  • Ejecución completa del conjunto de pruebas contra el adaptador; fallos clasificados.
  • Trabajo de CI en modo estricto añadido; cada brecha catalogada.
  • Cada brecha corregida (eliminar parámetro / API moderna / eliminar llamada).
  • Aserciones a nivel de byte ajustadas a nuevas referencias de content/structure.
  • tecnickcom/tcpdf eliminado; conjunto de pruebas en verde.
  • Adaptador retirado módulo a módulo; dependencia eliminada.
  • /integrations/tcpdf-compat/method-coverage/: comportamiento por método y guía de sustitución
  • docs/TCPDF_COVERAGE.md: matriz canónica verificada con pruebas
  • /integrations/tcpdf-compat/configuration/: trasladar la configuración fuera de las constantes globales
  • /integrations/tcpdf-compat/security-and-operations/: cifrado y firma durante la migración
  • /integrations/tcpdf-compat/troubleshooting/: el conflicto alias/real-TCPDF y otras trampas