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 } }

TYPO3: Finding pages in mixed mode

In TYPO3, Mixed Mode refers to translated pages that contain content only partially related to the corresponding content in the main language. This is indicated in the backend by an error message. But...

Zum Beitrag

Extbase Extensions: Think extensibility with data, site and language

Today, I have a small request for the TYPO3 extension authors out there: Make sure your extensions are extensible. This will also promote the distribution of the corresponding plugins.

Zum Beitrag

SQL: Show all tables sorted by size in descending order

Lately I've been using the SQL command more often to find out which tables in the TYPO3 database are the largest. I've published the snippet once.

Zum Beitrag

TYPO3 12 with CKEditor 5: Styles in a single selection

If you set a link in the RTE in TYPO3, you may have to choose between different link classes, for example to create buttons in the frontend. What's new in TYPO3 12 is that you can select not just one...

Zum Beitrag

Null-Safe Operator in the TYPO3 area

With the introduction of PHP8, problems with undefined arrays or variables in general can arise in many places. Here are a few examples and simple solutions.

Zum Beitrag

Delete the first/last lines of a (SQL) file

There isn't much to say about the following commands. Sometimes it can be useful to delete the first (or last) X lines from a file. And if the file is too large to open with a conventional program, a...

Zum Beitrag