Brokkoli in einer Hand, in der anderen einen Donout

TypoScript Conditions mit der Symfony Expression Language

Für die TYPO3 v9.5 LTS wurde die Symfony Expression Language bei den TypoScript Conditions eingeführt. Wem das zu viele Fragezeichen auf einmal sind, dem erklären wir zunächst, um was es sich bei TypoScript Conditions und der Symfony Expression Language handelt. Anschließend zeigen wir wie ältere Conditions migriert und somit zukunftsfähig gemacht werden.

TypoScript Conditions

TypoScript Conditions kommen wie der Name bereits verrät beim TypoScript zum Einsatz. TypoScript ist keine Skriptsprache. TypoScript dient eher als eine Art API (Schnittstelle), zum konfigurieren des zugrunde liegenden PHP-Codes.

Die TypoScript Conditions (zu Deutsch „Bedingungen“) bieten die Möglichkeit zu überprüfen, ob eine Bedingung erfüllt ist oder nicht. Je nachdem wird weiteres TypoScript verwendet oder nicht.

... TypoScript ...

[ Condition 1 ][ Condition 2 ]

... TypoScript, dass nur verarbeitet wird, wenn die Bedingungen erfüllt wurden ...

[END]

... TypoScript ...

Mit den Conditions kann beispielsweise Folgendes gefragt werden:

  • Ist der aktuelle Nutzer im Backend eingeloggt?
  • Ist heute Freitag?
  • Enthält die URL den Parameter „x=1“?
  • Findet im Gewandhaus zu Leipzig heute eine Veranstaltung statt?
  • Fühle ich mich gut?

Zugegeben sind einige von diesen Fragen nicht für jede Webseite relevant. Es soll lediglich gezeigt werden, dass die Möglichkeiten der TypoScript Conditions kaum Grenzen kennen. Mit der Einführung der Symfony Expression Language werden sie sogar noch mächtiger.

Symfony Expression Language

Symfony ist ein weit verbreitetes PHP-Framework. Es gibt PHP-Entwicklern nützliche Werkzeuge an die Hand. So zum Beispiel auch die Expression Language.

Die Expression Language stellt eine Engine bereit, mit der Ausdrücke kompiliert und ausgewertet werden können. Ein Ausdruck ist ein Einzeiler, der einen Wert zurückgibt. Meistens ist dieser Wert vom Typ Boolean, also entweder Wahr oder Falsch.

Innerhalb von Symfony sieht das dann wie folgt aus.

$expressionLanguage->evaluate('1 < 2'); // wahr

Die Expression Language stellt in diesem Fall ‚1 < 2‘ dar. Hierbei handelt es sich um ein simples Beispiel.

Die Expression Language Syntax ist viel umfangreicher. Möglich sind somit auch:

$expressionLanguage->evaluate('not ("Schuppenkopfrötel" matches "/Paddyreiher/")'); // wahr

$expressionLanguage->evaluate('11 in 1..10'); // falsch

$expressionLanguage->evaluate('calendar.getWeekday() == "Freitag"')); // Am Freitag wahr, sonst falsch

Der Ausdruck matches ermöglicht den Vergleich mit sämtlichen regulären Ausdrücken. Zudem können Eigenschaften und Funktionen von Objekten ausgeführt werden.

Zu beachten ist, dass ein Schrägstrich (\) innerhalb einer Zeichenkette mit 4 weiteren maskiert werden muss (\\\\) und sogar mit 8 (\\\\\\\\) in einem regulären Ausdruck.  Darüber hinaus werden Kontrollsequenzen, wie z.B. ein Zeilenumbruch (\n), normalerweise mit einem Leerzeichen ersetzt. Durch voranstellen eines Weiteren umgekehrten Schrägstrichs wird dies vermieden (\\n).

Die hier aufgeführten Beispiele sind nur ein kleiner Auszug. Einen umfangreichen Überblick gibt es in der Dokumentation.

TypoScript Conditions in TYPO3 v9.5 LTS

Die Symfony Expression Language wurde mit der TYPO3 v9.4 in den Core übernommen und steht somit auch in der Long Term Version 9.5 zur Verfügung. Die alte Syntax gilt als veraltet und wird nur noch bis zur 10er Version unterstützt. Um sein System zukunftsfähig zu halten, gilt es die alten Conditions zu migrieren.

Variablen

Schon vor der TYPO3 9 kamen Conditions zum Einsatz. Hier standen dem Integrator eine Vielzahl von Variablen zur Verfügung, wie z.B. die ID der aktuellen Seite oder der Name des angemeldeten Benutzers. Diese gibt es innerhalb der Symfony Expression Language bei TYPO3 wieder, nur die Syntax ist eine andere. Ein paar Beispiele:

  • applicationContext – Gibt Aufschluss über die aktuelle Umgebung, z.B. „production“ oder „development“.
  • page – Alle Eigenschaften der Seite als Array.
  • {$meineTypoScriptKonstante} – ermöglicht auf den Inhalt der TypoScript-Konstanten zuzugreifen.
  • frontend.user.isLoggedIn – ist wahr, wenn der Nutzer im Frontend angemeldet ist
  • typo3.version – aktuelle TYPO3-Version, z.B. 9.5.0-dev

Funktionen

Um wirklich alle bisherigen Conditions ersetzen zu können, gibt TYPO3 neben den Variablen auch Funktionen an die Hand.

  • date() – Zugriff auf das aktuelle Datum
  • like("Heuhaufen", "*Nadel")  – Schaut, ob die Zeichenkette Nadel im Heuhaufen vorkommt. Das Sternchen (*) wird als Platzhalter für eine beliebige Zeichenkette verwendet.
  • getTSFE() – Ermöglicht den Zugriff auf den TypoScriptFrontendController $GLOBALS[‚TSFE‘]
  • request.getQueryParams() – Ermittelt alle GET-Parameter.
  • site() – Gibt die Eigenschaften der aktuellen Seitenkonfiguration zurück.

Eine Übersicht aller Variablen und Funktionen, gibt es in der Feature-Beschreibung.

Ausdrücke

Es folgen nun Beispiele, wie bisherige Conditions mit der neuen Symfony Expression Language aussehen.

Seitensprache

//bis TYPO3 v9:
[globalVar = GP:L = 1]
 
// ab TYPO3 9.4 - der L-Parameter entfällt, daher Überprüfung der Site-Configuration
[siteLanguage("languageId") == "1"]
// neben der Id können nun auch weitere Eigenschaften abgefragt werden
[siteLanguage("title") == "Deutsch"]

Get-Parameter

// bis TYPO3 v9.3
[globalVar = GP:tx_myext_myplugin|bla > 0]

// ab TYPO3 v9.4 (GET-Parameter oder POST-Parameter)
[(request.getQueryParams()['tx_myext_myplugin'])['bla'] > 0 || 
 (request.getParsedBody()['tx_myext_myplugin'])['bla'] > 0]

Ebene im Seitenbaum

// bis TYPO3 v9.3 
[treeLevel = 0,2] 

// ab TYPO3 v9.4 
[tree.level in [0,2]]

Seite in Rootline

// bis TYPO3 v9.3 
[PIDinRootline = 5,10] 

// ab TYPO3 v9.4 
[5 in tree.rootLineIds || 10 in tree.rootLineIds]

Seiteneigenschaften

// bis TYPO3 v9.3
[page|backend_layout = 1]

// ab TYPO3 v9.4
[page["backend_layout"] == '1']

Domain

// bis TYPO3 v9.3
[globalString = IENV:HTTP_HOST = *.mydomain.com]

// ab TYPO3 v9.4
[like(request.getNormalizedParams().getHttpHost(), '*.mydomain.com')]

Konstanten

// bis TYPO3 v9.3
[globalVar = LIT:1 = {$meineTypoScriptKonstante}]

// ab TYPO3 v9.4
[{$meineTypoScriptKonstante} == '1']

Nutzer im Backend eingeloggt

// bis TYPO3 v9.3
[globalVar = TSFE:beUserLogin > 0]

// ab TYPO3 v9.4
[getTSFE().beUserLogin]

Ist heute Freitag?

// bis TYPO3 v9.3
[dayofweek = 5]

// ab TYPO3 v9.4
[date("w") == 5]

Weitere Beispiele

Wie bereits erwähnt sind die Möglichkeiten der Conditions kaum begrenzt. Weiterführende Links mit zusätzlichen Beispielen sind am Ende des Blog-Beitrags zusammengetragen.

Erweitern der Expression Language

Bisher konnten eigene Funktionen via [userFunc = \Vendor\Extension\UserFunc\MyUserFunc('foo')] verwendet werden. Auch die Symfony Expression Language lässt sich beliebig erweitern.

Dazu wird zunächst der eigene Provider in einer aktiven Extension unter Configuration/ExpressionLanguage.php registriert.

<?php

return [
    'tx_myext_provider' => [
        \Vendor\Extension\ExpressionLanguage\MyConditionProvider::class,
    ]
];

Die Klasse muss das \TYPO3\CMS\Core\ExpressionLanguage\ProviderInterface umsetzen. Dieses besteht aus den beiden Funktionen getExpressionLanguageProviders() und getExpressionLanguageVariables(). Für die Umsetzung kann von der Klasse \TYPO3\CMS\Core\ExpressionLanguage\AbstractProvider abgleitet werden.

Als Beispiel schauen wir uns den TypoScriptConditionProvider aus dem Core an.

class TypoScriptConditionProvider extends AbstractProvider
{
    public function __construct()
    {
        $typo3 = new \stdClass();
        $typo3->version = TYPO3_version;
        $typo3->branch = TYPO3_branch;
        $typo3->devIpMask = trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
        $this->expressionLanguageVariables = [
            'request' => GeneralUtility::makeInstance(RequestWrapper::class, $GLOBALS['TYPO3_REQUEST'] ?? null),
            'applicationContext' => (string)GeneralUtility::getApplicationContext(),
            'typo3' => $typo3,
        ];
        $this->expressionLanguageProviders = [
            Typo3ConditionFunctionsProvider::class
        ];
    }
}

Symfony und TYPO3

Die Symfony Expression Language ist eines von vielen Vorzügen der neuen TYPO3 9 LTS. Wir freuen uns sehr, dass TYPO3 Teile von Symfony übernimmt, da wir dieses Framework auch Unabhängig von TYPO3 einsetzen. In unseren Individual-Programmierungen setzen wir auf Symfony seit vielen Jahren und haben durchweg positive Erfahrungen gesammelt.

Fragen oder Anmerkungen zum Artikel können Sie wie immer gerne als Kommentar hinterlassen. Möchten Sie selbst eine Webseite mittels TYPO3 oder Symfony realisieren, dann nehmen Sie gerne mit uns Kontakt auf.

  • 28/12/2018

    Kommentar von Flecko

    Hallo,

    ich suche mir gerade meine Änderungen für meine Conditions zusammen und bin über die Seite gestolpert und konnte
    anhand eurer Beispiele viele Probleme lösen, jetzt hänge ich noch an zwei und komme nicht wirklich weiter.

    [treeLevel = 0,1]
    # *** Keine Breadcrumb
    [ELSE]
    # *** Zeige Breadcrumb
    [END]

    # *** Newssingleansicht
    [globalVar = GP:tx_news_pi1|news > 0]
    # *** Wenn wir auf der Newseinzelansicht sind da tue …
    [global]

    Gibt es für diesen Fall überhaupt eine Lösung?

    Vorab schonmal Daumen hoch für den Artikel.

    • 02/01/2019

      Kommentar von Marc

      Hallo Flecko,

      ich habe die Ebene im Seitenbaum (treeLevel) als Beispiel ergänzt. Wie Get-Parameter abgefragt werden, siehst du im Beispiel darüber. Ich hoffe, dass ich dir weiterhelfen konnte.

      Viele Grüße,
      Marc

  • 11/01/2019

    Kommentar von jokumer

    Leider werden mit request.getQueryParams()[‚tx_myext_myplugin‘]
    nur Werte aus GET Anfragen (der aufgerufenen URL) gelesen, nicht jedoch aus POST Anfragen.

    Ältere Bedingungen wie globalVar = GP:tx_myext_myplugin
    berücksichtigten sowohl GET als auch POST Anfragen gleichermaßen.

    Deshalb kann getQueryParams() nicht als Ersatz für globalVar = GP verwendet werden.

  • 12/01/2019

    Kommentar von jokumer

    Statt GET, lassen sich POST Abfragen mit folgender Schreibweise als Bedingung erstellen
    [request.getParsedBody()[‚tx_myext_myplugin‘][‚bla‘] > 0]

    • 14/01/2019

      Kommentar von Marc

      Hallo jokumer,

      vielen Dank für deinen Hinweis. Ich habe deine Anmerkung im Blog-Beitrag ergänzt.

      Viele Grüße,
      Marc

Kommentar hinzufügen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.