Salta ai contenuti

Impaginare una tabella HTML di grandi dimensioni su più pagine

Passare un’unica <table> di grandi dimensioni a writeHtml(). Il motore la impagina su tutte le pagine PDF necessarie a contenere le righe. Il <thead> si ripete all’inizio di ogni pagina, così ogni pagina si presenta come una tabella completa. Questa ricetta esegue il rendering di un report di 91 righe distribuito su più pagine. Non occorre suddividere la tabella né calcolare le interruzioni di pagina.

Terminal window
composer require nextpdf/core

Quando una tabella è più alta di una pagina, mantenerla come unico elemento <table>. Il motore misura ciascuna riga, riempie l’altezza utile della pagina, apre una nuova pagina e continua la stessa tabella. Le righe del <thead> vengono renderizzate di nuovo all’inizio di ogni pagina di continuazione. Le pagine di continuazione mantengono i margini superiore e inferiore del documento, quindi la prima riga di una nuova pagina inizia sotto il margine superiore, non sul bordo della pagina.

Inserire le celle di intestazione in un <thead> e le righe di dati in un <tbody>. Solo il <thead> viene ripetuto. Ogni riga deve restare suddivisibile. Una singola riga più alta dell’altezza utile della pagina non può essere impaginata e genera UnsplittableContentException.

SimboloPosizioneRuolo
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputEsegue il rendering dell’HTML e impagina le tabelle quando necessario.
Document::createStandalone(): selfNextPDF\Core\DocumentCrea un documento autonomo.
Document::addPage(): staticNextPDF\Core\DocumentApre la prima pagina e imposta le dimensioni della pagina e i margini.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$rows = '';
for ($i = 1; $i <= 91; $i++) {
$rows .= "<tr><td>{$i}</td><td>Item {$i}</td><td>In stock</td></tr>";
}
$doc = Document::createStandalone();
$doc->addPage();
$doc->writeHtml(
'<table>'
. '<thead><tr><th>#</th><th>Name</th><th>Status</th></tr></thead>'
. "<tbody>{$rows}</tbody>"
. '</table>'
);
$doc->save(__DIR__ . '/large-table.pdf');

Le 91 righe vengono distribuite su più pagine e l’intestazione #/Name/Status si ripete su ciascuna pagina.

Questo esempio autonomo applica uno stile all’intestazione, alterna i colori delle righe e scrive il PDF nel percorso fornito dall’harness.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$rows = '';
for ($i = 1; $i <= 91; $i++) {
$bg = $i % 2 === 0 ? '#F8FAFC' : '#FFFFFF';
$rows .= "<tr style=\"background-color: {$bg};\">"
. "<td style=\"border: 1px solid #CBD5E1; padding: 4px;\">{$i}</td>"
. "<td style=\"border: 1px solid #CBD5E1; padding: 4px;\">Item {$i}</td>"
. "<td style=\"border: 1px solid #CBD5E1; padding: 4px;\">In stock</td>"
. '</tr>';
}
$html = <<<HTML
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background-color: #1E3A8A; color: #FFFFFF;">
<th style="border: 1px solid #1E3A8A; padding: 6px;">#</th>
<th style="border: 1px solid #1E3A8A; padding: 6px;">Name</th>
<th style="border: 1px solid #1E3A8A; padding: 6px;">Status</th>
</tr>
</thead>
<tbody>{$rows}</tbody>
</table>
HTML;
$doc = Document::createStandalone();
$doc->setTitle('Inventory report');
$doc->addPage();
$doc->writeHtml($html);
$out = getenv('NEXTPDF_OUT');
$doc->save($out !== false ? $out : __DIR__ . '/paginate-large-html-tables.pdf');
echo "Wrote the paginated table PDF\n";

Le pagine di continuazione usano i margini superiore e inferiore del documento. La prima riga dopo un’interruzione di pagina inizia sotto il margine superiore e l’ultima riga prima di un’interruzione si ferma sopra il margine inferiore. Questo impedisce che una tabella lunga venga ritagliata contro il bordo della pagina. La stessa regola si applica sia a un blocco multipagina sia a una tabella multipagina.

  • Gli avvisi di impaginazione restano silenziosi in caso di successo. Quando una tabella si distribuisce correttamente su più pagine, non emette alcun avviso. Il motore genera un avviso TABLE_ROW_OVERFLOW solo per un layout degradato: quando non esiste un sink per le interruzioni di pagina, oppure quando una riga deve essere ricollocata per aprire una pagina. Trattare l’avviso come un segnale per semplificare la tabella, non come un errore.
  • Inserire l’intestazione nel <thead>. Si ripetono solo le righe del <thead>. Una riga di intestazione lasciata nel <tbody> compare una sola volta.
  • Le righe devono essere suddivisibili. Una singola riga più alta dell’altezza utile della pagina genera UnsplittableContentException. Scomporre il contenuto di quella riga, oppure accorciarlo.
  • rowspan degrada attraverso un’interruzione. Una cella con rowspan che attraversa il limite di una pagina si frammenta (ADR-007). Per i raggruppamenti che devono restare integri durante l’impaginazione, usare invece una riga di intestazione di categoria. Consultare Funzionalità CSS non supportate.

Il rendering scala linearmente con il numero di righe. Il motore trasmette l’output pagina per pagina e non mantiene mai un albero del documento; quindi, per una tabella lunga, la memoria non cresce con il numero di pagine. Il budget di questa ricetta è wall_ms: 2000, peak_mb: 96.

Convalidare il numero di righe e la lunghezza delle celle nei dati forniti dall’utente per mantenere limitata la dimensione dell’output. Il motore esegue il rendering del testo anziché interpretarlo e non esegue alcuno script.

DichiarazioneSpecificaClausolareference_id
Un gruppo di intestazione di tabella si ripete nei contenitori di frammentazione in cui una tabella viene suddivisa.W3C CSS Tables 3css_tables_3#x1.x7.x253622ccb1bce2a0cc53bd70919fa4633a9376e2050f63a31a3fde9cb6595ec78

Non applicabile.