TYPO3 Flow: Render Fluid View as PDF File

Veröffentlicht von Sascha am

Um mit TYPO3 Flow ein Fluid View so zu rendern, dass es als PDF-File ausgegeben wird, ist nicht sehr einfach.
Ob die nun gezeigte Vorgehensweise auch Best Practise ist, kann ich nicht sagen. Allerdings funktioniert es und kommt mir als Flow Anfänger relativ sauber vor.

Da das Tutorial nun aus relativ vielen Schritten besteht, werde ich diese vorerst nur wenig Beschreiben.

Der Controller

Im Controller, von wo aus ein Fluid View als PDF gerendert werden soll:

# namespace Vendor\Package\Controller\Standard

// Hier sagen wir, dass das Format 'pdf' von diesem View gehandelt werden soll
protected $viewFormatToObjectNameMap = array(
        'pdf' => 'Vendor\Package\View\Standard\ExportCustomerDetailsPdf'
    );

/**
* Action die später die PDF downloaden soll
*/
public function downloadPdfAction() {
        $this->view->assign("foo", "bar");
        $this->view->setControllerContext($this->getControllerContext());
}

Die Custom View

Nun legen wir eine Datei im folgenden Verzeichnis an:
Classes/Vendor/Package/View/Standard/ExportCustomerDetailsPdf.php

# namespace Vendor\Package\View\Standard

use Vendor\Package\Pop\Pdf;

class ExportCustomerDetailsPdf extends \TYPO3\Fluid\View\TemplateView {

    /**
     * Renders the view
     *
     * @return string The rendered view
     * @api
     */
    public function render() {
        $this->setTemplatePathAndFilename("resource://Vendor.Package/Private/Templates/Standard/ExportCustomerDetails.html");
        $output = parent::render();

        $pageFormat = "A4";
        $sizeUnit = "mm";
        $pageOrientation = "L";

        $pdf = new Pdf($pageOrientation, $sizeUnit, $pageFormat);
        $pdf->SetFont("helvetica", "", 11);
        $pdf->AddPage();

        $pdf->writeHTML($output, true, false, false, false, '');

        $this->controllerContext->getResponse()->setHeader('Content-Type', 'application/pdf');

        return $pdf->Output('', 'D'); // Parameter D=>Display; F=>SaveAsFile
    }
}

Das Template

Kümmern wir uns nun um die View. Hier legen wir eine ganz normale Fluid View im Verzeichnis Resources\Templates\Standard\ExportCustomerDetails.html an und füllen diese mit unserem HTML (Fluid) Code.

PDF / TCPDF

Die im Classes/Vendor/Package/View/Standard/ExportCustomerDetailsPdf.php verwendet eine Klasse namens Pdf (aus dem Namespace Vendor\Package\Pop).
(Pop steht hierbei für ‚Plain old PHP-Object)

namespace Vendor\Package\Pop;

class Pdf extends \TCPDF {

}

Diese PDF Klasse extended nun von \TCPDF, welche eine (erstmal) nicht Flow Kompatible Library (Klasse) ist. Nicht Kompatibel heißt hier in erster Linie, dass es kein Flow Package davon existiert und auch nicht dem PSR-0 / PSR-4 Autoloading Standard folgt.

Hier muss nun etwas getrickst werden ;)

Zuerst laden wir TCPDF herunter und legen folgende Verzeichnisstruktur an:

Packages\Libraries\technik.com\tcpdf\ (tcpdf.php)
In dieses Verzeichnis kommt die aktuelle Version von TCPDF hinein, sodass die tcpdf.php Datei direkt innerhalb dieses Verzeichnisses gefunden werden kann.

TCPDF Autoloading Classmap

Um das Autoloading für TCPDF zu konfigurieren, modifizieren wir die Packages\Libraries\composer\autoload_classmap.php Datei.
Hier fügen wir folgende Zeilen hinzu:

    'TCPDF' => $vendorDir . '/tecnick.com/tcpdf/tcpdf.php',
    'TCPDF2DBarcode' => $vendorDir . '/tecnick.com/tcpdf/tcpdf_barcodes_2d.php',
    'TCPDFBarcode' => $vendorDir . '/tecnick.com/tcpdf/tcpdf_barcodes_1d.php',
    'TCPDF_COLORS' => $vendorDir . '/tecnick.com/tcpdf/include/tcpdf_colors.php',
    'TCPDF_FILTERS' => $vendorDir . '/tecnick.com/tcpdf/include/tcpdf_filters.php',
    'TCPDF_FONTS' => $vendorDir . '/tecnick.com/tcpdf/include/tcpdf_fonts.php',
    'TCPDF_FONT_DATA' => $vendorDir . '/tecnick.com/tcpdf/include/tcpdf_font_data.php',
    'TCPDF_IMAGES' => $vendorDir . '/tecnick.com/tcpdf/include/tcpdf_images.php',
    'TCPDF_IMPORT' => $vendorDir . '/tecnick.com/tcpdf/tcpdf_import.php',
    'TCPDF_PARSER' => $vendorDir . '/tecnick.com/tcpdf/tcpdf_parser.php',
    'TCPDF_STATIC' => $vendorDir . '/tecnick.com/tcpdf/include/tcpdf_static.php'

RenderingContext in der Object.yaml

Die Configuration\Object.yaml Datei in eurem Package muss noch um folgenden Eintrag ergänzt werden:

 
Vendor\Package\View\Standard\ExportCustomerDetailsPdf:
  properties:
    renderingContext:
      object: TYPO3\Fluid\Core\Rendering\RenderingContext

Routing / Testing

Damit nun auch alles funktioniert, muss die downloadPdfAction des StandardControllers aufgerufen werden, allerdings muss das Format auf PDF gestellt werden.
Das können wir in der Routes.yaml erledigen:

-
  name: 'Download Customer Details as PDF'
  uriPattern:    'vendor.package/standard/downloadpdf'
  defaults:
    '@package':    'Vendor.Package'
    '@controller': 'Standard'
    '@action':     'downloadPdf'
    '@format':     'pdf'

Fehlerbehebung

Sollte euch folgende Fehlermeldung aus dem Konzept bringen wollen:

[Semantical Error] The annotation "@class" in class TCPDF was never
  imported. Did you maybe forget to add a "use" statement for this
  annotation?

Ist die Lösung so einfach (wie vielleicht auf quick & dirty).
In allen TCPDF relevanten Dateien müssen die Annotations (bzw. alle Doc Block Kommentare) mit einem @ Zeichen entfernt werden.
Ein Alternativer (und auch etwas sauberer) Weg wäre, den Technik.com Namespace via der Settings.yaml aus der Reflection auszuschließen – was bei mir aber nicht funktionieren wollte.

Andere Packages

Dank eines Tipps aus der Flow Mailing list scheint es mittlerweile auch ein TCPDF Package auf Packagist (https://packagist.org/packages/tecnick.com/tcpdf) zu geben. Dies könnte ein noch etwas sauberer Weg sein, TCPDF zu integrieren.

Als Vorlage hierfür diente mir das TYPO3.Tcpdf Package, welches in seiner aktuellen Form leider nicht mehr kompatibel zu sein scheint.
https://git.typo3.org/Packages/TYPO3.TcPdf.git/tree

Hier noch ein weiterer Tipp zu einem funktionierendem Package:
https://packagist.org/packages/famelo/pdf

Kategorien: AllgemeinNeos Flow

%d Bloggern gefällt das:

Durch das Fortsetzen der Benutzung dieser Seite, stimmst du der Benutzung von Cookies zu. Weitere Informationen

Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Außerdem geben wir Informationen zu Ihrer Nutzung unserer Website an unsere Partner für soziale Medien, Werbung und Analysen weiter.

Schließen