For coders TYPO3 Tech Corner

Im FlexForm Felder je nach Wert eines anderen Feldes ausblenden

Im FlexForm Felder je nach Wert eines anderen Feldes ausblenden

Von unserem Projektmanagement kommt des Öfteren die Anforderung, dass einzelne Felder im FlexForm ausgeblendet werden sollen, je nachdem was für ein Wert sich in einem anderen Feld befindet. Das ist ein Mittel, um TYPO3 möglichst schlank auszuliefern und keine unnötigen Felder für die Redaktion anzuzeigen.

Generell muss man verstehen, dass wir bei in2code TYPO3 immer nur mit funktionalen und benötigten Feldern an die Kunden ausliefern. Das bedeutet, dass Einstellungen, die keine Funktion beinhalten oder dass ungetestete und unbenötigte Einstellungen (TYPO3 und Extensions) von uns für alle Backend Benutzer (auch für Administratoren) ausgeblendet werden. Dies erhöht die Übersichtlichkeit und Usability des zu verwaltenden Content Management Systems.

1. Generelles zum Thema displayCond und FlexForm in TYPO3

Die Definition von FlexForm ist im Prinzip identisch mit der Definition von Feldern mittels TCA. Aber während es sich beim einen um eine PHP-Schreibweise handelt, handelt es sich beim anderen um eine XML-Schreibweise. Mit Hilfe der Eigenschaft displayCond kann man neben dem TCA also auch im FlexForm einfach auf Werte aus anderen Feldern zugreifen.

Hier wird das Feld field nur angezeigt, wenn sich im Feld field2 der Wert "1" befindet:

<settings.field> <TCEforms> <displayCond>FIELD:settings.field2:=:1</displayCond> <label>My label</label> <config> <type>select</type> <renderType>selectSingle</renderType> <items type="array"> <numIndex index="0" type="array"> <numIndex index="0">please choose</numIndex> <numIndex index="1"></numIndex> </numIndex> </items> <foreign_table>fe_groups</foreign_table> <foreign_table_where>AND fe_groups.deleted = 0</foreign_table_where> </config> </TCEforms> </settings.field>

Man kann auch verschiedene Conditions mit AND oder mit OR miteinander verknüpften. Im nachfolgenden Beispiel wird auf einen Wert im Feld switchableControllerActions zurückgegriffen. Da dieser Wert spitze Klammern beinhaltet, wird hier auf eine Schreibweise mit CDATA zurückgegriffen:

<displayCond> <OR> <numIndex index="0"><![CDATA[FIELD:main.switchableControllerActions:=:New->new;]]></numIndex> <numIndex index="1"><![CDATA[FIELD:main.switchableControllerActions:=:Invitation->new;]]></numIndex> </OR> </displayCond>

Tipp: Man kann auch ganze Tabs im FlexForm ausblenden, so wie es bei der Erweiterung femanger gemacht wird.

2. Ausblenden von Feldern in Drittextensions

Das Alles ist so weit vermutlich nichts neues für euch. Und TYPO3 macht es einem hier auch einfach, Extensions zu bauen, die genau so funktionieren sollen, wie wir uns das vorstellen. Schwerer wird das Ganze jedoch dann, wenn wir das FlexForm einer Drittextension manipulieren wollen. Gehen wir beispielsweise von der Extension news aus. Auch hier wollen wir unbenötigte Felder gar nicht erst im Plugin anzeigen.

Generell können wir die Felder im FlexForm ganz einfach per Page TSConfig ausblenden:

TCEFORM { tt_content { pi_flexform { news_pi1 { sDEF { switchableControllerActions.removeItems := addToList(News->list,News->selectedList,News->dateMenu,News->searchForm,News->searchResult,Category->list,Tag->list) settings\.categoryConjunction.disabled = 1 settings\.categories.disabled = 1 settings\.includeSubCategories.disabled = 1 settings\.recursive.disabled = 1 } } } } }

Tipp: Mit Hilfe von Conditions können wir auch auf eine Backend Benutzergruppe abfragen und einzelne Felder ausblenden.

Kommt es jedoch zur Anforderung, dass beispielsweise settings.backPid nur in der Listenansicht ausgeblendet werden soll, wird es schon kniffliger. Eigentlich müsste man jetzt das komplette FlexForm ersetzen. Aber da man hier Probleme mit künftigen Updates bekommen könnte, empfiehlt sich der Einsatz des FlexFormHooks.

Einbau in der ext_localconf.php eures Sitepackages:

/** * Hook to remove flexform fields per condition */ $flexFormToolsName = \TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools::class; $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][$flexFormToolsName]['flexParsing'][] = \In2code\In2template\Hooks\FlexFormHook::class;

Neue Datei in Classes/Hooks/FlexFormHook.php innerhalb eures Sitepackages:

<?php declare(strict_types=1); namespace In2code\In2template\Hooks; use TYPO3\CMS\Backend\Utility\BackendUtility; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; /** * FlexFormHook * to add display cond configuration by given page TS settings */ class FlexFormHook { const TABLE_NAME = 'tt_content'; /** * Remove FlexForm fields depending to dataStructureKeys * Example Page TSConfig: * TCEFORM { * tt_content { * pi_flexform { * _addDisplayCond { * 1 { * field = sheets/additional/ROOT/el/settings.backPid/TCEforms/displayCond * value = FIELD:sDEF.switchableControllerActions:=:News->detail * dataStructureKey = news_pi1,list * } * } * } * } * } * @param array $dataStructure * @param array $identifier * @return array */ public function parseDataStructureByIdentifierPostProcess(array $dataStructure, array $identifier): array { $pageTsConfig = BackendUtility::getPagesTSconfig($this->getCurrentPageIdentifier()); if ($this->isConditionEnabled($pageTsConfig, $identifier)) { $configurationParts = $pageTsConfig['TCEFORM.'][$identifier['tableName'] . '.'][$identifier['fieldName'] . '.']['_addDisplayCond.']; foreach ($configurationParts as $part) { if ($part['dataStructureKey'] === $identifier['dataStructureKey']) { $dataStructure = ArrayUtility::setValueByPath($dataStructure, $part['field'], $part['value']); } } } return $dataStructure; } /** * @param array $pageTsConfig * @param array $identifier * @return bool */ protected function isConditionEnabled(array $pageTsConfig, array $identifier): bool { return isset($pageTsConfig['TCEFORM.'][$identifier['tableName'] . '.'][$identifier['fieldName'] . '.']['_addDisplayCond.']); } /** * @return int */ protected function getCurrentPageIdentifier(): int { $contentIdentifier = $this->getCurrentContentIdentifier(); if ($contentIdentifier > 0) { return $this->getPageIdentifierFromContentIdentifier($contentIdentifier); } return 0; } /** * @return int */ protected function getCurrentContentIdentifier(): int { $edit = GeneralUtility::_GP('edit'); if (!empty($edit[self::TABLE_NAME])) { return (int)key($edit[self::TABLE_NAME]); } return 0; } /** * @param int $contentIdentifier * @return int */ protected function getPageIdentifierFromContentIdentifier(int $contentIdentifier): int { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable(self::TABLE_NAME); $queryBuilder->getRestrictions()->removeAll(); return (int)$queryBuilder ->select('pid') ->from(self::TABLE_NAME) ->where('uid=' . (int)$contentIdentifier) ->execute() ->fetchColumn(); } }

Danach könnte euer Page TSConfig so oder so ähnlich aussehen:

TCEFORM { tt_content { pi_flexform { # Add display cond configuration to an existing FlexForm configuration (see FlexFormHook class) _addDisplayCond { 1 { # Hide settings.backPid in detail view field = sheets/additional/ROOT/el/settings.backPid/TCEforms/displayCond value = FIELD:sDEF.switchableControllerActions:=:News->detail dataStructureKey = news_pi1,list } } news_pi1 { sDEF { switchableControllerActions.removeItems := addToList(News->list,News->selectedList,News->dateMenu,News->searchForm,News->searchResult,Category->list,Tag->list) settings\.categoryConjunction.disabled = 1 settings\.categories.disabled = 1 settings\.includeSubCategories.disabled = 1 settings\.recursive.disabled = 1 } additional { settings\.hidePagination.disabled = 1 settings\.limit.disabled = 1 settings\.listPid.disabled = 1 settings\.tags.disabled = 1 settings\.disableOverrideDemand.disabled = 1 settings\.list\.paginate\.itemsPerPage.disabled = 1 } template { settings\.templateLayout.disabled = 1 settings\.media\.maxWidth.disabled = 1 settings\.media\.maxHeight.disabled = 1 settings\.cropMaxCharacters.disabled = 1 } } } } tx_news_domain_model_news { categories.disabled = 1 related.disabled = 1 related_from.disabled = 1 tags.disabled = 1 keywords.disabled = 1 description.disabled = 1 alternative_title.disabled = 1 editlock.disabled = 1 notes.disabled = 1 } tx_news_domain_model_link { description.disabled = 1 } }

Kennst du das: Immer nur schnell schnell?

Wie wäre es einmal mit Zeit und Respekt für Codequalität? Arbeiten im Team? Automatisierte Tests?

Komm zu uns

SQL: Zeige alle Tabellen absteigend nach Größe sortiert

Ich brauche in letzter Zeit häufiger den SQL-Befehl, um herauszufinden, welche Tabellen in der TYPO3-Datenbank am größten sind. Ich habe das Snippet einmal veröffentlicht.

Zum Beitrag

TYPO3 12 mit CKEditor 5: Stile als Einfachauswahl

Wenn man im RTE in TYPO3 einen Link setzt, kann es sein, dass man zwischen verschiedenen Link-Klassen auswählen muss, um beispielsweise Buttons im Frontend zu erzeugen. Neu ist in TYPO3 12 dass man...

Zum Beitrag

Null-Safe Operator im TYPO3-Bereich

Spätestens mit dem Einzug von PHP8 kann es an vielen Stellen zu Problemen mit undefinierten Arrays oder Variablen im Allgemeinen kommen. Hier ein paar Beispiele und einfache Lösung dafür.

Zum Beitrag

Die ersten/letzten Zeilen einer (SQL)-Datei löschen

Zu den nachfolgenden Befehlen gibt es eigentlich nicht viel zu sagen. Manchmal kann es nützlich sein, die ersten (bzw. letzten) X Zeilen aus einer Datei zu löschen. Und wenn die Datei zu groß zum...

Zum Beitrag

b13/container: Kindelemente in der Bearbeitungsansicht hinzufügen und ändern

Anders als in gridelements kann man in der Extension Container von B13 die Kindelemente nicht verwalten, wenn man den Container in der Bearbeitungsansicht öffnet. Wie man das schnell selber einbauen...

Zum Beitrag

Menü-Vergleich: Zahlen, Zahlen, Zahlen

Zum Beitrag