Salta ai contenuti

Migrare un codebase TCPDF 6.x a NextPDF

Il pacchetto nextpdf/compat-legacy espone i nomi dei metodi pubblici, l’ordine dei parametri e i valori predefiniti di TCPDF 6.x sul motore core di NextPDF tramite l’adattatore NextPDF\Compat\Tcpdf\TCPDF. Procedere con la migrazione in questo ordine: passare prima al nuovo motore con la modifica minima, verificare ciò che già funziona, attivare la modalità strict per elencare ciò che non funziona, correggere i punti di chiamata uno alla volta e infine dismettere l’adattatore passando all’API moderna. L’adattatore è il supporto temporaneo della migrazione, non la destinazione.

Prerequisiti iniziali:

  • Il core di NextPDF e nextpdf/compat-legacy sono installati.
  • Si dispone di un codebase TCPDF 6.x esistente con una suite di test. La suite costituisce la rete di sicurezza per ogni fase descritta di seguito.

Questa è una guida pratica. Per il comportamento, metodo per metodo, di una specifica chiamata TCPDF, consultare la pagina sulla copertura dei metodi. Per la strategia completa file per file con codice, consultare la pagina di migrazione upstream. Entrambe sono collegate in Vedere anche.

Installare l’adattatore insieme al core. Non rimuovere ancora la libreria TCPDF reale: mantenere entrambi consente di confrontare l’output durante la migrazione.

Terminal window
composer require nextpdf/compat-legacy

Prima di modificare qualsiasi codice, verificare che la dipendenza del motore si risolva (nextpdf/core ^3.0) e che la suite continui a essere eseguita.

L’adattatore è un livello di compatibilità, non un fork di TCPDF né un clone identico byte per byte. Dei circa 120 metodi pubblici di TCPDF 6.x esaminati, circa 94 vengono mappati direttamente su un’operazione di NextPDF\Core\Document e si comportano in modo compatibile per i parametri documentati. Una minoranza circoscritta accetta parametri legacy che il motore non onora (ignorati silenziosamente) oppure non produce alcun output (non implementati o non applicabili). La matrice di copertura autorevole e verificata dai test si trova nel repository del pacchetto in docs/TCPDF_COVERAGE.md. In caso di discrepanza tra questa guida e tale matrice, prevale la matrice.

Due fatti caratterizzano l’intera migrazione:

  • I byte di output differiscono. Il motore è un’implementazione PDF 2.0 indipendente, quindi i byte prodotti differiscono dall’output di TCPDF anche quando il risultato visibile appare identico. I test basati sui byte PDF esatti devono essere ricalibrati sul contenuto renderizzato o su proprietà strutturali.
  • La modalità strict è lo strumento di audit. Con la modalità strict disattivata (impostazione predefinita), i metodi che non possono riprodurre il comportamento di TCPDF degradano silenziosamente. Con la modalità strict attivata, tali chiamate generano TcpdfNotImplementedException, che indica esattamente i parametri ignorati e un suggerimento per la migrazione. Usare la modalità strict in un passaggio di audit dedicato, mai in produzione.

L’adattatore espone inoltre il documento del motore sottostante tramite getDocument(), che restituisce il NextPDF\Core\Document. Questa è la via d’uscita: migrare i punti di chiamata sull’API moderna uno alla volta finché non è possibile rimuovere l’adattatore.

AspettoSuperficie
Costruzionenew NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4')
Alias globali opt-inNextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases()
Abilitare l’auditTCPDF::setStrictMode(true)
Eccezione di auditNextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException
Via di fuga verso l’API modernaTCPDF::getDocument(): NextPDF\Core\Document
OutputTCPDF::Output(string $name, string $dest)S, F, E, I, D

LegacyBootstrap::enableAliases() è idempotente. Registra \TCPDF, \TCPDF_STATIC, \TCPDF_FONTS, \TCPDF_COLORS e \TCPDF_IMAGES solo quando tali classi non esistono già. La copertura completa per singolo metodo e il comportamento delle destinazioni di output sono documentati nelle pagine sulla copertura dei metodi e di avvio rapido collegate in Vedere anche.

Modificare l’import, mantenere le chiamate in stile TCPDF e produrre un PDF.

quickstart-first.php
<?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') scrive il file e restituisce una stringa vuota. A differenza di TCPDF legacy, l’Output() dell’adattatore non scrive nel buffer di output attivo, quindi è possibile chiamarlo in sicurezza all’interno di un worker di coda o di un handler HTTP che gestisce direttamente la propria risposta.

Quando non si può intervenire sui punti di chiamata che costruiscono new \TCPDF(...) nello spazio dei nomi globale, abilitare gli alias opt-in una volta all’avvio.

quickstart-alias.php
<?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');

Non abilitare gli alias mentre la libreria TCPDF reale è ancora caricabile tramite autoload. La creazione dell’alias viene saltata quando una classe \TCPDF esiste già, quindi si potrebbe continuare a usare TCPDF legacy senza accorgersene. Durante la migrazione, preferire gli import file per file.

Il passaggio sicuro della migrazione è l’audit in modalità strict. Eseguire, con la modalità strict attivata, un percorso di produzione rappresentativo o la suite e raccogliere ogni TcpdfNotImplementedException. Ciascuna diventa un elemento di lavoro: indica il metodo, i parametri ignorati e un suggerimento.

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

Per ogni differenza, scegliere la correzione corretta con il minor intervento: rimuovere un parametro su cui non si è mai fatto affidamento oppure riformulare l’intento tramite l’API moderna usando getDocument(). La via di fuga copre tutto ciò che la superficie di TCPDF non riesce a esprimere.

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 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');

Eseguire la modalità strict in un job CI dedicato, quindi disattivarla e distribuire il percorso di codice sottoposto ad audit. Mantenere un job CI periodico in modalità strict per individuare le regressioni durante il refactoring progressivo.

  • MultiCell() restituisce 1, Write() restituisce 0. Si tratta di segnaposto di compatibilità, non di valori calcolati. Adeguare qualsiasi codice che prende rami diversi in base a tali valori di ritorno.
  • Error() genera un’eccezione invece di chiamare die(). L’adattatore genera RuntimeException. Il codice che faceva affidamento sulla terminazione del processo deve intercettare l’eccezione.
  • Parametri ignorati silenziosamente. Metodi come Image(), writeHTML(), SetProtection() e Bookmark() accettano parametri legacy che vengono ignorati. Usare la modalità strict per individuarli. Per un’immagine cliccabile, disegnare l’immagine e quindi aggiungere Document::link() sullo stesso rettangolo.
  • Metodi non implementati. setSignature(), addEmptySignatureAppearance() e endPage() sono no-op che generano un’eccezione in modalità strict; Open() è un no-op sicuro che non genera mai eccezioni. Rimuovere endPage() e Open(). La firma richiede un’edizione commerciale di NextPDF tramite l’API di firma moderna.
  • La versione PDF è fissa. setPDFVersion() non può puntare a una versione PDF più datata; l’output è sempre PDF 2.0. setUserRights() è deprecato in PDF 2.0 e viene ignorato con un avviso.
  • Conflitto di alias. Se qualche riferimento si risolve ancora sulla classe TCPDF reale dopo aver rimosso tecnickcom/tcpdf, vale l’avvertenza sugli alias: importare l’adattatore esplicitamente in quei punti di chiamata.

L’adattatore delega al motore; il costo di costruzione del documento dipende dal contenuto, non dallo strato dell’adattatore. Poiché l’Output() dell’adattatore non scrive nel buffer di output, è sicuro all’interno di un worker di coda: spostare la generazione pesante in stile TCPDF fuori dal thread della richiesta, come si farebbe per qualsiasi generazione NextPDF. Ricalibrare i test a livello di byte sul contenuto renderizzato è un costo una tantum e produce test che restano validi con i futuri aggiornamenti del motore.

  • Cifratura. SetProtection() ignora i parametri legacy mode e pubkeys; il motore usa AES-256 per l’handler standard. Per la cifratura basata su certificato, usare il punto di ingresso moderno per la cifratura a chiave pubblica esposto sull’adattatore, non i parametri legacy.
  • La firma è soggetta a restrizioni. Il supporto della firma baseline è una funzionalità dell’edizione commerciale, raggiungibile tramite l’API di firma moderna con un value object certificato; il setSignature() legacy è un no-op. Questa guida non fa alcuna affermazione su profili di firma con validazione a lungo termine o con marca temporale per qualsiasi edizione.
  • Fallire in modo esplicito durante l’audit. La modalità strict rende visibile la perdita silenziosa di parametri, così che un chiamante sappia quando il suo intento non è stato onorato. Considerare le eccezioni raccolte come l’elenco delle attività di migrazione, non come comportamento di produzione.
  • Non scrivere mai un blocco catch vuoto. L’esempio di audit intercetta TcpdfNotImplementedException e scrive una riga di elemento di lavoro definita.

L’impostazione completa di cifratura e firma durante la migrazione è nella pagina sulla sicurezza e le operazioni di compat-legacy.

Questa guida non avanza alcuna affermazione normativa di standard propria. L’adattatore scrive output PDF 2.0 (ISO 32000-2) e non può puntare a una versione più datata. Tale comportamento e la relativa clausola sono fissati nella pagina sulla copertura dei metodi upstream, che registra anche il principio OWASP del fallimento esplicito alla base della modalità strict e l’inquadramento di completezza funzionale ISO/IEC 25023 dell’audit di copertura. Questa pagina del cookbook ribadisce l’utilizzo e rimanda tali citazioni a quella pagina.