Zum Inhalt springen

Contracts / Dokument

Die Document-Domäne enthält die Contracts, gegen die Sie PDFs entwickeln: PdfDocumentInterface für Inhalte, DocumentFactoryInterface für Worker-sichere Erstellung, die Font- und Image-Registry-Contracts sowie die drei Ausgabe- und Layout-Enums. Alle sind seit 1.0.0 oder 1.7.0 stable.

Terminal-Fenster
composer require nextpdf/core:^3

Das PdfDocumentInterface ist die primäre API-Oberfläche. Es definiert Seitenverwaltung, Font-Auswahl, Text-Layout für Cell und Multi-Cell, HTML-Rendering, Bildeinbettung und die finale Ausgabe. Jede Methode liefert static, daher lassen sich Aufrufe verketten. Document::createStandalone() liefert eine konkrete Instanz, die das Interface erfüllt. Typisieren Sie Ihre eigenen Services gegen das Interface. Dadurch bleiben die Engine-Interna austauschbar.

Für die Dokumenterstellung gibt es zwei Pfade. In einem klassischen PHP-FPM-Request baut createStandalone() ein in sich geschlossenes Dokument mit privaten Registries. Für einen lang laufenden Worker ist der andere Pfad vorgesehen. Dazu gehören RoadRunner, Swoole und Laravel Octane. Dort liefert DocumentFactoryInterface::create() ein frisches, wegwerfbares Document. Das Dokument liest aus den Registries, die so lange leben wie der Prozess selbst, mutiert sie aber nie. Die Factory hält die Singletons FontRegistryInterface und ImageRegistryInterface. Jedes Dokument bekommt seinen eigenen Rendering-Kontext und Writer. Das sorgt für Fehlerisolation. Ein Dokument kann nicht den gemeinsam genutzten Zustand beschädigen, von dem ein anderes Dokument abhängt.

Die Registry-Contracts sind der Grund, weshalb ein Worker schnell bleibt. FontRegistryInterface parst eine Font-Datei genau einmal. Es speichert die geparsten Metadaten für die Lebensdauer des Prozesses im Cache. Es lässt sich nach dem Warmup sperren, sodass Produktionstraffic es nicht mutieren kann. ImageRegistryInterface speichert die dekodierten Binärdaten von Bildern mit einer begrenzten Least-Recently-Used-Policy im Cache. Bild-Metadaten bleiben im Speicher, auch nachdem die Binärdaten verdrängt wurden. Beide stellen memoryUsage() für die Kapazitätsplanung bereit. ImageRegistryInterface erweitert ResettableService. Dieser Contract verdrängt Daten aus dem Cache, ohne die strukturellen Metadaten zu zerstören. Ein Worker kann bei Speicherdruck Image-Caches verwerfen und weiter ausliefern.

Drei Enums runden die Domäne ab. OutputDestination wählt Inline-Anzeige, erzwungenen Download, Schreiben ins Dateisystem oder die Rückgabe als rohen String. Orientation wählt Hochformat oder Querformat. Alignment wählt linksbündigen, zentrierten, rechtsbündigen oder Blocksatz-Text. Jedes Enum verwendet für seine Cases den alten TCPDF-Code als Enum-Wert. Die compat-tcpdf-Brücke kann diese Werte deshalb sauber abbilden. Das Versprechen zur Abwärtskompatibilität für diese Enums ist additiv. Kein Case wird entfernt. Neue Cases können in einem Minor-Release hinzukommen.

TypArtWichtige MitgliederStabilitätSeit
PdfDocumentInterfaceinterfaceaddPage(), setMargins(), setFont(), cell(), multiCell(), writeHtml(), image(), output(), save()stable1.0.0
DocumentFactoryInterfaceinterfacecreate(?Config): Documentstable1.7.0
ResettableServiceinterfacereset(): voidstable1.7.0
FontRegistryInterfaceinterfaceregister(), get(), warmup(), lock(), isLocked(), registerFromBinary(), memoryUsage()stable1.7.0
ImageRegistryInterfaceinterfaceload(), loadFromString(), getMetadata(), memoryUsage() (erweitert ResettableService)stable2.0.0
OutputDestinationenum (string)Inline, Download, File, Stringstable1.0.0
Orientationenum (string)Portrait, Landscapestable1.0.0
Alignmentenum (string)Left, Center, Right, Justifystable1.0.0

FontRegistryInterface und ImageRegistryInterface sind vollständig auf der Typografie-Seite dokumentiert; die Document-Seite behandelt ihre Rolle im Erstellungs-Lebenszyklus.

examples/01-hello-world.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Hello World');
$doc->addPage();
$doc->setFont('helvetica', '', 24);
$doc->cell(0, 15, 'Hello, NextPDF!', newLine: true);
$doc->setFont('helvetica', '', 12);
$doc->cell(0, 10, 'This is a minimal PDF generated with NextPDF.', newLine: true);
$doc->save(__DIR__ . '/output/01-hello-world.pdf');
examples/02-pdf-factory.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\PdfFactory;
use NextPDF\ValueObjects\{Margin, PageSize};
$factory = PdfFactory::new()
->withPageSize(PageSize::A4())
->withMargins(new Margin(15.0, 15.0, 15.0, 15.0))
->withCompress(true)
->withLang('en');
// The same configured factory creates independent documents.
$doc = $factory->create();
$doc->setTitle('PdfFactory Example');
$doc->setAuthor('NextPDF');
$doc->addPage();
$doc->setFont('helvetica', '', 16);
$doc->cell(0, 12, 'Created via PdfFactory', newLine: true);
$doc2 = $factory->create();
$doc2->addPage();
$doc2->setFont('helvetica', '', 12);
$doc2->cell(0, 10, 'Second document from the same factory.');
$doc->save(__DIR__ . '/output/02-pdf-factory.pdf');

PdfFactory ist der unveränderliche Builder; jedes with*() liefert eine neue Instanz. Intern setzt sie ein DocumentFactoryInterface zusammen, sodass das Worker-Registry-Modell aus dem Überblick ohne zusätzliche Verdrahtung greift.

  • createStandalone() baut private Registries. In einer Worker-Schleife wird dadurch jeder Font bei jedem Request neu geparst. Verwenden Sie stattdessen DocumentFactoryInterface mit gemeinsam genutzten Registries.
  • Ein Document ist von Grund auf wegwerfbar. Die Wiederverwendung einer Instanz über logische Dokumente hinweg lässt Zustand durchsickern. Rufen Sie create() pro Dokument auf und lassen Sie es von der Garbage Collection zurückfordern.
  • FontRegistryInterface::lock() bewirkt, dass register(), addFontDirectory() und warmup() eine LogicException werfen. Sperren Sie nach dem Warmup, niemals während der Request-Verarbeitung.
  • OutputDestination::File schreibt in das Dateisystem des Servers und liefert die rohen Bytes zurück. save() ist der explizite Dateipfad. Verwenden Sie die beiden nicht gemischt für dasselbe Dokument.
  • cell() akzeptiert für das Border-Argument aus TCPDF-Kompatibilität bool|string; ein leerer String ist nicht dasselbe wie false. Übergeben Sie den typisierten Wert, den Sie meinen.

Die Font- und Image-Registries machen die Document-Domäne zu einem speicherbegrenzten System statt zu einem pro Request neu aufgebauten System. Das Font-Parsing beim ersten Request dominiert. Das performance_budget beträgt 1500 ms Wall-Time und 64 MB Peak über drei Dokumente im Worker-Beispiel. Fast das gesamte Budget entfällt auf das erste Font-Parsing. Nach dem Warmup ist die den Contracts zurechenbare Arbeit pro Dokument O(1) — ein Registry-Lookup und eine Kontext-Allokation. memoryUsage() auf einer der beiden Registries liefert einen MemoryReport für die Kapazitätsplanung in Echtzeit. ResettableService::reset() begrenzt den Speicher-Peak bei dauerhafter Last.

Die Document-Contracts tragen keine kryptografische Oberfläche, aber zwei operative Risiken bleiben relevant. Erstens akzeptiert image() einen Pfad oder eine URL. Beschränken Sie in Szenarien mit nicht vertrauenswürdiger Eingabe das Remote-Fetching über ExternalResourcePolicyInterface (siehe die Security-Policy-Seite), statt nutzergesteuerte URLs direkt zu übergeben. Zweitens ist writeHtml() der Einstiegspunkt für die HTML-Pipeline. Nicht vertrauenswürdiges Markup muss vor dem Rendering eine HtmlSecurityPolicyInterface durchlaufen. Die Document-Schicht selbst bereinigt nicht. Das ist die Aufgabe der Security-Policy-Domäne, und es ist ein Contract, sodass Sie eine strengere Policy bereitstellen können, ohne zu forken.

Die Document-Contracts implementieren die PDF 2.0-Dokumentstruktur, wie sie in ISO 32000-2 definiert ist. Output-, Seiten- und Font-Handling erzeugen indirekte Objekte und einen Cross-Reference-Stream gemäß ISO 32000-2 §7. Inhalte werden über die Writer-Schicht gemäß dem Engine-Layer-Contract (ADR-010) ausgegeben. Auf dieser Seite wird über die strukturelle Konformität hinaus kein klausel-genauer Anspruch erhoben. PDF/A- und PDF/UA-Konformität sind auf den Seiten zu Extraktion und Barrierefreiheit dokumentiert, die die normativen Tabellen tragen.