I’m trying to produce a PDF using TCPDF, and generally speaking everything is fine. I am producing a list of vehicles, and a couple of lists of information about each vehicle. These are created in the form of individual HTML tables. This works as expected, but with the problem that page breaks can occur within a vehicle record – so I might get the header at the bottom of the page, and the other two tables on the next page.
I’ve done a bit of reading and found that there are two options, either to set the `page-break-inside: avoid’, or to add ‘nobr=true’. I’ve found that for these to work, I have to set K_TCPDF_CALLS_IN_HTML to be true, I have done that and if I echo that value, it is set to 1. I am aware that TCPDF only parses parameters which are set with ” quotes rather than ‘ quotes. I have tried both methods in a div surrounding each vehicle record, and each time it makes no difference, the div is just split across a page if required. I have tried removing the font changes in case that breaks the div, but it didn’t help.
Here is a summary of my code, the TCPDF stuff is all pretty much based on the first example from their web site:
<?php
include("my_database.php");
// Include the main TCPDF library (search for installation path).
require_once('vendor/tecnickcom/tcpdf/tcpdf.php');
// Get the model details
$model_id = $_POST['model_id'];
$q1 = "select model, make from car_models left join car_makes on car_models.make_id = car_makes.id where car_models.model_id = ?";
$prep = $dbc->prepare($q1);
$ex = $prep->execute(array($model_id));
$model = $prep->fetchAll();
if (count($model) > 0) {
$mname = $model[0]['make'] . " " . $model[0]['model'];
$query = "select car_id from cars where model_id = ? and (hidden <> 2) order by registration";
$prep = $dbc->prepare($query);
$ex = $prep->execute(array($model_id));
if ($ex) {
$cars = $prep->fetchAll();
$vehcount = count($cars);
// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('My Name');
$pdf->SetTitle('My vehicle List');
$pdf->SetSubject('Vehicle List');
$pdf->SetKeywords('cars, list');
// set default header data
$pdf->SetHeaderData("mylogo.png", 40, 'My vehicle Register', $mname . " - " . $vehcount . " recorded", array(0,64,255), array(0,64,128));
$pdf->setFooterData(array(0,64,0), array(0,64,128));
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
// set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
// set some language-dependent strings (optional)
if (@file_exists(dirname(__FILE__).'/lang/eng.php')) {
require_once(dirname(__FILE__).'/lang/eng.php');
$pdf->setLanguageArray($l);
}
// ---------------------------------------------------------
// set default font subsetting mode
$pdf->setFontSubsetting(true);
// Add a page
// This method has several options, check the source code documentation for more information.
$pdf->AddPage();
// I've tried both of these, without success.
//$pbopen = "<div style="page-break-inside:avoid;">";
$pbopen = "<div nobr="true">";
$pbclose = "</div>";
foreach($cars as $car) {
$carinfo = getCarInfoAsHTML($dbc, $car['car_id']);
if (is_array($carinfo)) {
$pdf->SetFont('helvetica', '', 14, '', true);
$pdf->writeHTML($pbopen . $carinfo['header'], true, false, false, false, '');
$pdf->SetFont('helvetica', '', 10, '', true);
$pdf->writeHTML($carinfo['owner'], true, false, false, false, '');
$pdf->writeHTML($carinfo['notes'], true, false, true, false, '');
$pdf->writeHTML("<hr />" . $pbclose, true, false, true, false, '');
// ---------------------------------------------------------
// Close and output PDF document
// This method has several options, check the source code documentation for more information.
}
else {
echo "Car not found. ";
}
}
$pdf->Output($mname . ".pdf", 'I');
}
}
else {
echo "Invalid model id";
}
?>
I’ve taken out stuff that I think is irrelevant here, but I hope I’ve left enough in place to help someone see what I’m doing incorrectly. This is typical (but edited for privacy) of what each string returned will contain:
'header' => string '<table cellspacing='0' cellpadding='1'><tr><td style="width: 30%">Registration</td><td style="width: 70%">ABC 123V </td></tr><tr><td>Date of Registration</td><td></td></tr><tr><td>Model</td><td>Ford Fiesta</td></tr><tr><td>VIN</td><td> / </td></tr><tr><td>Last VED / MOT / V5</td><td>SORN / Not recorded / </td></tr></table>' (length=334)
'owner' => string '<h3>Owner Sequence</h3><table><tr><th style="width: 10%"> </th><th style="width: 32%">Owner</th><th style="width: 20%">Area</th><th style="width: 18%">From</th><th>To</th></tr><tr><td>1</td><td>Bill Clinton</td><td>Northern Ireland</td><td></td><td></td></tr></table>' (length=279)
'notes' => string '<h3>Notes</h3><table><tr><th style="width: 25%">Date</th><th style="width: 75%">Notes</th></tr><tr><td style="width:25%;"> </td><td style="width: 75%">Rally car. </td></tr><tr><td style="width: 25%;">2023-03-20</td><td style="width: 75%">Last-taxed-date changed from '' to 'SORN'</td></tr></table>' (length=306)
My code should therefore create a separate <div>
for each vehicle, inside which is one, two or three HTML tables (not all have a list of owners, or any notes). It works well, but it splits a vehicle record across a page break which I’d like to avoid. I’m sure I am missing something simple, but I can’t see what it is.