Lewati ke konten
getnextpdf.com

stabilitas: Eksperimental

Ekstensi buffer halaman dipertahankan

Ekstensi opt-in, bukan paritas legacy. Argumen konstruktor ini tidak ada dalam TCPDF 6.x legacy. Ini adalah ekstensi NextPDF. Ia default-mati; dengan ia mati, adapter berperilaku persis seperti sebelumnya, dan setPage() ke halaman terdahulu memunculkan UnsupportedFeatureException sebagaimana selalu.

TCPDF legacy memungkinkan Anda memanggil setPage() untuk kembali ke halaman terdahulu dan terus menggambar. Adapter streaming tidak dapat melakukan itu secara default — begitu sebuah halaman di-flush, ia hilang — sehingga setPage() atau lastPage() ke halaman terdahulu memunculkan UnsupportedFeatureException. Buffer halaman dipertahankan adalah opt-in yang memulihkan perilaku pengisian-ulang ini di atas buffer halaman dipertahankan core NextPDF.

Berikan retainedPageBuffer: true ke konstruktor adapter. Dengan buffer aktif, sebuah panggilan setPage() atau lastPage() yang menargetkan halaman terdahulu mendelegasikan ke pengisian-ulang core alih-alih memunculkan eksepsi:

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

Contoh produksi: mengisi-ulang halaman sampul yang dicadangkan

Bagian berjudul “Contoh produksi: mengisi-ulang halaman sampul yang dicadangkan”

Alasan umum untuk meraih buffer adalah halaman sampul atau ringkasan yang angkanya baru diketahui setelah body ditata — total jumlah halaman, grand total, hitungan rekaman. Cadangkan halaman 1 di muka, render body, lalu isi-ulang sampul dengan setPage(1), dan lanjutkan di akhir dengan lastPage(). Contoh ini juga menunjukkan dua batasan fail-closed yang harus Anda tangani: UnsupportedFeatureException adapter untuk nomor halaman di-luar-rentang, dan RetainedPageBufferIncompatibleException core jika dokumen juga mengaktifkan fitur yang tidak kompatibel.

<?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,
);
}
}

Bedakan kedua permukaan kegagalan secara sengaja:

  • UnsupportedFeatureException (adapter) — target setPage() / lastPage() yang di-luar-rentang, atau peralihan halaman-terdahulu apa pun saat buffer mati.
  • RetainedPageBufferIncompatibleException (core, NextPDF\Exception\Strict) — buffer aktif tetapi digabung dengan fitur yang metadata tingkat-halamannya tidak dapat diturunkan ulang setelah pengisian-ulang. Tidak ada tipe RetainedPageBufferInconsistency; ini adalah satu-satunya eksepsi ketidakkompatibelan, dan pelanggaran anggaran muncul sebagai \OverflowException.

Adapter mendelegasikan ke buffer halaman dipertahankan core, sehingga penolakan yang sama berlaku. Pengisian-ulang ditolak — terlepas dari urutan dan sebelum serialisasi — saat dokumen juga memakai salah satu dari:

  • Sebuah tanda tangan digital.
  • PDF bertag (pohon struktur).
  • PDF/A.
  • Linearisasi.
  • Pengemasan object stream.
  • Enkripsi.
  • Mode rendering Safe CSS.

Setiap penolakan adalah eksepsi bertipe dan fail-closed — tidak pernah drop diam:

  • Menggabungkan buffer dengan fitur mana pun di atas memunculkan RetainedPageBufferIncompatibleException core (namespace NextPDF\Exception\Strict, @since core 6.1.0). Pemeriksaannya terlepas dari urutan: ia terpicu baik fitur tak-kompatibel dikonfigurasikan sebelum atau setelah buffer di-opt-in.
  • Anggaran byte-tak-terkompresi per-dokumen 16 MiB membatasi buffer; melampauinya memunculkan \OverflowException pada waktu build alih-alih mendrop halaman yang sudah diisi-ulang.

Inti dari penolakan ini adalah bahwa pengisian-ulang tidak akan pernah dapat diam-diam mengubah dokumen yang ditandatangani atau terenkripsi — keduanya tidak dapat diaktifkan bersama.

  • Default-mati. Konstruksi tanpa flag dan adapter tidak berubah; setPage() ke halaman terdahulu tetap memunculkan UnsupportedFeatureException. Ini mempertahankan kontrak streaming bagi setiap pemanggil yang sudah ada.
  • Bukan paritas legacy. TCPDF legacy tidak memiliki flag konstruktor retainedPageBuffer. Dokumentasikan ini sebagai ekstensi NextPDF saat Anda bermigrasi, agar pembaca di masa depan tidak salah mengiranya sebagai fitur TCPDF.
  • lastPage() kembali ke akhir. Setelah pengisian-ulang, panggil lastPage() untuk melanjutkan append pada halaman terakhir.
  • Rencanakan satu mode. Jika dokumen harus ditandatangani, bertag, PDF/A, ter-linearisasi, terenkripsi, atau object-streamed, jangan aktifkan buffer; pra-hitung nilai yang akan Anda isi-ulang sebagai gantinya.