Skip to content
Dragon edited this page Jun 3, 2026 · 4 revisions

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.

Basic usage

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, 15);
$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

Page::table() parameters

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().

The method returns a TableResult with public properties rowCount, pageCount, page, x, and y.

Column

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.
->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').

Cell types

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 to TextAlign::CENTER / VerticalAlign::MIDDLE. A plain path string is accepted as $src (equivalent to Image::fromFile($path)).

TableStyle

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.

TableBorders

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.

Conditional cell styling (withCellStyle)

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).

Automatic page-break and header repeat

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.

Limitations

  • No cell spanning: colspan and rowspan are not supported.
  • No content-derived auto-width: every column must have an explicit ->width() or ->fill() policy.

See also

Clone this wiki locally