TYPO3 9 – Routing Enhancer & Aspekte

Wenn man bisher in seinem TYPO3-Projekt suchmaschinenfreundliche, sprechende URLs generieren wollte, war dies immer mit etwas Extra-Aufwand möglich. Das CMS bot nicht von Haus aus diese Möglichkeit. Entwickler mussten auf Extensions, wie etwas RealUrl oder CoolUri zurückgreifen um die eigenen TYPO3-Frontend-Seiten, News-Seiten, Suche-Urls oder Contentseiten eigener Extensions „sprechend schön“ zu gestalten. Die Verwendung externer Extensions war im Zusammenhang mit TYPO3-Updates häufig nicht ganz unkompliziert.

Die Entwickler des CMS haben sich daher viele Gedanken über das Thema gemacht und dieses Feature „Routing“ nun auch in den Core von TYPO3 integriert – nachdem andere CMS hier bereits nutzerfreundlicher aufgestellt waren. Man kann zwar schon über den Pagetree für einfache Seiten sogennante Slugs defninieren oder ganze URL-Pfadsegmente ändern, aber bei Erweiterungen hörten hier die Möglichkeiten schon auf.

 

Wie funktioniert das neue Routing?

 

Man hat inzwischen die Möglichkeit einen oder meherere Ausgangspunkte in einem Seitenbaum zu definieren. Wichtig ist, dass man eine „Seiten-Konfiguration“ über das TYPO3 Backend anlegt über welches man das Wurzelverzeichnis (die Rootpage) definiert.

 

TYPO3 Backend > SITE MANAGEMENT > Sites:

+ Add new site Configuration

==> eine conig.yaml wird automatisch generiert

 

Man vergibt über die Site-Configuration einen sogenannten „Site-Identifier“, ein eindeutiges Schlüsselwort, unter dessen Namen nun eine Konfigurationsdatei (config.yml) generiert wird. Innerhalb dieser .yml lassen sich die grundlegenden Regeln für alle gewünschten Routes konfigurieren. Weiterhin kann man einen Entry-Point definieren. Dieser kann z.B. die vollständige Domain beinhalten (https://www.example.com) oder komplett relativ mit „/“ definiert werden. Dazu lassen sich verschiedenste zusätzliche Domain-Varianten definieren. Das war bisher auch möglich, allerdings passiert dies unter TYPO3 9.5 gebündelt in einem Konfigurationsbereich.

Mithilfe der sogenannten Routing Enhancer lassen sich nun Regeln für jede Form von GET-Parametern, die im Projekt auftreten werden, festlegen und das Seiten-Routing somit flexibel für jede Extension erweitern. Um Routing Enhancer zu definieren fügt man in seiner config.yml einen Abschnitt „routeEnhancers“ hinzu.

 

Routing Enhancer

 

Enhancer werden zweckgebunden in verschiedenen Typen zur Verfügung gestellt. Außerdem lassen sich damit zusätzliche Platzhalter in Seitenpfaden ergänzen.

Folgende Enhancer-Typen können definiert werden:

 

- Simple Enhancer (type "Simple") 

- PageType Enhancer (type „PageType“) 

- Plugin Enhancer (type "Plugin")

- Extbase Plugin Enhancer (type "Extbase")

 

Es ist möglich, dieselben Enhancer mehrfach mit unterschiedlichen Konfigurationen zu verwenden, allerdings lassen sie sich nicht miteinander kombinieren.

Enhancer liefern die Gesamtstruktur und die Segmente einer URL und die Details, wie ein Segment aussehen wird, wird imittels der "Aspekten" definiert.

 

Simple Enhancer

 

Der Simple Enhancer arbeitet mit verschiedenen Routenargumenten, um sie einem Argument zuzuordnen, das später verwendet werden soll. Die routeEnhancers werden auf der Root-Ebene der Konfiguration definiert. Dabei erhält jeder Enhancer eine eindeutige Bezeichnung (hier CatListing) und dann wird festgelegt um welchen Typ es sich handelt. Hier type: Simple. Der routePath definiert, wie die URL letzten Endes aussehen soll. Über defaults definiert man die Werte, die auch optional wegfallen können und requirements schränk jene Werte der verwendeten Variablen nach bestimmten RegEx-Regelements ein.

 

routeEnhancers:

  # eindeutiger Name für die Enhancer, der intern für

  # die Referenzierung verwendet wird

  CatListing:

    type: Simple

    limitToPages: [5]

    routePath: '/show-by-category/{cat_id}/{tag}'

    defaults:

      tag: ''

    requirements:

      cat_id: '[0-9]{1..3}'

      tag: '^[a-zA-Z0-9].*$'

 

PageType Enhancer

 

Weiterhin lässt sich mittels eines PageTypeSuffixEnhancern festlegen, welcher Seitentyp einen Suffix erhalten soll. Das gilt Beispielweise für Dateiendungen, RSS-Feeds, JSON-Files, etc. Hiermit werden die Suffixe der URL auf die in den TypoScript-Einstellungen definierten typeNum-Werte abgebildet.

 


routeEnhancers:

   PageTypeSuffix:

      type: PageType

      default: '.html'

      index: 'index'

      map:

           'rss.feed': 13

 

           '.json': 26

 

Plugin Enhancer

 

Der PluginEnhancer wurde für die Unterstützung der Plugins aus der pi-Based-Ära zur Verfügung gestellt, bei denen URL-Pfade in dieser Form entstanden sind:

/page-1/sub-page?tx_felogin_pi1[forgot]=1&&tx_felogin_pi1[user]=123&tx_felogin_pi1[hash]=ABCDEFGHIJKLMNOPQRSTUVWXYZ012345

aus dieser wird:

/page-1/sub-page/frontend-login/123/ABCDEFGHIJKLMNOPQRSTUVWXYZ012345

 

 routeEnhancers:

  FrontendLogin:

    type: Plugin

    # pageid of sub-page

    limitToPages: [13]

    routePath: '/frontend-login/{user}/{hash}'

    namespace: 'tx_felogin_pi1'

    defaults:

      forgot: "1"

    requirements:

      user: '[0-9]{1..3}'

       hash: '^[a-zA-Z0-9]{32}$'

 

Hier dient der namespace zur Deklaration des betreffendes Plugins (im Beispiel tx_felogin_pi1)

 

Extbase Plugin Enhancer

 

Bei diesem Enhancer werden explizit Extbase-Extensions angesprochen und verarbeitet.

 

routeEnhancers:

  NewsPlugin:

    type: Extbase

    limitToPages: [13]

    extension: News

    plugin: Pi1

    routes:

     # News-Listenansicht

      - { routePath: '/list/{page}', _controller: 'News::list', _arguments: {'page': '@widget_0/currentPage'} }

     # Tags/Listenansicht

      - { routePath: '/tag/{tag_name}', _controller: 'News::list', _arguments: {'tag_name': 'overwriteDemand/tags'}}

     # News-Detailansicht

      - { routePath: '/blog/{news_title}', _controller: 'News::detail', _arguments: {'news_title': 'news'} }

     # News-Archiv

      - { routePath: '/archive/{year}/{month}', _controller: 'News::archive' }

    defaultController: 'News::list'

    defaults:

      page: '0'

    requirements:

       page: '\d+'

 

Hier wird mit 3 neuen Argumenten (extension, plugin und routes) gearbeitet, wobei man extension und plugin wie im vorherigen Enhancer durch namespace zusammenfassen kann. Unter routes lassen sich nun verschiedene actions einer Extension ansprechen. Dabei wird der gewünschte Pfad definiert, die angesprochene Controller-Action genannt und alle notwendigen Argumente definiert um ein eindeutige URL zu generieren. Sollte der Request ergebnislos bleiben, gibt’s einen Fallback auf den definierten defaultController.

 

Ausgangs-URL:

index.php?id=13&tx_news_pi1[controller]=News&tx_news_pi1[action]=detail&tx_news_pi1[news]=13

 

Speaking URL:

 /path-to/my-page/detail/13

 

Benutzerdefinierte Enhancers

 

Es besteht auch die Möglichkeit benutzerdefinierte Enhancer zu erstellen. Damit lassen sich auch individuelle / komplexere Anwendungsfälle überwinden, wenn beispielsweise zwei Plugins gleichnamige Parameter nutzen.

Benutzerdefinierte Enhancer werden in der ext_localconf.php registriert:

 

$GLOBALS['TYPO3_CONF_VARS']['SYS']['routing']['CustomPlugin'] = \MyVendor\MyPackage\Routing\CustomEnhancer::class;

 

Aspekte

 

Auf bestimmte Enhancer lassen sich auch Aspekte registrieren, um einen bestimmten Platzhalter (z.B. nummerische Werte) innerhalb des Pfades zu ändern bzw. verschönern – seien es statisch generierte oder dynamische Platzhalter. Es sind die sogenannten Aliase. Je nach Anwendungsfall werden diese auch als Mapper oder Modifier bezeichnet werden.

Man registriert Aspekte innerhalb einer Routing-Enhancer-Konfiguration mittels option aspects und kann diese dann mit jedem beliebigen Enhancer verwenden.

 

StaticValueMapper

Dieser Mapper ersetzt Werte einfach auf einer 1:1-Mapping-Liste eines Arguments in ein sprechendes Segment. Im Beispiel werden im Auszug Sprachsegmente für die verfügbaren Monate zu erstellt

 

 (...)

     aspects:

           month:

                type: StaticValueMapper

                map:

                      january: 1

                      february: 2
                      (...)

(...)

 

LocaleModifier

 

Dieser Modifier bietet die Möglichkeit in mehrsprachigen Umgebungen Platzhalter je Sprache und Seitenübersetzung auszuspielen. Im Beispiel wird das News-Pfadsegment /archive/ für französisch und deutsch definiert:

 

(...)

    aspects:

      localized_archive:

        type: LocaleModifier

        default: 'archive'

        localeMap:

          - locale: 'fr_FR.*|fr_CA.*'

            value: 'archives'

          - locale: 'de_DE.*'

            value: 'archiv'

(...)

 

StaticRageMapper

Dieser Mapper ermöglicht es, den cHash in einer URL zu vermeiden, die verfügbaren Möglichkeiten für einen Platzhalter einzuschränken und explizit einen Bereich für einen Wert zu definieren, der für alle Arten von Paginierungsfunktionalitäten empfohlen wird. Im Beispiel wird der Seitenumbruch auf max. 20 Seiten begrenzt. Ab Seite 21 würde der Platzhalter nicht mehr greifen.

 

(...)

    aspects:

      page:

        type: StaticRangeMapper

        start: '1'

        end: '20'
(...)

 

PersistedAliasMapper

 

Der PersistedAliasMapper ordnet eine UID einem bestimmten Feld innerhalb dieses Datensatzes zu (i. d. R. dem Slug-Feld, ehemals bekannt als das Feld "sprechende URL-Pfadsegment").

 

(...)

    aspects:

      news_title:

        type: PersistedAliasMapper

        tableName: 'tx_news_domain_model_news'

        routeFieldName: 'path_segment'

        routeValuePrefix: '/'
(...)

 

PersistedPatternMapper

 

Dieser Aspekt erstellt den sprechenden URL-Pfad abhängig von mehreren Feldern aus einem Datenbankeintrag. Dies ist nützlich, wenn ein verwendetes Feld möglicherweise nicht eindeutig ist. Das Hinzufügen der UID zur sprechenden URL macht diese einzigartig.

 

(...)
     aspects:

           blogpost:

                type: PersistedPatternMapper

                tableName: 'tx_blogexample_domain_model_post'

                routeFieldPattern: '^(?P<title>.+)-(?P<uid>\d+)$'

                routeFieldResult: '{title}-{uid}'
(...)

 

Detailliertere Infos zum Thema erfahrt ihr der TYPO3 Dokumentation der auch ein Großteil der Beispiele entnommen sind.