-
Notifications
You must be signed in to change notification settings - Fork 0
Tables
Page::table() renders a data grid from an array (or any iterable) of associative rows. Columns are defined with Column value objects that describe which row key to read, a header label, a width policy, and optional alignment overrides. The renderer reuses the cell and image pipeline, supports automatic page-break with repeated header rows, zebra striping, configurable borders, and per-cell conditional styling.
use DragonOfMercy\PhpPdf\Color;
use DragonOfMercy\PhpPdf\Document;
use DragonOfMercy\PhpPdf\Image;
use DragonOfMercy\PhpPdf\Table\Cell;
use DragonOfMercy\PhpPdf\Table\CellStyle;
use DragonOfMercy\PhpPdf\Table\Column;
use DragonOfMercy\PhpPdf\Table\TableBorders;
use DragonOfMercy\PhpPdf\Table\TableStyle;
use DragonOfMercy\PhpPdf\TextAlign;
$doc = new Document();
$doc->setAutoPageBreak(true);
$page = $doc->addPage();
$page->setFont($doc->getFont('Helvetica'), 10);
// One fill column takes the remaining width; two fixed columns get exact mm.
$columns = [
Column::of('avatar', '')->width(14)->align(TextAlign::CENTER),
Column::of('name', 'Name')->fill(),
Column::of('role', 'Role')->width(40),
Column::of('salary', 'Salary')->width(32)->align(TextAlign::RIGHT),
];
// Scalars are shorthand for Cell::of($value). Cell::image() embeds a raster or SVG image.
$rows = [
['avatar' => Cell::image(Image::fromFile('avatar1.png'), w: 10), 'name' => 'Alice Martin', 'role' => 'Engineer', 'salary' => '95,000'],
['avatar' => Cell::image(Image::fromFile('avatar2.png'), w: 10), 'name' => 'Bob Nguyen', 'role' => 'Designer', 'salary' => '82,000'],
['avatar' => Cell::image(Image::fromFile('avatar3.png'), w: 10), 'name' => 'Carol Schmidt', 'role' => 'Manager', 'salary' => '110,000'],
];
$style = TableStyle::default()
->withHeader(fill: Color::gray(220), bold: true)
->withBorder(TableBorders::GRID)
->withZebra(Color::rgb(255, 255, 255), Color::gray(247))
->withCellStyle(function (mixed $value, array $row, Column $col): ?CellStyle {
if ($col->key === 'salary' && is_string($value) && (int) str_replace(',', '', $value) > 100000) {
return CellStyle::new()->withTextColor(Color::rgb(180, 0, 0))->withBold(true);
}
return null;
});
$result = $page->table($columns, $rows, x: 15, y: 30, width: 180, style: $style);
// $result->rowCount -- number of data rows rendered
// $result->pageCount -- number of pages the table spans
// $result->page -- last Page instance used (useful for further drawing)
// $result->x / ->y -- cursor position after the last row| Parameter | Type | Description |
|---|---|---|
$columns |
Column[] |
Column definitions (at least one required). |
$rows |
iterable |
Associative arrays. Scalar values become Cell::of() automatically. |
x |
float |
Left edge in the document unit (mm by default). |
y |
float |
Top edge in the document unit. |
width |
float |
Total table width. Fixed columns are subtracted first; fill columns share the remainder. |
style |
TableStyle |
Presentation and pagination config. Optional; defaults to TableStyle::default(). |
ln |
NextPosition |
Cursor advance after the table. Defaults to BELOW (cursor moves to the table's left edge, just under the last row) so content flows beneath it. Pass NONE to leave the cursor untouched. |
The method returns a TableResult with public properties rowCount, pageCount, page, x, and y. Regardless of ln, TableResult::$y always reports the position just below the last row, so you can anchor a totals block there explicitly.
Column::of(string $key, ?string $header = null) is the named constructor. Chain the following methods (each returns a new immutable Column):
| Method | Description |
|---|---|
->width(float $mm) |
Fixed width in the document unit. Mutually exclusive with ->fill(). |
->fill(int $weight = 1) |
Fill policy: takes a proportional share of the remaining width. Multiple fill columns divide by weight. Mutually exclusive with ->width(). |
->align(TextAlign $align) |
Default horizontal alignment for data cells in this column (LEFT, CENTER, RIGHT, JUSTIFY). JUSTIFY fills wrapped cells to the column width, leaving each cell's last line ragged - see Justified text. |
->verticalAlign(VerticalAlign $v) |
Default vertical alignment for data cells. |
->padding(CellPadding $p) |
Default padding override for every cell in this column. |
The $key property is public and readable in callbacks (e.g. $col->key === 'salary').
A row value may be:
-
Scalar - converted implicitly to
Cell::of((string) $value). -
Cell::of(string|\Stringable $text)- text cell with optional style overrides:->bold(),->align(),->verticalAlign(),->textColor(),->fill(),->padding(). -
Cell::image(Image|string $src, ?float $w = null, ?float $h = null)- image cell. Aspect ratio is preserved and the image is clamped to the inner cell box. Defaults toTextAlign::CENTER/VerticalAlign::MIDDLE. A plain path string is accepted as$src(equivalent toImage::fromFile($path)).
Build from TableStyle::default() and chain with* methods. All methods return a new immutable TableStyle.
| Method | Description |
|---|---|
->withHeader(?Color $fill, bool $bold, ?Color $textColor) |
Header row appearance. |
->withBorder(TableBorders $borders) |
Border preset (see below). |
->withBorderStyle(Border $b) |
Line appearance (width, color, style) applied to all drawn borders. |
->withZebra(Color $even, Color $odd) |
Alternate row fills. Even rows (0, 2, ...) use $even; odd rows use $odd. |
->withRepeatHeader(bool $repeat) |
Whether the header row is re-drawn at the top of each continuation page. Default: true. |
->withCellStyle(callable $fn) |
Per-cell conditional styling callback (see below). |
->withRowPadding(CellPadding $p) |
Default padding applied to every data cell. |
| Case | Effect |
|---|---|
GRID |
All cell edges drawn (default). |
HORIZONTAL |
Horizontal rules between rows only. |
HEADER_UNDERLINE |
Single rule under the header row only. |
NONE |
No borders. |
The callable receives (mixed $value, array $row, Column $col) and must return CellStyle|null. A non-null return overrides style for that cell only:
->withCellStyle(function (mixed $value, array $row, Column $col): ?CellStyle {
if ($col->key === 'status' && $value === 'overdue') {
return CellStyle::new()->withFill(Color::rgb(255, 220, 220))->withBold(true);
}
return null;
})CellStyle::new() is immutable and supports ->withTextColor(Color), ->withFill(Color), ->withBold(bool), and ->withAlign(TextAlign).
When Document::setAutoPageBreak(true) is active, a new page is started automatically whenever a row does not fit the remaining space. The header row is re-drawn on the new page unless ->withRepeatHeader(false) is set.
- No cell spanning:
colspanandrowspanare not supported. - No content-derived auto-width: every column must have an explicit
->width()or->fill()policy.
MIT licensed. Source on GitHub - if phppdf helps you, you can buy me a coffee.