Mehrseitige PDFs aus Fluid-Templates generieren

Wir haben hier mehrere PDF-Seiten aus einem Fluid-Template generiert

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.

Bei Fragen oder Interesse an der Umsetzung eines ähnlichen Projektes...

Kontaktieren Sie uns!

 

Hat Dir der Artikel gefallen?