Mehrseitige PDFs aus Fluid-Templates generieren
Wieso haben wir uns für mPDF entschieden?
Nach diversen Tests u.a. auch mit FPDM haben wir uns für die PHP-Bibliothek mPDF entschieden. Bei der Entscheidung haben uns vor allem folgende Features überzeugt:
- UTF-8 encoded HTML wird als Standard-Input akzeptiert
- CSS stylesheets
- Bilder (JPG, GIF, PNG, SVG, BMP und WMF)
- Orientierung (Landscape/Portrait)
- Support von HTML-Tags und Attributen
- Seitennummerierung
Wie wir mPDF integriert haben...
Unser Projekt wurde mit einer composer-basierten TYPO3 v9 umgesetzt. Dort konnten wir dann ganz einfach die mPDF-Bibliothek integrieren.
In unserer composer.json haben wir einfach mPDF und unsere eigene Extension hinzugefügt:
"require": {
"mpdf/mpdf": "^7.1",
"werkraum/wr_extension": "dev-master"
}
Danach wird einfach im Controller ein neues Objekt ($mpdf = new \Mpdf\Mpdf($mpdfConfig);) mit der gewünschten Konfiguration erzeugt.
**
* Sets variables for event PDF Output
*
* @param \Werkraum\WrExtension\Domain\Model\Event $event
* @return void
*/
public function generatePdfForEventAction(\Werkraum\WrExtension\Domain\Model\Event $event = null)
{
$this->view->assign('event', $event);
$renderedHtml = $this->view->render();
$date = $event->getStartDate();
$startdate = $date->format('d.m.Y - H.i') . ' Uhr';
$topic = $event->getTopic();
$topicTitle = $topic->getTitle();
$pdfTitle = $startdate . ' - Daten aller Teilnehmer';
$this->generatePdf($renderedHtml, $startdate, $topicTitle, $pdfTitle);
}
public function generatePdf($renderedHtml, String $startdate, String $topicTitle, String $pdfTitle, String $orientation = 'P')
{
$currentPath = PATH_site . 'typo3temp/pdf/';
if (!is_dir($currentPath) && !mkdir($currentPath, 0777, true) && !is_dir($currentPath)) {
// this is an error!
}
/**
* @see https://mpdf.github.io
*/
$mpdfConfig = [
'tempDir' => $currentPath,
'orientation' => $orientation,
'format' => 'A4',
'margin_left' => 0,
'margin_right' => 0,
'margin_top' => 0,
'margin_bottom' => 0,
];
try {
$mpdf = new \Mpdf\Mpdf($mpdfConfig);
$mpdf->WriteHTML($renderedHtml);
$mpdf->SetTitle($startdate . ' - ' . $topicTitle . ' - Zeugnisse');
$mpdf->SetAuthor('\'Name des Autors');
$mpdf->SetCreator('Name des Erstellers');
$mpdf->SetSubject($topicTitle . ' - ' . $startdate);
$mpdf->Output($startdate . ' - ' . $pdfTitle . '.pdf', true); // dest === true ? 'download' : 'write to file'
exit;
} catch (\Mpdf\MpdfException $e) { // Note: safer fully qualified exception name used for catch
// Process the exception, log, print etc.
echo $e->getMessage();
}
}
Beispiel aus dem Fluid-Template
<div class="container container-is-first">
<f:render partial="PdfTemplates/LogoHeader" arguments="{_all}"/>
<div class="col-xs-12">
<h1>{participant.event.topic.title}</h1>
</div>
<div class="row">
<div class="col-xs-3">
<p>Name / Geb.Datum:</p>
<p>Anschrift:</p>
</div>
<div class="col-xs-7">
<p>{participant.name} /
<f:format.date format="%d.%m.%Y">{participant.birthday}</f:format.date>
</p>
<p>{participant.address}, {participant.zip} {participant.city}</p>
</div>
</div>
</div>
So werden mehrere Seiten verknüpft und mit CSS versehen
<f:be.container pageTitle="Alle Zertifikate für einen Termin" includeCssFiles="{
0:'{f:uri.resource(path:\'Css/bootstrap.min.css\')}',
1:'{f:uri.resource(path:\'Css/Be_custom.css\')}'}">
<f:for each="{event.participants}" as="participant" iteration="iter">
<f:render partial="Backend/PdfTemplates/PageOne" arguments="{_all}"/>
<pagebreak/>
<f:render partial="Backend/PdfTemplates/PageTwo" arguments="{_all}"/>
<pagebreak/>
<f:render partial="Backend/PdfTemplates/PageThree" arguments="{_all}"/>
<f:if condition="!{iter.isLast}">
<pagebreak/>
</f:if>
</f:for>
</f:be.container>
Wir haben bei diesem Projekt ein Backend-Modul mit verschiedenen Listen und Funktionen erstellt. Unter anderem kann man dort für Teilnehmer einer Veranstaltung ein PDF herunterladen.