Zum Inhalt springen

Große HTML-Tabelle über mehrere Seiten paginieren

Übergeben Sie eine große <table> an writeHtml(). Die Engine paginiert sie über so viele PDF-Seiten, wie die Zeilen benötigen. Der <thead> wird oben auf jeder Seite wiederholt, sodass jede Seite als vollständige Tabelle lesbar bleibt. Dieses Rezept rendert einen Bericht mit 91 Zeilen, der über mehrere Seiten läuft. Sie müssen die Tabelle nicht selbst aufteilen und keine Seitenumbrüche berechnen.

Terminal-Fenster
composer require nextpdf/core

Wenn eine Tabelle höher als eine Seite ist, belassen Sie sie als ein einziges <table>-Element. Die Engine misst jede Zeile, füllt die nutzbare Seitenhöhe, öffnet eine neue Seite und setzt dieselbe Tabelle fort. Die <thead>-Zeilen werden oben auf jeder Fortsetzungsseite erneut gerendert. Fortsetzungsseiten behalten die oberen und unteren Ränder des Dokuments, sodass die erste Zeile auf einer neuen Seite unterhalb des oberen Rands beginnt und nicht direkt am Seitenrand.

Platzieren Sie Kopfzellen in einem <thead> und Datenzeilen in einem <tbody>. Nur der <thead> wird wiederholt. Gestalten Sie jede Zeile so, dass sie aufgeteilt werden kann. Eine einzelne Zeile, die höher als die nutzbare Seitenhöhe ist, lässt sich nicht paginieren und löst UnsplittableContentException aus.

SymbolSpeicherortRolle
Document::writeHtml(string $html): staticNextPDF\Core\Concerns\HasTextOutputRendert HTML und paginiert Tabellen nach Bedarf.
Document::createStandalone(): selfNextPDF\Core\DocumentErstellt ein eigenständiges Dokument.
Document::addPage(): staticNextPDF\Core\DocumentÖffnet die erste Seite und setzt Seitengröße und Ränder.
<?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');

Die 91 Zeilen laufen über mehrere Seiten, und die Kopfzeile #/Name/Status wird auf jeder Seite wiederholt.

Dieses eigenständige Beispiel formatiert die Kopfzeile, gestaltet die Zeilen abwechselnd und schreibt das PDF in den vom Harness bereitgestellten Pfad.

<?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";

Fortsetzungsseiten verwenden die oberen und unteren Ränder des Dokuments. Die erste Zeile nach einem Seitenumbruch beginnt unterhalb des oberen Rands, und die letzte Zeile vor einem Umbruch endet oberhalb des unteren Rands. Dadurch wird verhindert, dass eine lange Tabelle am Seitenrand abgeschnitten wird. Dieselbe Regel gilt für mehrseitige Blöcke und mehrseitige Tabellen.

  • Bei erfolgreicher Paginierung bleiben Warnungen aus. Wenn eine Tabelle sauber über die Seiten läuft, wird keine Warnung ausgegeben. Die Engine löst eine TABLE_ROW_OVERFLOW-Warnung nur bei einem herabgestuften Layout aus: wenn es keinen Page-Break-Sink gibt oder wenn eine Zeile an den Anfang einer Seite verschoben werden muss. Behandeln Sie die Warnung als Hinweis darauf, die Tabelle zu vereinfachen, nicht als Fehler.
  • Setzen Sie die Kopfzeile in <thead>. Nur <thead>-Zeilen werden wiederholt. Eine Kopfzeile, die in <tbody> belassen wird, erscheint nur einmal.
  • Zeilen müssen aufteilbar sein. Eine einzelne Zeile, die höher als die nutzbare Seitenhöhe ist, löst UnsplittableContentException aus. Teilen Sie den Inhalt dieser Zeile auf oder kürzen Sie ihn.
  • rowspan wird über einen Umbruch hinweg herabgestuft. Eine rowspan-Zelle, die eine Seitengrenze überschreitet, fragmentiert (ADR-007). Verwenden Sie für Gruppierungen, die bei der Paginierung intakt bleiben müssen, stattdessen eine Kategorie-Kopfzeile. Siehe Nicht unterstützte CSS-Funktionen.

Das Rendering skaliert linear mit der Zeilenanzahl. Die Engine streamt die Ausgabe Seite für Seite und hält zu keinem Zeitpunkt einen vollständigen Dokumentbaum vor, sodass der Speicherbedarf für eine lange Tabelle nicht mit der Seitenanzahl wächst. Das Budget dieses Rezepts ist wall_ms: 2000, peak_mb: 96.

Validieren Sie bei von Benutzern gelieferten Daten die Zeilenanzahl und die Zellenlänge, um die Ausgabegröße zu begrenzen. Die Engine rendert Text, statt ihn zu interpretieren, und führt keine Skripte aus.

AussageSpezifikationKlauselreference_id
Eine Tabellen-Kopfgruppe wiederholt sich über die Fragmentierungscontainer hinweg, in die eine Tabelle aufgeteilt wird.W3C CSS Tables 3css_tables_3#x1.x7.x253622ccb1bce2a0cc53bd70919fa4633a9376e2050f63a31a3fde9cb6595ec78

Nicht zutreffend.