Transactions (TransactionManager)
Transactions let you take a snapshot of the document state, render content speculatively, and then decide whether to keep or discard the result. This is the primary mechanism for "try-fit" layout logic.
API Overview
| Method | Description | Returns |
|---|---|---|
startTransaction() | Take a snapshot of the current document state | static |
commitTransaction() | Discard the snapshot and keep all changes | static |
rollbackTransaction() | Restore the document to the snapshot | static |
All three methods return static for fluent chaining.
How It Works
When you call startTransaction(), the TransactionManager stores a full copy of the current document state — cursor position, page count, content buffers, and internal counters. You then render content as normal.
- Commit discards the stored snapshot. The rendered content stays in the document.
- Rollback replaces the current state with the stored snapshot. Everything rendered since
startTransaction()is discarded.
Basic Example
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
->addPage()
->setFont('Helvetica', '', 12);
// Try to fit a block on the current page
$pdf->startTransaction();
$startPage = $pdf->getPage();
$pdf->multiCell(0, 6, $longText);
if ($pdf->getPage() > $startPage) {
// Content overflowed to next page — rollback and try differently
$pdf->rollbackTransaction();
$pdf->addPage();
$pdf->multiCell(0, 6, $longText);
} else {
// Content fits — keep it
$pdf->commitTransaction();
}Use Cases
Fitting Content in a Remaining Space
The most common use case is checking whether content fits on the current page before committing it:
use Yeeefang\TcpdfNext\Core\Document;
$pdf = Document::create()
->addPage()
->setFont('Helvetica', '', 10);
foreach ($sections as $section) {
$pdf->startTransaction();
$startPage = $pdf->getPage();
$pdf->setFont('Helvetica', 'B', 14)
->cell(0, 8, $section['title'], newLine: true)
->setFont('Helvetica', '', 10)
->multiCell(0, 5, $section['body']);
if ($pdf->getPage() > $startPage) {
$pdf->rollbackTransaction();
$pdf->addPage();
$pdf->setFont('Helvetica', 'B', 14)
->cell(0, 8, $section['title'], newLine: true)
->setFont('Helvetica', '', 10)
->multiCell(0, 5, $section['body']);
} else {
$pdf->commitTransaction();
}
}Measuring Content Height
Use a transaction to measure how much vertical space content will consume without actually placing it:
$pdf->startTransaction();
$startY = $pdf->getY();
$pdf->multiCell(0, 5, $text);
$endY = $pdf->getY();
$height = $endY - $startY;
$pdf->rollbackTransaction();
// Now use $height for layout decisionsImportant Constraints
No Nesting
Nested transactions are not supported. Calling startTransaction() while a transaction is already active will throw an exception. Always commit or rollback before starting a new transaction.
Performance Impact
A transaction stores a full snapshot of the document state. For documents with many pages and large content buffers, this can temporarily double memory usage. Keep transaction blocks as small as possible — snapshot, render, decide, then commit or rollback immediately.
Best Practices
- Keep the code between
startTransaction()andcommitTransaction()/rollbackTransaction()minimal. - Always ensure every
startTransaction()is paired with exactly onecommitTransaction()orrollbackTransaction(). - Do not perform file I/O or send output within a transaction block — only document mutations can be rolled back.
- Prefer measuring small sections rather than wrapping entire document generation in a transaction.