DataProcessor, GridElements und FAL Bilder im FluidTemplate (4 Beginners)

Jeder, der in letzter Zeit unter TYOP3 7 LTS in Verbindung mit Gridelements versucht hat, ein FlexForm Element vom Typ "inline" auf Bilder (FAL) zu erstellen, wird gemerkt haben, dass es nach dem anklicken des Bildes im File Wizard zu einer Alert-Box mit einem Fehler 500 kommt.

In Forge gibt es dazu auch ein Bugreport, der recht aufschlussreich ist:

https://forge.typo3.org/issues/71436

Am Ende  des Tickets findet sich auch ein Statement von Jo (Übersetzt und gekürzt):

"Bis auf Ausnahme von einfachen Eingabefeldern, Dropdown Listen und Checkboxen, sollten immer normale Inhaltselemente in den Spalten eines Gridelements verwendet werden, anstelle von Beziehungen in der FlexForm. FAL Bild-Relationen sollten daher über das Element Bilder angelegt werden."

Im Konkreten Fall bedeutet dies, dass man anstatt in der FlexForm ein FAL Inline Element erstellt, lieber ein Grid verwendet, in dem man eben normale TYPO3 Inhaltselemente verwendet. Viele werden jetzt an etwaige Nachteile denken: Der Redakteur hat hier viel zu viele Möglichkeiten, die dann nicht auf den Anwendungsfall treffen. Zum Beispiel weil der Redakteur im Bildelement zu viel einstellen kann, wie Bildgröße, Klick-Vergrößern oder Ausrichtung. Ausserdem steht man grundsätzlich vor dem Problem, das im Fluid Template des Gridelements nur der fertige HTML Code des Bildelements zur Verfügung steht, mit den ganzen Wrappern, Figure Tags und vieles mehr. Ein direkter Zugriff auf das eigentliche Bild, welches über die Tabelle "sys_file_reference" mit dem Bilddatensatz in der Tabelle "sys_file" verknüpft ist, ist im Fluid Template nicht möglich, zumindest nicht mit Hausmitteln von TYPO3 und Fluid. Oder?

Nun gibt es verschiedene Lösungsansätze. Einen habe ich bereits im Artikel "TYPO3 7 LTS Fluid Styled Content: Spezialmenü "Auflistung der Unterseiten" mit Bild aus Seiteneigenschaften" vorgestellt. Hier greife ich auf die Extension "vhs" zurück, um die Relation zwischen einer TYPO3 Seite und dem Bild aufzulösen. Mittlerweile bin ich aber ein großer Verfechter des "no-dependencies" Grundsatzes. Je weniger externe Ressourcen Du also in einem Projekt verwendest, umso besser ist das für Dich als Entwickler, und letztlich auch für Deinen Kunden. Insbesondere dann, wenn Updates anstehen.

Es gibt auch mit Boardmitteln die Möglichkeit, im Fluid Template auf FAL Bilder direkt zuzugreifen, auch wenn diese im Content Element, oder auch in einer Seite, über sys_file_reference verknüpft sind. Hierfür stehen in TYPO3 7 LTS sogenannte DataProcessors zur verfügung. Hört sich kompliziert an, ist es aber nicht. Für meinen Anwendungsfall lassen sich die DataProcessors rein über TypoScript nutzen. Somit können auch Integratoren, die sich nicht mit der Entwicklung von Extensions, im TYPO3 Core oder in php generell auskennen, diese Features nutzen. Derzeit (Stand TYPO3 7.6.6) stehen  diese vorgefertigten DataProcossors zur Verfügung, die direkt genutzt werden können:

TYPO3\CMS\Frontend\DataProcessing\CommaSeparatedValueProcessor
TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
TYPO3\CMS\Frontend\DataProcessing\GalleryProcessor
TYPO3\CMS\Frontend\DataProcessing\SplitProcessor

Natürlich besteht auch die Möglichkeit, eigene Projektdefinierte Prozessoren zu schreiben, die im Fluid Template dann genauso wie die bestehenden genutzt werden können. Ich möchte nun ein Beispiel geben, wie Du eine fast alltägliche Aufgabe recht einfach mit diesen DataProcessors bewältigen kannst (Beispiel aus einem aktuellen Projekt entnommen).

 
Aufgabenstellung: Umsetzung eines Inhaltselementes mit einem Bild und einem Text

Hört sich einfach an, ist es auch. Da ich in meinem Projekt ein fest definierten Inhaltstypen mit einem Bild und einem Text hatte, nutzte ich die Möglichkeit, mir dieses Thema genauer anzuschauen. Zusätzlich gab es die Vorgabe, dass dieses Element immer gleich aussehen muss, egal was der Redakteur so treibt. In diesem Fall erstellte ich ein spezielles Gridelement "Imagetextbox". Es gibt zwei Spalten, eine für ein Bild, die andere für den Text. Die Konfiguration für das Gridelement schaut so aus:

 

tx_gridelements {
    setup {
        imagetextbox {
            title = Bild-/Textbox Spezial
            icon = EXT:customtheme/Resources/Public/icons/imagetextbox.png
            frame = 3
            topLevelLayout = 0
            config{
                colCount = 1
                rowCount = 2
                rows.1 {
                    columns {
                        1 {
                            name = Bild (nur ein Bild)
                            colPos = 101
                            allowed = image
                        }
                    }
                }
                rows.2 {
                    columns {
                        1 {
                            name = Text mit überschrift
                            colPos = 102
                            allowed = text
                        }
                    }
                }
            }
        }
    }
}

 

 

Soweit so normal, das Gridelement hat nun 2 Spalten. Spalte 1 ist lediglich auf das Content Element "Bild" beschränkt, währenddessen Spalte 2 lediglich auf Elemente vom Typ Text beschränkt ist. Das TypoScript Setup sieht im einfachsten Fall dazu so aus:

 

tt_content.gridelements_pi1.20.10.setup {
    imagetextbox < lib.gridelements.defaultGridSetup
    imagetextbox {
        cObject = FLUIDTEMPLATE
        cObject {
            file = EXT:customtheme/Resources/Private/Templates/GridElements/Imagetextbox.html
        }
        outerWrap = |
    }
}

 

 

Wenn man die beiden Spalten im FluidTemplate ausgeben möchte, könnte man das HTML Template so gestalten:

 

<div class="row">
    <div class="col-xs-6 col-sm-6">
        <f:format.raw>{data.tx_gridelements_view_column_101}</f:format.raw>
    </div>
    <div class="col-xs-6 col-sm-6">
        <f:format.raw>{data.tx_gridelements_view_column_102}</f:format.raw>
    </div>
</div>

 

 

 

In den Variablen {data.tx_gridelements_view_column_101} und{data.tx_gridelements_view_column_102} steht wie gewohnt der fertige HTML Code zur Verfügung, dieser kann auch direkt ausgeben werden. Jedoch ist der HTML Code des Bildes in gewohnter Form mit den ganzen Wrappern und figure Tags. Ausserdem kann ich in diesem Code keine Änderungen vornehmen, wie zu Anfangs erwähnt. Stellt der Redakteur also eine Breit von 20 Pixeln ein, ist das Bild auch nur 20 Pixel breit.

In der Variable {data.tx_gridelements_view_raw_columns.101.0.uid} ist zwar eine UID gespeichert, allerdings ist das die UID des Inhaltselementes, in dem sich das Bild befindet. Diese UID gehört zur Tabelle tt_content, und keineswegs zur Tabelle sys_file. An dieser Stelle gibt es keine weitere Möglichkeit, aus den Variablen auszulesen, welche UID das Bild hat, um dieses zum Beispiel in einem  <f:image src="" /> Tag zu verwenden.

Hier greife ich nun auf die DataProcessors zurück. Für dieses Beispiel benötige ich aus der vorhandenen Sammlung die folgenden beiden DataProcessors:

TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
TYPO3\CMS\Frontend\DataProcessing\FilesProcessor

Den DataBaseQueryProcessor nutze ich, um zuerst die Content Elemente in der Spalte 101 des Grid Containers zu finden. Sobald ich die Content Elemente habe, nutze ich den FilesProcessor um an das eigentliche Bild zukommen. Das alles kann im TypoScript Setup des Gridelements gemacht werden, und ist gar nicht aufwendig, Mein neues, verbessertes TypoScript schaut nun so aus:

 

  imagetextbox < lib.gridelements.defaultGridSetup
    imagetextbox {
        cObject = FLUIDTEMPLATE
        cObject {
            file = EXT:customtheme/Resources/Private/Templates/GridElements/Imagetextbox.html
            dataProcessing {
                10 = TYPO3\CMS\Frontend\DataProcessing\DatabaseQueryProcessor
                10 {
                    table = tt_content
                    where.data = field:uid
                    where.wrap = tx_gridelements_columns = 101 AND tx_gridelements_container=|
                    orderBy = sorting
                    as = content

                    dataProcessing {
                        10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
                        10 {
                            references.fieldName = image
                            references.table = tt_content
                            as = image
                        }
                    }
                }
            }
        }
        outerWrap = |
    }

 

 

Data Prozessoren werden über dataProcessing {} eingeleitet, und es können beliebig viele hintereinander verwendet werden. Ausserdem ist das verschachteln von DataProcessors ebenfalls möglich. Durch die Angabe von as = content oder as = image kann ich bestimmen, über welche Variable ich auf die Daten zugreifen möchte.  In content sind meine tt_content Elemente enthalten. In dieser Variable sind dann auch die eigentlichen Bilder unter image gespeichert. Das FluidTemplate kann dann wie folgt aussehen:

 

<div class="image-text-box">
    <f:for each="{content}" as="content">
        <f:for each="{content.image}" as="image">
            <f:image class="img-responsive" src="{image.originalFile.uid}" alt="" title="" />
        </f:for>
    </f:for>
    <div class="text">
        <h5>{data.tx_gridelements_view_raw_columns.102.0.header}</h5>
        <f:format.html>{data.tx_gridelements_view_raw_columns.102.0.bodytext}</f:format.html>
    </div>
</div>

 

  

Wie Du siehst, habe ich volle Kontrolle über das oder die Bilder. Auch Die Überschrift und der Text wird direkt über die Variablen ausgelesen. Der Redakteur kann also in den Content Elementen einstellen was er möchte, die Ausgabe ist hier sichergestellt und wird immer gleich erscheinen. Um übrigens auf das erste Bild im ersten Content Element zugreifen zu können, kann auch der direkte Pfad im f:image Tag genutzt werden:

<f:image class="img-responsive" src="{content.0.image.0.originalFile.uid}" alt="" title="" />

Happy DataProcessing :-)