stabilność: Eksperymentalna
Zachowany bufor stron (rozszerzenie)
W skrócie
Dział zatytułowany „W skrócie”Opcjonalne rozszerzenie, a nie odpowiednik starego. Ten argument konstruktora nie istnieje w starym TCPDF 6.x. To rozszerzenie NextPDF. Jest domyślnie wyłączone; przy nim wyłączonym adapter zachowuje się dokładnie jak wcześniej, a
setPage()do wcześniejszej strony zgłaszaUnsupportedFeatureExceptionjak zawsze.
Stary TCPDF pozwala wywołać setPage(), aby cofnąć się do wcześniejszej strony i
dalej rysować. Adapter strumieniowy nie potrafi tego domyślnie — po wypchnięciu
strony znika ona — więc setPage() lub lastPage() do wcześniejszej strony
zgłasza UnsupportedFeatureException. Zachowany bufor stron to opcja, która
przywraca to zachowanie uzupełniania na bazie zachowanego bufora stron rdzenia
NextPDF.
Włączanie bufora
Dział zatytułowany „Włączanie bufora”Przekaż retainedPageBuffer: true do konstruktora adaptera. Przy włączonym
buforze wywołanie setPage() lub lastPage() celujące we wcześniejszą stronę
deleguje do uzupełniania w rdzeniu, zamiast zgłaszać:
<?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');Przykład produkcyjny: uzupełnienie zarezerwowanej strony tytułowej
Dział zatytułowany „Przykład produkcyjny: uzupełnienie zarezerwowanej strony tytułowej”Częstym powodem sięgnięcia po bufor jest strona tytułowa lub podsumowująca,
której liczby są znane dopiero po rozłożeniu treści — łączna liczba stron, suma
ogólna, liczba rekordów. Zarezerwuj stronę 1 z góry, wyrenderuj treść, a następnie
uzupełnij stronę tytułową przez setPage(1) i wznów na końcu przez lastPage().
Ten przykład pokazuje też dwie granice fail-closed, które musisz obsłużyć:
adapterowy UnsupportedFeatureException dla numeru strony spoza zakresu oraz
rdzeniowy RetainedPageBufferIncompatibleException, jeśli dokument włącza też
niezgodną funkcję.
<?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, ); }}Rozróżniaj te dwie powierzchnie awarii celowo:
UnsupportedFeatureException(adapter) — celsetPage()/lastPage()spoza zakresu lub jakiekolwiek przełączenie na wcześniejszą stronę, gdy bufor jest wyłączony.RetainedPageBufferIncompatibleException(rdzeń,NextPDF\Exception\Strict) — bufor jest włączony, ale połączony z funkcją, której metadanych na poziomie strony nie da się ponownie wyprowadzić po uzupełnieniu. Nie ma typuRetainedPageBufferInconsistency; to jedyny wyjątek niezgodności, a przekroczenie budżetu wypływa jako\OverflowException.
Granica fail-closed
Dział zatytułowany „Granica fail-closed”Adapter deleguje do zachowanego bufora stron rdzenia, więc obowiązują te same odmowy. Uzupełnianie jest odmawiane — niezależnie od kolejności i przed serializacją — gdy dokument używa też którejkolwiek z:
- Podpisu cyfrowego.
- Tagowanego PDF (drzewa struktury).
- PDF/A.
- Linearyzacji.
- Pakowania w strumienie obiektów.
- Szyfrowania.
- Trybu renderowania Safe CSS.
Każda odmowa to typowany wyjątek fail-closed — nigdy cichy zrzut:
- Połączenie bufora z którąkolwiek z powyższych funkcji zgłasza rdzeniowy
RetainedPageBufferIncompatibleException(przestrzeń nazwNextPDF\Exception\Strict,@sincerdzeń 6.1.0). Sprawdzenie jest niezależne od kolejności: zadziała niezależnie od tego, czy niezgodna funkcja została skonfigurowana przed buforem czy po włączeniu opcji bufora. - Budżet 16 MiB nieskompresowanych bajtów na dokument ogranicza bufor;
przekroczenie go zgłasza
\OverflowExceptionw czasie budowania, zamiast porzucać uzupełnioną stronę.
Sensem odmowy jest to, że uzupełnienie nigdy nie może po cichu zmienić podpisanego lub zaszyfrowanego dokumentu — tych dwóch nie da się włączyć razem.
Uwagi o zachowaniu
Dział zatytułowany „Uwagi o zachowaniu”- Domyślnie wyłączone. Skonstruuj bez flagi, a adapter pozostaje bez zmian;
setPage()do wcześniejszej strony nadal zgłaszaUnsupportedFeatureException. To zachowuje kontrakt strumieniowy dla każdego istniejącego wywołującego. - Nie odpowiednik starego. Stary TCPDF nie ma flagi konstruktora
retainedPageBuffer. Udokumentuj to jako rozszerzenie NextPDF, gdy migrujesz, aby przyszły czytelnik nie pomylił tego z funkcją TCPDF. lastPage()wraca na koniec. Po uzupełnieniu wywołajlastPage(), aby wznowić dołączanie na ostatniej stronie.- Zaplanuj jeden tryb. Jeśli dokument ma być podpisany, tagowany, PDF/A, zlinearyzowany, zaszyfrowany lub ze strumieniami obiektów, nie włączaj bufora; zamiast tego oblicz z góry wartość, którą byś uzupełnił.