Zum Inhalt springen

Migration von TCPDF 6.x zu NextPDF

Die Migration folgt einer klaren Reihenfolge. Stellen Sie zunächst mit der kleinstmöglichen Änderung auf die NextPDF-Engine um. Weisen Sie nach, was bereits funktioniert. Prüfen Sie, was noch nicht funktioniert. Beheben Sie die Probleme Aufrufstelle für Aufrufstelle. Entfernen Sie anschließend den Adapter. Die Kompatibilitätsschicht unterstützt die Schritte zwei bis vier; sie ist nicht das Ziel.

Diese Seite beschreibt die Strategie. Das genaue Verhalten einzelner Methoden finden Sie unter /integrations/tcpdf-compat/method-coverage/ und in der maßgeblichen Matrix im Repository 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

In jeder Stufe bleibt die Anwendung auslieferbar. Eine vollständige Umstellung auf einen Schlag ist nie erforderlich.

Installieren Sie nextpdf/compat-legacy (siehe /integrations/tcpdf-compat/install/). Entfernen Sie tecnickcom/tcpdf noch nicht — wenn Sie beide behalten, können Sie einen Vergleich durchführen.

Wählen Sie, wie Legacy-Aufrufstellen die Klasse auflösen sollen:

  • Bevorzugt: Ändern Sie use/require pro Datei zu use NextPDF\Compat\Tcpdf\TCPDF;. So bleibt es explizit und per grep auffindbar.
  • Wenn Sie die Aufrufstellen noch nicht anfassen können: Aktivieren Sie die optionalen globalen Aliase einmalig beim Bootvorgang mit LegacyBootstrap::enableAliases() (siehe /integrations/tcpdf-compat/boot-and-discovery/). Dadurch werden \TCPDF und die vier Hilfsklassen auf den Adapter aufgelöst.

Die beiden Strategien schließen sich in der Praxis gegenseitig aus. Wenn die echte TCPDF-Bibliothek weiterhin über den Autoload ladbar ist und Sie globale Aliase aktivieren, wird der Alias übersprungen, wenn bereits eine \TCPDF-Klasse existiert. Möglicherweise verwenden Sie dann stillschweigend weiterhin das Legacy-TCPDF. Bevorzugen Sie in Stufe 1 Importe pro Datei, damit Sie genau wissen, welche Klasse jede Aufrufstelle verwendet. Siehe /integrations/tcpdf-compat/troubleshooting/.

Stufe 2 — Die vorhandene Suite unverändert ausführen

Abschnitt betitelt „Stufe 2 — Die vorhandene Suite unverändert ausführen“

Führen Sie Ihre vollständige Test-Suite gegen den Adapter aus, ohne weitere Codeänderungen vorzunehmen. Die meisten delegierten Methoden (94 der ~120 untersuchten) verhalten sich kompatibel. Rechnen Sie mit zwei vorhersehbaren Fehlerarten:

  1. Assertions auf Byte-Ebene. Tests, die exakte PDF-Bytes vergleichen, schlagen fehl, weil die Engine eine eigenständige Implementierung ist. Das ist erwartet, kein Fehler. Behandeln Sie diese erst in Stufe 4.
  2. Verzweigungen anhand von Rückgabewerten. Einige Methoden geben Kompatibilitätsplatzhalter anstelle berechneter Werte zurück — insbesondere MultiCell() gibt 1 zurück und Write() gibt 0 zurück. Code, der anhand dieser Rückgabewerte verzweigt, muss angepasst werden.

Katalogisieren Sie jeden Fehler. Klassifizieren Sie ihn als Byte-Baseline, Rückgabewert oder echte Verhaltenslücke.

Diese Stufe macht die Migration sicher. Führen Sie die Suite (oder einen repräsentativen Produktionspfad) mit aktiviertem Strict-Modus aus:

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");
}

Jede TcpdfNotImplementedException ist ein Arbeitspaket. Die Meldung enthält die Methode, die genaue Liste der ignorierten Parameter und einen Migrationshinweis. Die Methoden, die eine Ausnahme werfen, sind in tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php aufgezählt und per Test abgesichert. Die Begründung dafür findet sich jeweils in docs/TCPDF_COVERAGE.md.

Führen Sie den Strict-Modus als dedizierten CI-Job aus, nicht in der Produktion. Ziel ist, die Lücken sichtbar zu machen, nicht in der Produktion Ausnahmen auszulösen.

Wählen Sie für jede Lücke die kostengünstigste korrekte Lösung:

LückenmusterLösung
Ignorierter Parameter ist unerheblich (z. B. ein TCPDF-$align, auf den Sie sich nie verlassen haben)Entfernen Sie den Parameter. Der Aufruf ist dann exakt kompatibel.
Ignorierter Parameter war relevant (z. B. ein anklickbarer Image()-Link)Bilden Sie ihn über die moderne API ab. Zeichnen Sie das Bild und fügen Sie dann Document::link() über dem Rechteck hinzu.
Methode ist nicht implementiert (setSignature(), endPage())endPage() / Open(): Entfernen Sie den Aufruf. Signieren: siehe /integrations/tcpdf-compat/security-and-operations/ — erfordert eine kommerzielle Edition.
Nicht zutreffende Methode (setPDFVersion(), setUserRights())Entfernen. Die Ausgabe ist immer PDF 2.0; user-rights sind in PDF 2.0 veraltet.
Verzweigung anhand eines RückgabewertsBerechnen Sie den Wert selbst oder verlagern Sie diese Logik in die moderne API.

Verwenden Sie die Ausweichlösung für alles, was sich über die TCPDF-Oberfläche nicht ausdrücken lässt:

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

Ersetzen Sie Assertions auf exakte Bytes durch Assertions auf das, was tatsächlich zählt:

  • Die Ausgabe beginnt mit %PDF und lässt sich parsen (Smoke-Level).
  • Der gerenderte Textinhalt ist vorhanden (extrahieren Sie den Text und prüfen Sie ihn mit einer Assertion).
  • Strukturelle Eigenschaften (Seitenzahl, Seitengröße, Vorhandensein einer Gliederung) stimmen überein.

Dieser einmalige Aufwand liefert Tests, die künftige Engine-Upgrades überstehen.

Sobald das Audit im Strict-Modus erfolgreich ist, der Strict-Modus in der Produktion aus ist und die Suite mit den neu als Baseline festgelegten Assertions grün ist, entfernen Sie tecnickcom/tcpdf:

Terminal-Fenster
composer remove tecnickcom/tcpdf

Führen Sie die Suite erneut aus. Wenn noch etwas auf die echte TCPDF-Klasse aufgelöst wird, hat sich der Alias-Vorbehalt aus Stufe 1 bestätigt — passen Sie die verbleibenden Aufrufstellen so an, dass sie den Adapter explizit importieren.

Der Adapter ist eine Migrationshilfe, keine dauerhafte Schicht. Nachdem TCPDF entfernt und die Engine erprobt ist, nehmen Sie den Adapter schrittweise außer Betrieb:

  1. Ersetzen Sie in jedem Modul new TCPDF(...) durch die moderne Konstruktion mit NextPDF\Core\Document.
  2. Ersetzen Sie TCPDF-Methodenaufrufe durch ihre modernen Entsprechungen (die getDocument()-Aufrufe, die Sie bereits in Stufe 4 hinzugefügt haben, dienen als Vorlage).
  3. Wenn ein Modul den Adapter nicht mehr referenziert, löschen Sie seine Kompatibilitätsimporte.
  4. Wenn kein Modul den Adapter referenziert, entfernen Sie nextpdf/compat-legacy aus composer.json.

Sie verwenden dann die moderne PDF-2.0-API ohne Kompatibilitätsschicht.

  • nextpdf/compat-legacy installiert; Engine-Anbindung verifiziert.
  • Aufrufstellen importieren den Adapter explizit (oder Aliase sind aktiviert, wobei das echte TCPDF aus dem Autoload-Pfad entfernt ist).
  • Vollständige Suite gegen den Adapter ausgeführt; Fehler klassifiziert.
  • CI-Job für den Strict-Modus hinzugefügt; jede Lücke katalogisiert.
  • Jede Lücke behoben (Parameter entfernt / moderne API genutzt / Aufruf entfernt).
  • Byte-Level-Assertions auf content/structure als neue Baseline festgelegt.
  • tecnickcom/tcpdf entfernt; Suite grün.
  • Adapter Modul für Modul außer Betrieb genommen; Abhängigkeit entfernt.
  • /integrations/tcpdf-compat/method-coverage/ — Verhalten pro Methode und Hinweise zum Ersatz
  • docs/TCPDF_COVERAGE.md — maßgebliche, per Test verifizierte Matrix
  • /integrations/tcpdf-compat/configuration/ — globale Konstanten über die Konfiguration auflösen
  • /integrations/tcpdf-compat/security-and-operations/ — Verschlüsselung und Signieren während der Migration
  • /integrations/tcpdf-compat/troubleshooting/ — der alias/real-TCPDF-Konflikt und weitere Fallstricke