Aller au contenu

Mettre en page un tableau HTML

Cette recette rend un tableau HTML avec un en-tête, des cellules alignées, des bordures et une ligne de pied de tableau. Les tableaux constituent un module Vérifié dans la matrice de prise en charge CSS. La recette suit examples/09-html-table.php.

Fenêtre de terminal
composer require nextpdf/core:^3

Cette contrainte cible le package nextpdf/core. L’exemple s’exécute sur PHP 8.4.

Le moteur HTML dispose d’un pipeline de tableau dédié (src/Html/Table/). TableParser regroupe les lignes et les cellules dans un tampon éphémère, puis le tableau est mis en page et peint. C’est la seule entorse reconnue au modèle sans DOM conservé décrit dans l’ADR-001. Le tampon est éphémère et limité à son conteneur. Ce n’est pas un DOM persistant.

Les largeurs de colonne suivent le modèle CSS Table. Le tableau est mis en page à une largeur utilisée donnée, puis l’algorithme de dimensionnement des colonnes fixe la largeur utilisée de chaque colonne (W3C CSS Table Level 3). Avec table-layout: fixed, le contenu des cellules est ignoré pour le calcul de la largeur. La première ligne et les largeurs de colonne explicites pilotent alors la mise en page (W3C CSS Table Level 3).

CSS Table Level 3 est noté Vérifié dans la matrice. Quatre sources étayent cette note : src/Html/Table/, la suite de tests unitaires Table, les tests TableParser et les PDF de référence synthétiques.

Les tableaux sont rendus via writeHtml(string $html): static (NextPDF\Core\Concerns\HasTextOutput). Le moteur prend en charge le balisage de tableau standard. Les balises prises en charge sont table, thead, tbody, tfoot, tr, th et td. Les attributs pris en charge sont border, cellpadding, cellspacing, colspan, ainsi qu’un attribut style par cellule. La table PHPDoc complète est générée à partir du code source.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->addPage();
$doc->writeHtml(
'<table border="1" cellpadding="5"><tr><th>SKU</th><th>Qty</th></tr>'
. '<tr><td>NPD-CORE</td><td style="text-align: right;">1</td></tr></table>'
);
$doc->save(__DIR__ . '/out.pdf');

Cet exemple est autonome et le harnais peut l’exécuter. Il reprend examples/09-html-table.php et montre un en-tête stylisé, des fonds de ligne alternés, des colonnes numériques alignées et un total en pied de tableau.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('HTML Table');
$doc->addPage();
$html = <<<'HTML'
<h1 style="color: #1E3A8A;">Product Inventory Report</h1>
<table border="1" cellpadding="5" cellspacing="0" style="width: 100%;">
<thead>
<tr style="background-color: #1E3A8A; color: #FFFFFF;">
<th style="width: 10%;">#</th>
<th style="width: 45%;">Product</th>
<th style="width: 20%; text-align: center;">SKU</th>
<th style="width: 25%; text-align: right;">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>NextPDF Core License</td>
<td style="text-align: center;">NPD-CORE</td>
<td style="text-align: right;">$0.00</td>
</tr>
<tr style="background-color: #F8FAFC;">
<td>2</td>
<td>NextPDF Pro License</td>
<td style="text-align: center;">NPD-PRO</td>
<td style="text-align: right;">$299.00</td>
</tr>
</tbody>
<tfoot>
<tr style="background-color: #1E293B; color: #FFFFFF; font-weight: bold;">
<td colspan="3" style="text-align: right;">Grand total:</td>
<td style="text-align: right;">$299.00</td>
</tr>
</tfoot>
</table>
HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
$doc->save($out !== false ? $out : __DIR__ . '/html-table-layout.pdf');
echo "Wrote html-table-layout.pdf\n";

Sortie STDOUT attendue :

Wrote html-table-layout.pdf
  • Largeurs en pourcentage. Les pourcentages de width de colonne se résolvent par rapport à la largeur utilisée du tableau. L’algorithme de dimensionnement des colonnes normalise les pourcentages dont la somme n’atteint pas 100. Ne pars pas du principe que les largeurs en pixels seront exactes.
  • colspan. Une cellule fusionnée participe à la répartition de la largeur sur les colonnes qu’elle couvre. Un total en pied de tableau qui s’étend sur la plupart des colonnes est un motif courant et pris en charge.
  • Modèle de bordure. Dans certains fixtures de tableau, la valeur par défaut de border-collapse diffère de la valeur initiale du CSS. Définis-la directement lorsque le rendu des bordures compte.
  • Rowspan à cheval sur des sauts de page. Une cellule en rowspan peut franchir une limite de page ; le paginateur de rowspan fragmente alors cette cellule (ADR-007). Une cellule très haute qui ne peut pas être divisée peut lever UnsplittableContentException.
  • Cellules vides. Un <td> vide occupe quand même son emplacement dans la grille. Il n’est pas supprimé par fusion.

Le tampon du tableau est éphémère et limité à son conteneur. Le coût d’analyse est linéaire en fonction du nombre de cellules, auquel s’ajoute la passe de dimensionnement des colonnes en O(lignes x colonnes). Le budget est wall_ms: 1500, peak_mb: 96. Garde un seul tableau sous la limite de nœuds de l’ADR-020, soit 5,000 nœuds par contexte.

Extrait de la matrice de prise en charge CSS (lignes Vérifié uniquement)

Section intitulée « Extrait de la matrice de prise en charge CSS (lignes Vérifié uniquement) »

Cet extrait ne reprend que les lignes Vérifié de la matrice de prise en charge CSS dont l’exactitude a été auditée.

Module W3CNiveauStatutPreuves
CSS Table (css_tables_3)3Vérifiésrc/Html/Table/, tests/Unit/Html/Table/ + tests TableParser + PDF de référence
CSS Flexible Box Layout (css_flexbox_1)1Vérifiésrc/Html/Flex/, tests/Unit/Html/Flex/
CSS Grid Layout (css_grid_1)1Vérifiésrc/Html/Grid/, corpus WPT
CSS Cascading and Inheritance (css_cascade_3)3Vérifiésrc/Html/Cascade/

background-color, utilisé ici pour le rayage des lignes, est noté « Revendiqué » dans la matrice. D’après l’audit de la Phase 0, sa portée se limite à la cellule du tableau. Il est rendu pour les lignes de tableau, mais il n’est pas répertorié comme Vérifié.

Contraintes du streaming en une seule passe (ADR-001)

Section intitulée « Contraintes du streaming en une seule passe (ADR-001) »

Le tampon du tableau est l’exception documentée au modèle de streaming. Il est éphémère et borné ; ce n’est pas un DOM général. Ne compte pas sur un tableau pour fournir un contexte d’arbre à du contenu situé en dehors du tableau.

FormattingContextFactory::startTable() lit le CSS via le contrat de la couche de mise en page. Il n’analyse pas de $css[...] brut dans la répartition. La surface publique reste writeHtml().

Un contexte de formatage de tableau est borné à 5,000 nœuds et 20 niveaux de profondeur, dans le plafond de mémoire active de 50 Mo (ADR-020). Divise ou pagine un tableau très volumineux. Ne le rends pas comme un seul contexte surdimensionné.

Le balisage de tableau issu d’une entrée non fiable est borné par les mêmes limites d’éléments et d’imbrication que le reste du HTML. Valide les données de tableau qu’un utilisateur assemble. Le moteur de rendu n’exécute pas le contenu et, sous la politique par défaut, il ne récupère pas de ressources distantes arbitraires.

ÉnoncéSpécificationClausereference_id
Les largeurs de colonne utilisées sont déterminées par l’algorithme de dimensionnement des colonnes du tableau à la largeur utilisée du tableau.W3C CSS Table Level 3css_tables_3#x1.x4.x9.x3
En mode fixe, le contenu des cellules est ignoré pour le calcul de la largeur des colonnes.W3C CSS Table Level 3css_tables_3#x1.x4.x5.x1.p6

Cette recette montre comment NextPDF rend les tableaux HTML pris en charge. CSS Table Level 3 est Vérifié dans la matrice de prise en charge, et les autres modules CSS utilisés ici sont notés selon cette matrice.

Non applicable.