estabilidad: Experimental
Extensión del búfer de páginas retenidas
De un vistazo
Sección titulada «De un vistazo»Extensión opcional, no paridad heredada. Este argumento del constructor no existe en el TCPDF heredado 6.x. Es una extensión de NextPDF. Está desactivado por defecto; con él desactivado, el adaptador se comporta exactamente como antes, y
setPage()a una página anterior lanzaUnsupportedFeatureExceptioncomo siempre ha hecho.
El TCPDF heredado le permite llamar a setPage() para volver a una página
anterior y seguir dibujando. El adaptador por streaming no puede hacer eso por
defecto —una vez que una página se vuelca, desaparece—, por lo que setPage() o
lastPage() a una página anterior lanza UnsupportedFeatureException. El búfer
de páginas retenidas es la opción que restaura este comportamiento de relleno a
posteriori sobre el búfer de páginas retenidas del core de NextPDF.
Habilitar el búfer
Sección titulada «Habilitar el búfer»Pase retainedPageBuffer: true al constructor del adaptador. Con el búfer
activado, una llamada setPage() o lastPage() que apunte a una página anterior
delega en el relleno a posteriori del core en lugar de lanzar:
<?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');Ejemplo de producción: rellenar a posteriori una página de portada reservada
Sección titulada «Ejemplo de producción: rellenar a posteriori una página de portada reservada»Un motivo común para recurrir al búfer es una página de portada o de resumen
cuyos números solo se conocen después de maquetar el cuerpo: un recuento total
de páginas, un total general, un recuento de registros. Reserve la página 1 por
adelantado, represente el cuerpo, luego rellene a posteriori la portada con
setPage(1) y reanude al final con lastPage(). Este ejemplo también muestra los
dos límites de cierre seguro que debe manejar: la UnsupportedFeatureException
del adaptador para un número de página fuera de rango, y la
RetainedPageBufferIncompatibleException del core si el documento también
habilita una característica incompatible.
<?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, ); }}Distinga las dos superficies de fallo deliberadamente:
UnsupportedFeatureException(adaptador): un objetivo desetPage()/lastPage()fuera de rango, o cualquier cambio a una página anterior cuando el búfer está desactivado.RetainedPageBufferIncompatibleException(core,NextPDF\Exception\Strict): el búfer está activado pero combinado con una característica cuyos metadatos a nivel de página no pueden volver a derivarse tras un relleno a posteriori. No existe ningún tipoRetainedPageBufferInconsistency; esta es la única excepción de incompatibilidad, y una vulneración del presupuesto aflora como\OverflowException.
Límite de cierre seguro
Sección titulada «Límite de cierre seguro»El adaptador delega en el búfer de páginas retenidas del core, por lo que se aplican los mismos rechazos. El relleno a posteriori se rechaza —de forma independiente del orden y antes de la serialización— cuando el documento también usa cualquiera de:
- Una firma digital.
- PDF etiquetado (árbol de estructura).
- PDF/A.
- Linealización.
- Empaquetado en flujos de objetos.
- Cifrado.
- Modo de representación Safe de CSS.
Cada rechazo es una excepción tipada y de cierre seguro, nunca un descarte silencioso:
- Combinar el búfer con cualquier característica de arriba lanza la
RetainedPageBufferIncompatibleExceptiondel core (espacio de nombresNextPDF\Exception\Strict,@sincecore 6.1.0). La comprobación es independiente del orden: se dispara tanto si la característica incompatible se configuró antes como después de optar por el búfer. - Un presupuesto de bytes sin comprimir de 16 MiB por documento acota el
búfer; excederlo lanza
\OverflowExceptionen el momento de la compilación en lugar de descartar una página rellenada a posteriori.
El objetivo del rechazo es que un relleno a posteriori nunca pueda alterar silenciosamente un documento firmado o cifrado: ambos no pueden habilitarse a la vez.
Notas de comportamiento
Sección titulada «Notas de comportamiento»- Desactivado por defecto. Construya sin el indicador y el adaptador queda sin
cambios;
setPage()a una página anterior aún lanzaUnsupportedFeatureException. Esto preserva el contrato de streaming para cada llamador existente. - No es paridad heredada. El TCPDF heredado no tiene ningún indicador de
constructor
retainedPageBuffer. Documente esto como una extensión de NextPDF cuando migre, para que un lector futuro no lo confunda con una característica de TCPDF. lastPage()vuelve al final. Tras un relleno a posteriori, llame alastPage()para reanudar el anexado en la página final.- Planee un modo. Si el documento debe estar firmado, etiquetado, en PDF/A, linealizado, cifrado o con flujos de objetos, no habilite el búfer; en su lugar, calcule de antemano el valor que habría rellenado a posteriori.