Zum Inhalt springen
getnextpdf.com

Stabilität: Experimentell

Retained-Page-Buffer-Erweiterung

Per Opt-in aktivierbare Erweiterung, keine Legacy-Parität. Dieses Konstruktor-Argument existiert in Legacy-TCPDF 6.x nicht. Es ist eine NextPDF-Erweiterung. Es ist standardmäßig aus; ist es aus, verhält sich der Adapter genau wie zuvor, und setPage() auf eine frühere Seite löst UnsupportedFeatureException aus wie eh und je.

Legacy-TCPDF erlaubt Ihnen, setPage() aufzurufen, um zu einer früheren Seite zurückzuwechseln und weiterzuzeichnen. Der streamende Adapter kann das standardmäßig nicht — sobald eine Seite geflusht ist, ist sie weg — sodass setPage() oder lastPage() auf eine frühere Seite UnsupportedFeatureException auslöst. Der Retained Page Buffer ist das Opt-in, das dieses Nachfüllverhalten auf Basis des NextPDF-Core-Retained-Page-Buffers wiederherstellt.

Übergeben Sie retainedPageBuffer: true an den Adapter-Konstruktor. Bei aktivem Puffer delegiert ein setPage()- oder lastPage()-Aufruf, der auf eine frühere Seite zielt, an die Core-Nachfüllung, statt auszulösen:

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF(retainedPageBuffer: true);
$pdf->AddPage(); // page 1 — reserve room for a running total
$pdf->Cell(0, 10, 'Invoice', ln: 1);
$pdf->AddPage(); // page 2 — line items
$pdf->Cell(0, 10, 'Line items…', ln: 1);
$total = 1234.56; // known only after the items are laid out
$pdf->setPage(1); // delegates to the core back-fill
$pdf->Cell(0, 10, 'Grand total: ' . number_format($total, 2), ln: 1);
$pdf->lastPage(); // return to the final page
$pdf->Output(__DIR__ . '/invoice.pdf', 'F');

Produktionsbeispiel: eine reservierte Deckseite nachfüllen

Abschnitt betitelt „Produktionsbeispiel: eine reservierte Deckseite nachfüllen“

Ein häufiger Grund, zum Puffer zu greifen, ist eine Deck- oder Übersichtsseite, deren Zahlen erst bekannt sind, nachdem der Body umbrochen wurde — eine Gesamtseitenzahl, eine Gesamtsumme, eine Datensatzanzahl. Reservieren Sie Seite 1 im Voraus, rendern Sie den Body, füllen Sie dann die Deckseite mit setPage(1) nach und setzen Sie am Ende mit lastPage() fort. Dieses Beispiel zeigt außerdem die zwei Fail-closed-Grenzen, die Sie behandeln müssen: die UnsupportedFeatureException des Adapters für eine Seitenzahl außerhalb des Bereichs und die Core-RetainedPageBufferIncompatibleException, falls das Dokument zusätzlich eine inkompatible Funktion aktiviert.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\UnsupportedFeatureException;
use NextPDF\Compat\Tcpdf\TCPDF;
use NextPDF\Exception\Strict\RetainedPageBufferIncompatibleException;
/**
* Render a multi-page report whose cover page summarises figures that are
* only known once every body page has been laid out.
*
* @param list<array{label: string, amount: float}> $lineItems
*/
function renderReport(array $lineItems, string $destination): void
{
// Opt in to the back-fill buffer. Default-off; this is a NextPDF
// extension, not legacy TCPDF parity. (Underlying core feature: 6.1.0.)
$pdf = new TCPDF(retainedPageBuffer: true);
// Page 1 — the cover. Reserve it now; the summary is filled in last.
$pdf->AddPage();
$pdf->Cell(0, 10, 'Quarterly report', ln: 1);
// Body pages — lay out the line items, accumulating the running total.
$pdf->AddPage();
$total = 0.0;
foreach ($lineItems as $item) {
$total += $item['amount'];
$pdf->Cell(0, 8, $item['label'] . ': ' . number_format($item['amount'], 2), ln: 1);
}
// Back-fill the cover with figures known only now. setPage() delegates to
// the core back-fill in retained mode; an out-of-range page number still
// fails closed with UnsupportedFeatureException in BOTH modes.
try {
$pdf->setPage(1);
} catch (UnsupportedFeatureException $e) {
throw new RuntimeException('Cover page was not reserved: ' . $e->getMessage(), previous: $e);
}
$pdf->Cell(0, 10, 'Total: ' . number_format($total, 2), ln: 1);
$pdf->Cell(0, 10, 'Line items: ' . count($lineItems), ln: 1);
// Resume appending at the final page before output.
$pdf->lastPage();
// Output() drives the core build. If the document had also enabled a
// back-fill-incompatible feature (signing, tagging, PDF/A, linearization,
// object streams, encryption, Safe CSS mode), the core refuses here,
// order-independently, with RetainedPageBufferIncompatibleException — the
// back-fill can never silently corrupt such a document.
try {
$pdf->Output($destination, 'F');
} catch (RetainedPageBufferIncompatibleException $e) {
// $e->feature names the incompatible feature, e.g. 'signature'.
throw new RuntimeException(
'Back-fill is incompatible with ' . $e->feature . '; render pages in order instead.',
previous: $e,
);
}
}

Unterscheiden Sie die zwei Fehleroberflächen bewusst:

  • UnsupportedFeatureException (Adapter) — ein außerhalb des Bereichs liegendes setPage()- / lastPage()-Ziel oder jeder Wechsel auf eine frühere Seite, wenn der Puffer aus ist.
  • RetainedPageBufferIncompatibleException (Core, NextPDF\Exception\Strict) — der Puffer ist an, aber mit einer Funktion kombiniert, deren Seiten-Metadaten nach einer Nachfüllung nicht neu abgeleitet werden können. Es gibt keinen RetainedPageBufferInconsistency-Typ; dies ist die einzige Inkompatibilitäts-Ausnahme, und eine Budget-Überschreitung tritt als \OverflowException zutage.

Der Adapter delegiert an den Core-Retained-Page-Buffer, sodass dieselben Verweigerungen gelten. Die Nachfüllung wird verweigert — reihenfolgeunabhängig und vor der Serialisierung — wenn das Dokument zusätzlich eine der folgenden Funktionen nutzt:

  • Eine digitale Signatur.
  • Tagged PDF (Strukturbaum).
  • PDF/A.
  • Linearisierung.
  • Object-Stream-Packing.
  • Verschlüsselung.
  • Safe-CSS-Rendering-Modus.

Jede Verweigerung ist eine typisierte, fail-closed Ausnahme — niemals ein stiller Drop:

  • Das Kombinieren des Puffers mit einer der obigen Funktionen löst die Core-RetainedPageBufferIncompatibleException aus (Namespace NextPDF\Exception\Strict, @since Core 6.1.0). Die Prüfung ist reihenfolgeunabhängig: Sie feuert, gleich ob die inkompatible Funktion vor oder nach dem Opt-in des Puffers konfiguriert wurde.
  • Ein Budget von 16 MiB unkomprimierter Bytes pro Dokument begrenzt den Puffer; ein Überschreiten löst zur Build-Zeit \OverflowException aus, statt eine nachgefüllte Seite zu droppen.

Der Sinn der Verweigerung ist, dass eine Nachfüllung niemals stillschweigend ein signiertes oder verschlüsseltes Dokument verändern kann — die beiden lassen sich nicht gemeinsam aktivieren.

  • Standardmäßig aus. Konstruieren Sie ohne das Flag, und der Adapter ist unverändert; setPage() auf eine frühere Seite löst weiterhin UnsupportedFeatureException aus. Dies bewahrt den Streaming-Vertrag für jeden bestehenden Aufrufer.
  • Keine Legacy-Parität. Legacy-TCPDF hat kein retainedPageBuffer-Konstruktor-Flag. Dokumentieren Sie dies bei der Migration als NextPDF-Erweiterung, sodass ein späterer Leser es nicht für eine TCPDF-Funktion hält.
  • lastPage() führt ans Ende zurück. Rufen Sie nach einer Nachfüllung lastPage() auf, um das Anhängen an der finalen Seite fortzusetzen.
  • Planen Sie einen Modus. Wenn das Dokument signiert, getaggt, PDF/A, linearisiert, verschlüsselt oder Object-Stream-gepackt sein muss, aktivieren Sie den Puffer nicht; berechnen Sie stattdessen den Wert, den Sie nachgefüllt hätten, vorab.