-
Notifications
You must be signed in to change notification settings - Fork 0
Cells
cell() is the workhorse of the page layout API. It draws a rectangular text block at a given position, optionally with a border, fill, and explicit or auto-derived size. Use it for everything from simple labels to full table-like row/column grids.
use DragonOfMercy\PhpPdf\Border;
use DragonOfMercy\PhpPdf\BorderStyle;
use DragonOfMercy\PhpPdf\Fit;
use DragonOfMercy\PhpPdf\TextAlign;
use DragonOfMercy\PhpPdf\VerticalAlign;
$page->setFont(Font::helvetica(), 12);
// Header: centered, bordered, filled.
$page->cell(
x: 20, y: 20, w: 170, h: 10,
text: 'Invoice #2026-001',
border: Border::all()->withWidth(0.3),
fill: Color::rgb(242, 242, 242),
align: TextAlign::CENTER,
verticalAlign: VerticalAlign::MIDDLE,
);
// Wrapping prose with a dashed border; height determined by content.
$result = $page->cell(
x: 20, y: 35, w: 170,
text: 'Long paragraph that wraps automatically across multiple lines.',
border: Border::all()->withStyle(BorderStyle::DASHED),
);
// Right-aligned with a custom text color, positioned below the previous cell.
$page->cell(
x: 20, y: $result->y + 2, w: 170, h: 8,
text: 'Total: 1234.56 EUR',
textColor: Color::rgb(192, 0, 0),
align: TextAlign::RIGHT,
);
// Long word condensed to fit a narrow cell (no wrapping).
$page->cell(
x: 20, y: 80, w: 40, h: 8,
text: 'Antidisestablishmentarianism',
border: Border::all(),
fit: Fit::CONDENSE,
);
// Width auto-derived from the longest text line plus horizontal padding.
$page->cell(x: 20, y: 95, text: 'Auto-sized label', border: Border::all());| Parameter | Type | Description |
|---|---|---|
x |
float |
Left edge in the document unit; also sets the row-start anchor for NEWLINE
|
y |
float |
Top edge in the document unit |
w |
float |
Width; omit to auto-size from text (requires non-empty text) |
h |
float |
Height; omit to auto-size from content |
text |
string |
Cell content; \n forces a line break |
border |
Border |
Border descriptor; Border::all(), Border::none(), Border::sides(...)
|
fill |
Color |
Background fill color |
align |
TextAlign |
Horizontal alignment (LEFT, CENTER, RIGHT, JUSTIFY) |
verticalAlign |
VerticalAlign |
Vertical alignment (TOP, MIDDLE, BOTTOM) |
textColor |
Color |
Text color override for this cell |
fit |
Fit |
Overflow strategy: NONE (word-wrap, default), CONDENSE (Tz scaling), SHRINK (reduce font size) |
padding |
CellPadding|float |
Per-call padding override |
ln |
NextPosition |
Cursor position after rendering (see Cursor flow) |
When w is omitted the cell auto-sizes its width to fit the longest line of text plus horizontal padding. Omitting both w and text raises an error.
TextAlign::JUSTIFY fills each wrapped line to the cell's inner width by widening the gaps between words. The last line of every paragraph (text between \n, including a single short line) stays left-aligned, following standard typographic practice. Justification needs a fixed width and the default Fit::NONE word-wrap: an auto-width cell (no w), or Fit::CONDENSE / Fit::SHRINK, falls back to left alignment. It works the same for the standard 14 fonts and embedded custom fonts.
$page->cell(
w: 80,
text: 'Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt.',
align: TextAlign::JUSTIFY,
);cell() returns a CellResult value object:
| Property | Type | Description |
|---|---|---|
x |
float |
Right edge of the cell (bottom-right anchor, in the document unit) |
y |
float |
Bottom edge of the cell (bottom-right anchor, in the document unit) |
effectiveWidth |
float |
Resolved width (useful when the cell was auto-sized from text) |
height |
float |
Rendered height in the document unit |
lineCount |
int |
Number of text lines rendered |
brokenWords |
int |
Count of words that were force-broken to fit the width |
textOverflow |
bool |
true if text was clipped because it exceeded the cell area |
page |
Page |
Page on which the cell was actually emitted (may differ when auto-page-break triggered a new page) |
Cell padding controls the space between the cell border and its text content. Values are in the document unit.
use DragonOfMercy\PhpPdf\CellPadding;
// Uniform: same value on all four sides.
$page->setCellsPadding(2);
// Via the CellPadding value object - three named constructors:
$page->setCellsPadding(CellPadding::all(2)); // top=right=bottom=left=2
$page->setCellsPadding(CellPadding::symmetric(1, 4)); // vertical=1, horizontal=4
$page->setCellsPadding(CellPadding::sides(top: 1, bottom: 3)); // omitted sides default to 0
// One-shot override on a single cell:
$page->cell(x: 20, y: 20, w: 60, h: 8, text: 'Tight',
padding: CellPadding::sides(left: 4, right: 1));
// Document-level default applied to pages created after this call:
$doc->setDefaultCellsPadding(CellPadding::symmetric(2, 4));The built-in default is 2 pt on all sides when neither the page nor the document configures one. Negative padding values raise PdfException at construction time.
Border::all(), Border::none(), and Border::sides(...) leave the line width unset, deferring to a configurable default. The initial value is 0.25 in the document unit. Border::withWidth(x) always wins over the default.
$doc->setDefaultBorderWidth(0.5); // document-wide default
$page->setDefaultBorderWidth(1.0); // per-page override (pass null to revert to the document default)
$page->cell(x: 20, y: 20, w: 50, h: 8, text: 'Default 1.0', border: Border::all());
$page->cell(x: 20, y: 30, w: 50, h: 8, text: 'Explicit', border: Border::all()->withWidth(0.3));cell() can drive an internal cursor so subsequent calls can omit x and y. The ln parameter (a NextPosition enum) controls where the cursor is left after rendering. Without ln (or with NextPosition::NONE), the cursor is unchanged.
use DragonOfMercy\PhpPdf\NextPosition;
$page->setCellsPadding(2);
// Row of three cells: only the first call sets x/y.
// The first two pass ln: RIGHT to continue the row;
// the third uses NEWLINE to drop to the next row.
$page->cell(x: 20, y: 20, w: 40, h: 8, text: 'Name', border: Border::all(), ln: NextPosition::RIGHT);
$page->cell( w: 60, h: 8, text: 'Email', border: Border::all(), ln: NextPosition::RIGHT);
$page->cell( w: 30, h: 8, text: 'Phone', border: Border::all(), ln: NextPosition::NEWLINE);
// Cursor is now at (20, 28), ready for the next row.
$page->cell(w: 40, h: 8, text: 'Alice', border: Border::all(), ln: NextPosition::RIGHT);
$page->cell(w: 60, h: 8, text: 'alice@host.test', border: Border::all(), ln: NextPosition::RIGHT);
$page->cell(w: 30, h: 8, text: '+41 21 000 0000', border: Border::all());| Case | Cursor after rendering |
|---|---|
RIGHT |
Moves to the right edge of the cell just drawn (continue the row) |
NEWLINE |
Returns to the x at which the row started, advances y by the rendered height |
BELOW |
Stays at the cell's left edge, advances y (vertical stack at the same column) |
NONE |
Cursor is left unchanged (useful for stamps or overlays) |
An explicit x passed to cell() always becomes the new row-start anchor used by NEWLINE. Calling cell() without x before any cursor is set raises an error.
The cursor is also exposed directly, useful for seeding a position, jumping mid-flow, or reading after a stack of cells:
$page->setXY(20, 20); // seed the cursor and set the row-start anchor
$page->cell(w: 50, h: 8, text: 'Header', ln: NextPosition::NEWLINE);
$y = $page->getY(); // bottom of the row, ready for the body| Method | Description |
|---|---|
getX(): float |
Current cursor x (document unit) |
getY(): float |
Current cursor y (document unit) |
setX(float $x) |
Set cursor x; also redefines the row-start anchor |
setY(float $y) |
Set cursor y |
setXY(float $x, float $y) |
Set both; also redefines the row-start anchor |
MIT licensed. Source on GitHub - if phppdf helps you, you can buy me a coffee.