Hallo zusammen,
kürzlich hat die Agentur Einmahl WebSolution sich damit befasst, die Extension tx_news für TYPO3 einzubinden und für die News auf unserer Webseite zu konfigurieren. In der Version 9.5.X werden Extensions, wie z.B. realurl nicht mehr benötigt, da derartige Funktionen hier im TYPO3-Core integriert sind. Diese ändern die URLs einiger Extensions, wie tx_news aber nicht, weshalb handlungsbedarf besteht. Hierbei war Recherche nötig und wir haben festgestellt, dass es viele Anleitungen und Erklärungen gibt, die genau diese Angelegenheit thematisieren, jedoch nur einen Parameter in der URL zulassen.
So wird zum Beispiel aus folgender URL:
einmahl.de/ueber-uns/news/detail?tx_news_pi1[action]=detail&tx_news_pi1[controller]=News&tx_news_pi1[news]=1&cHash=...
diese URL generiert:
einmahl.de/ueber-uns/news/detail/ein-neuer-blog-entsteht
Hier wurde der Titel des News-Posts als Parameter an die URL angehängt, was an sich schonmal ganz gut aussieht. Jetzt stellt sich nur das Problem, dass diese Titel doppelt und dreifach vergeben werden können, was zu dem Fehler führt, dass jeder dieser Posts dieselbe URL generieren würde. Wir haben dieses Problem gelöst, indem wir die ID des Posts an den Namen anhängen lassen haben, was zu folgender URL führt:
einmahl.de/ueber-uns/news/detail/ein-neuer-blog-entsteht-1
Wie funktioniert das?
Wie dies im Detail geht, erklären wir nun (Am Ende des Beitrags folgt noch einmal eine Gesamtansicht des Codes).
Die einzige Datei, die dafür geändert werden muss, ist die config.yaml. Diese findet ihr im Verzeichnis "typo3conf/sites/eure-seite/config.yaml". Hier fügt ihr folgenden Code ein:
routeEnhancers: News: type: Extbase limitToPages: [55] extension: News plugin: Pi1
Mit den routeEnhancers kann man die Generierung der URLs durch TYPO3 beeinflussen. Als nächstes wird eine eindeutige Kennung angegeben. In unserem Fall wäre das "News". Darauf folgen die generellen Einstellungen:
- Der type gibt an, um was für einen Enhancer es sich handelt. Hier gibt es "Simple", "Plugin" und "Extbase", sowie die Möglichkeit, eigene Enhancer zu wählen, die in der Datei "typo3conf/AdditionalConfiguration.php" registriert werden müssen. Die Extension tx_news benötigt hier den type "Extbase", weshalb wir auf die anderen Möglichkeiten nicht weiter eingehen werden.
- limitToPages sagt aus, welche Seiten von der URL-Generierung betroffen sein sollen. In unserem Beispiel ist dies die Seite mit der ID 55 (im Seitenbaum des TYPO3-Backends zu finden). Es ist auch möglich, hier mehrere Seiten anzugeben. Das würde folgendermaßen aussehen: "limitToPages: [55, 66, 77]". Dieser Wert ist optional; wenn limitToPages nicht angegeben wird, wird der Enhancer auf jede Seite angewendet, weshalb es bei speziellen Extensionseiten performancetechnisch sinnvoll ist, das Routing auf diese zu begrenzen.
- Mit extension ist hier der Extension-Key der betreffenden Extension gemeint (in unserem Falle "News"). Zu beachten ist, dass der Extension-Key in UpperCamelCase angegeben werden muss. Heißt, aus dem Extension-Key "meine_neue_extension" würde "MeineNeueExtension" werden.
- Unter plugin wird der Name des Plugins der Extension angegeben. Bei der News-Extension lautet dieser "Pi1".
routes und aspects
Nun haben wir den routeEnhancer vorbereitet. Jetzt müssen wir ihm sagen, was er genau zu tun hat. Dafür benötigt ihr die routes und aspects. routes erweitern existierende URLs mit Argumenten, während aspects dazu benutzt werden, diese Argumente zu modifizieren. Für den einfachen Titel der Newsposts in der URL würde folgender Code reichen:
routes: - routePath: '/{news-title}' _controller: 'News::detail' _arguments: news-title: 'news' aspects: news-title: type: PersistedAliasMapper tableName: 'tx_news_domain_model_news' routeFieldName: 'path_segment'
Damit würde unsere speaking URL wie folgt aussehen:
einmahl.de/ueber-uns/news/detail/ein-neuer-blog-entsteht
Jetzt wollen wir aber die ID des Posts ebenfalls in der URL haben, um Fehler durch gleichnamige Posts zu vermeiden. Unter routePath wird angegeben, dass unserer URL schlicht und einfach der Titel des Posts angehängt werden soll. Hier wäre es auch möglich, zu sagen, dass der routePath '/detail/{news-title}' lauten soll, was zu der URL führt, die ihr über diesem Absatz seht. Wir haben das durch das Anlegen einer Seite "Detail" unterhalb von "News" im Seitenbaum des TYPO3-Backends gelöst, weshalb diese Angabe bei uns hier im Code nicht mehr nötig ist.
Unter aspects findet sich die einzigartige Kennung "news-title", die mit den _arguments aus routes übereinstimmt und diesem sagt, wo sie den Titel des Posts finden kann. Es wird festgelegt, dass der Name der Tabelle in der Datenbank (tableName) "tx_news_domain_model_news" lauten soll und das betreffende Feld in der Tabelle (routeFieldName) "path_segment", welches immer den URL-konformen Titel der News enthält.
Um nun die ID mit ins Spiel zu bringen, benötigen wir allerdings einen anderen type. Dieser würde so aussehen:
aspects: news-title: type: PersistedPatternMapper tableName: 'tx_news_domain_model_news' routeFieldPattern: '^(?P<path_segment>.+)-(?P<uid>\d+)$' routeFieldResult: '{path_segment}-{uid}'
Wir haben hier den type "PersistedPatternMapper" benutzt und nicht mehr "PersistedAliasMapper". Die einzigartige Kennung (news-title) bleibt hier gleich, da wir dasselbe Argument ansprechen wollen. Auch der Name der Tabelle ändert sich nicht, da wir beides, den Titel und die ID der Posts, in ebendieser Tabelle finden können. In der nächsten Zeile kommt ein Regulärer Ausdruck zum Einsatz, der die entsprechenden Namen der Tabellenfelder beinhaltet und darauf folgt das Endergebnis, wie unser URL-Zusatz am Ende auszusehen hat. Damit haben wir unsere finale gewünschte URL erreicht:
einmahl.de/ueber-uns/news/detail/ein-neuer-blog-entsteht-1
Endergebnis
Hier findet ihr noch einmal den gesamten Code:
routeEnhancers: News: type: Extbase limitToPages: [55] extension: News plugin: Pi1 routes: - routePath: '/{news-title}' _controller: 'News::detail' _arguments: news-title: 'news' aspects: news-title: type: PersistedPatternMapper tableName: 'tx_news_domain_model_news' routeFieldPattern: '^(?P<path_segment>.+)-(?P<uid>\d+)$' routeFieldResult: '{path_segment}-{uid}'
Hier solltet ihr dringend darauf achten, die Einrückungen korrekt zu setzen, da andernfalls unvorhergesehene Resultate folgen können.