Listenansicht und Detailansicht mit typoscript
Kommunikation eines fiktiven Projektes:
Kunde: “ ... und dann möchten wir hier auf der Seite noch ein paar Produkte als Liste darstellen und wenn man drauf klickt, soll eine Detailansicht kommen ...”
Entwickler: “Ach so, kein Problem. Da legen wir eine extra Tabelle an, erstellen ein Repository mit Models und einen Controller mit listaction und detailaction. Dann erstellen wir eine Seite mit der Listenansicht und eine mit der Detailansicht”.
Kunde: “Okay. Ich verstehe kein Wort - ich vertraue dir - mach weiter”.
Etwas später ...
Redakteur: “Ich verstehe nicht, warum ich einen extra sys_folder anlegen muss, in dem meine Produkte liegen. Und warum ist da so ein komisches Plugin auf der Seite mit der Listenansicht? Warum brauche ich eine extra Seite für die Details?"
Solche oder ähnliche Diskussionen hat wahrscheinlich jeder schon einmal geführt und hoffentlich daraus gelernt.
Im Folgenden zeige ich, wie man diese Probleme mit einfachen Mitteln lösen kann. Ich bin mir bewusst, dass eine extbase-Lösung viel mächtiger ist. Dennoch finde ich die Einfachheit dieser Lösung bestechend und sie zeigt einmal mehr die Stärken von typoscript.
Was soll genau passieren?
Das Ziel ist eine Seite mit einfachen Inhaltselementen für Produkte. Dazu erstellen wir ein einfaches tt_content Element mit einem Feld für den Teaser, einem Feld für die Detailinformationen und einem Bild. Zusätzlich soll das Element ein Slug-Feld haben, um eine lesbare Detail-URL zu erzeugen.
Das Ganze wird auf einer normalen Seite platziert.
Klickt man im Frontend auf ein Element, wird die Detailansicht angezeigt.
Zusätzlich sollte ein Backlink vorhanden sein.
Zuerst das Backend
Da ich es einfacher und übersichtlicher finde, verwende ich mst_yaml2tca, um das Inhaltselement im Backend zu erstellen.
Ich hoffe, der Code spricht für sich.
Da ich zwei neue Spalten in tt_content erstellt habe, muss die Datenbank angepasst werden:
ddev typo3 database:updateschema
columns:
tt_content:
slug:
label: 'Slug'
config:
type: slug
generatorOptions:
fields:
- header
fieldSeparator: '/'
prefixParentPageSlug: true
description:
label: 'Description'
config:
type: text
enableRichtext: true
contentElements:
new_mst_site_basic_elements:
title: "New Basic elements yaml"
elements:
product:
title: "Product"
description: "Product"
icon: "content-extension"
config:
columnsOverrides:
bodytext:
config:
type: text
enableRichtext: true
showitem:
-
title: "LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:general"
fields:
- "--palette--;;general"
- "--palette--;;header"
- "slug"
- "description"
- "bodytext"
- "media"
-
title: "LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:tabs.appearance"
fields:
- "--palette--;;frames"
-
title: "LLL:EXT:core/Resources/Private/Language/Form/locallang_tabs.xlf:access"
fields:
- "--palette--;;hidden"
- "--palette--;;access"
Das sieht dann im Backen in etwa so aus
typoscript, HTML & route enhancer
Damit im frontend etwas erscheint benötigen wir ein paar Zeilen typoscript und ein Fluid-Template. Außerdem noch einen Route enhancer der die URL schön macht.
Da ich kein Freund von viel Text bin - hier ist Code:
tt_content {
product =< lib.contentElement
product {
layoutRootPaths.20 = EXT:mst_site/Resources/Private/Components/Layouts/
partialRootPaths.20 = EXT:mst_site/Resources/Private/Components/Partials/
templateRootPaths.20 = EXT:mst_site/Resources/Private/Components/Templates/
templateName = Product
dataProcessing {
10 = TYPO3\CMS\Frontend\DataProcessing\FilesProcessor
10 {
references.fieldName = media
as = media
}
}
variables {
display = TEXT
display{
value = teaser
override.cObject = TEXT
override.cObject {
value = false
if.isTrue.data = GP:product|detail
override.cObject = TEXT
override.cObject {
value = detail
if.equals.data = GP:product|detail
if.value.field = uid
}
}
}
}
}
}
<html xlmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers" data-namespace-typo3-fluid="true">
<f:switch expression="{display}">
<f:case value="detail">
<div class="mstitb_col mstitb_col--100">
<f:link.page>zurück</f:link.page>
<div class="mstitb_product">
<h4>{data.header}</h4>
<f:if condition="{media.0}">
<f:image image="{media.0}" alt="{media.0.alternative}" width="800px" />
</f:if>
<f:format.html>{data.bodytext}</f:format.html>
</div>
</div>
</f:case>
<f:case value="teaser">
<div class="mstitb_col mstitb_col--33">
<div class="mstitb_product">
<f:link.typolink parameter="{data.pid}" additionalParams="&product[detail]={data.uid}">
<h4>{data.header}</h4>
<f:if condition="{media.0}">
<f:image image="{media.0}" alt="{media.0.alternative}" width="300px" />
</f:if>
<f:format.html>{data.description}</f:format.html>
</f:link.typolink>
</div>
</div>
</f:case>
</f:switch>
</html>
routeEnhancers:
Products:
type: Plugin
namespace: 'product'
routePath: '/{product_detail}'
_arguments:
product_detail: 'detail'
aspects:
product_detail:
type: PersistedAliasMapper
tableName: tt_content
routeFieldName: slug
Zusammenfassung
Man könnte das Ganze natürlich auch ohne zusätzliche Zeile machen, indem man die Detailansicht im Seitenbaum ablegt und auf der Listenansicht ein Menüelement mit Unterseiten platziert.
Aber vielleicht ist das in einem gewachsenen Projekt nicht möglich, weil es die gesamte Navigation ändern würde.
Ich bezweifle allerdings, dass dieser Vorschlag jemals produktiv umgesetzt wird. Falls doch, würde ich mich über einen entsprechenden Hinweis freuen.
Comments
No Comments