Bỏ qua để đến nội dung
getnextpdf.com

độ ổn định: Thử nghiệm

Phần mở rộng bộ đệm trang retained

Phần mở rộng opt-in, không phải tương đương cũ. Đối số hàm dựng này không tồn tại trong TCPDF 6.x cũ. Nó là một phần mở rộng NextPDF. Nó mặc định tắt; khi nó tắt, bộ chuyển đổi hành xử hệt như trước, và setPage() về một trang trước đó làm phát sinh UnsupportedFeatureException như xưa nay.

TCPDF cũ cho phép bạn gọi setPage() để quay về một trang trước đó và tiếp tục vẽ. Bộ chuyển đổi streaming không thể làm điều đó theo mặc định — một khi một trang đã được flush, nó biến mất — nên setPage() hoặc lastPage() về một trang trước đó làm phát sinh UnsupportedFeatureException. Bộ đệm trang retained là tùy chọn opt-in khôi phục hành vi điền bù này trên nền bộ đệm trang retained của NextPDF core.

Truyền retainedPageBuffer: true vào hàm dựng bộ chuyển đổi. Khi bộ đệm bật, một lệnh gọi setPage() hoặc lastPage() nhắm vào một trang trước đó sẽ ủy quyền cho điền bù của core thay vì làm phát sinh:

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

Ví dụ sản phẩm: điền bù một trang bìa đã dành

Phần tiêu đề “Ví dụ sản phẩm: điền bù một trang bìa đã dành”

Một lý do phổ biến để dùng đến bộ đệm là một trang bìa hay trang tóm tắt mà các con số chỉ biết được sau khi phần thân đã được dàn xong — tổng số trang, một ô tổng, một số đếm bản ghi. Hãy dành sẵn trang 1 từ đầu, kết xuất phần thân, rồi điền bù trang bìa với setPage(1), và tiếp tục ở cuối với lastPage(). Ví dụ này cũng cho thấy hai ranh giới fail-closed mà bạn phải xử lý: UnsupportedFeatureException của bộ chuyển đổi cho một số trang ngoài phạm vi, và RetainedPageBufferIncompatibleException của core nếu tài liệu cũng bật một tính năng không tương thích.

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

Hãy phân biệt hai bề mặt hỏng một cách có chủ ý:

  • UnsupportedFeatureException (bộ chuyển đổi) — một mục tiêu setPage() / lastPage() ngoài phạm vi, hoặc bất kỳ lần chuyển sang trang trước đó nào khi bộ đệm tắt.
  • RetainedPageBufferIncompatibleException (core, NextPDF\Exception\Strict) — bộ đệm bật nhưng kết hợp với một tính năng mà siêu dữ liệu cấp trang của nó không thể được suy dẫn lại sau một lần điền bù. Không có kiểu RetainedPageBufferInconsistency nào; đây là ngoại lệ không-tương-thích duy nhất, và một lần vượt ngân sách hiện lên dưới dạng \OverflowException.

Bộ chuyển đổi ủy quyền cho bộ đệm trang retained của core, nên cùng các từ chối áp dụng. Điền bù bị từ chối — không phụ thuộc thứ tự và trước khi serialize — khi tài liệu cũng dùng bất kỳ tính năng nào trong số:

  • Một chữ ký số.
  • PDF gắn thẻ (cây cấu trúc).
  • PDF/A.
  • Linearization.
  • Đóng gói object-stream.
  • Mã hóa.
  • Chế độ kết xuất CSS Safe.

Mỗi lần từ chối là một ngoại lệ có kiểu, fail-closed — không bao giờ là một lần bỏ âm thầm:

  • Kết hợp bộ đệm với bất kỳ tính năng nào ở trên làm phát sinh RetainedPageBufferIncompatibleException của core (namespace NextPDF\Exception\Strict, @since core 6.1.0). Phép kiểm tra không phụ thuộc thứ tự: nó kích hoạt dù tính năng không tương thích được cấu hình trước hay sau khi bộ đệm được opt-in.
  • Một ngân sách byte-chưa-nén 16 MiB theo từng tài liệu chặn bộ đệm; vượt quá nó làm phát sinh \OverflowException tại lúc build thay vì bỏ một trang đã điền bù.

Điểm cốt lõi của sự từ chối là một lần điền bù không bao giờ có thể âm thầm làm thay đổi một tài liệu đã ký hay đã mã hóa — cả hai không thể được bật cùng nhau.

  • Mặc định tắt. Dựng mà không có cờ thì bộ chuyển đổi không đổi; setPage() về một trang trước đó vẫn làm phát sinh UnsupportedFeatureException. Điều này giữ hợp đồng streaming cho mọi bên gọi hiện có.
  • Không phải tương đương cũ. TCPDF cũ không có cờ hàm dựng retainedPageBuffer. Hãy ghi tài liệu điều này như một phần mở rộng NextPDF khi bạn di trú, để một người đọc về sau không nhầm nó là một tính năng TCPDF.
  • lastPage() quay về cuối. Sau một lần điền bù, hãy gọi lastPage() để tiếp tục thêm ở trang cuối.
  • Lập kế hoạch một chế độ. Nếu tài liệu phải được ký, gắn thẻ, PDF/A, linearize, mã hóa, hoặc object-stream, đừng bật bộ đệm; thay vào đó hãy tính trước giá trị mà lẽ ra bạn sẽ điền bù.