[TASK] FormEngine: Move ElementConditionMatcher into data provider 18/43418/5
authorMorton Jonuschat <m.jonuschat@mojocode.de>
Tue, 15 Sep 2015 16:48:47 +0000 (18:48 +0200)
committerWouter Wolters <typo3@wouterwolters.nl>
Sat, 19 Sep 2015 15:32:29 +0000 (17:32 +0200)
Move the handling of column and flexform display conditions into a
dedicated form data provider. The provider removes the hidden elements
from the processed Tca so that no handling of the display conditions is
required in the rendering part of FormEngine.

Resolves: #69938
Resolves: #69897
Releases: master
Change-Id: I367740f61d1a14ba57c57eca30a2edf26ed0f272
Reviewed-on: http://review.typo3.org/43418
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
typo3/sysext/backend/Classes/Form/Container/AbstractContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormNoTabsContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormTabsContainer.php
typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
typo3/sysext/backend/Classes/Form/ElementConditionMatcher.php [deleted file]
typo3/sysext/backend/Classes/Form/FormDataProvider/EvaluateDisplayConditions.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Form/ElementConditionMatcherTest.php [deleted file]
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/EvaluateDisplayConditionsTest.php [new file with mode: 0644]
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Documentation/Changelog/master/Deprecation-69938-HIDE_L10N_SIBLINGSFlexFormdisplayCond.rst [new file with mode: 0644]

index 4f4aa49..19468a7 100644 (file)
@@ -19,7 +19,6 @@ use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Backend\Form\AbstractNode;
-use TYPO3\CMS\Backend\Form\ElementConditionMatcher;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 
@@ -70,49 +69,6 @@ abstract class AbstractContainer extends AbstractNode {
        }
 
        /**
-        * Evaluate condition of flex forms
-        *
-        * @param string $displayCondition The condition to evaluate
-        * @param array $flexFormData Given data the condition is based on
-        * @param string $flexFormLanguage Flex form language key
-        * @return bool TRUE if condition matched
-        */
-       protected function evaluateFlexFormDisplayCondition($displayCondition, $flexFormData, $flexFormLanguage) {
-               $elementConditionMatcher = GeneralUtility::makeInstance(ElementConditionMatcher::class);
-
-               $splitCondition = GeneralUtility::trimExplode(':', $displayCondition);
-               $skipCondition = FALSE;
-               $fakeRow = array();
-               switch ($splitCondition[0]) {
-                       case 'FIELD':
-                               list($sheetName, $fieldName) = GeneralUtility::trimExplode('.', $splitCondition[1], FALSE, 2);
-                               $fieldValue = $flexFormData[$sheetName][$flexFormLanguage][$fieldName];
-                               $splitCondition[1] = $fieldName;
-                               $displayCondition = join(':', $splitCondition);
-                               $fakeRow = array($fieldName => $fieldValue);
-                               break;
-                       case 'HIDE_FOR_NON_ADMINS':
-
-                       case 'VERSION':
-
-                       case 'HIDE_L10N_SIBLINGS':
-
-                       case 'EXT':
-                               break;
-                       case 'REC':
-                               $fakeRow = array('uid' => $this->data['databaseRow']['uid']);
-                               break;
-                       default:
-                               $skipCondition = TRUE;
-               }
-               if ($skipCondition) {
-                       return TRUE;
-               } else {
-                       return $elementConditionMatcher->match($displayCondition, $fakeRow, 'vDEF');
-               }
-       }
-
-       /**
         * Rendering preview output of a field value which is not shown as a form field but just outputted.
         *
         * @param string $value The value to output
index 75852af..1362914 100644 (file)
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Form\Container;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Backend\Form\ElementConditionMatcher;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Lang\LanguageService;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
@@ -93,18 +92,6 @@ class FlexFormElementContainer extends AbstractContainer {
                                }
                                $html = array();
                                foreach ($lkeys as $lkey) {
-                                       $displayConditionResult = TRUE;
-                                       if (!empty($flexFormFieldArray['displayCond'])) {
-                                               $conditionData = is_array($flexFormRowData) ? $flexFormRowData : array();
-                                               $conditionData['parentRec'] = $row;
-                                               /** @var $elementConditionMatcher ElementConditionMatcher */
-                                               $elementConditionMatcher = GeneralUtility::makeInstance(ElementConditionMatcher::class);
-                                               $displayConditionResult = $elementConditionMatcher->match($flexFormFieldArray['displayCond'], $conditionData, $lkey);
-                                       }
-                                       if (!$displayConditionResult) {
-                                               continue;
-                                       }
-
                                        // Set up options for single element
                                        $fakeParameterArray = array(
                                                'fieldConf' => array(
index 8a3ee2d..27608a6 100644 (file)
@@ -45,25 +45,9 @@ class FlexFormNoTabsContainer extends AbstractContainer {
                $sheetName = array_pop(array_keys($flexFormDataStructureArray['sheets']));
                $flexFormRowDataSubPart = $flexFormRowData['data'][$sheetName][$flexFormCurrentLanguage];
 
-
                // That was taken from GeneralUtility::resolveSheetDefInDS - no idea if it is important
                unset($flexFormDataStructureArray['meta']);
 
-
-               // Evaluate display condition for this "sheet" if there is one
-               $displayConditionResult = TRUE;
-               if (!empty($flexFormDataStructureArray['sheets'][$sheetName]['ROOT']['displayCond'])) {
-                       $displayConditionDefinition = $flexFormDataStructureArray['ROOT']['displayCond'];
-                       $displayConditionResult = $this->evaluateFlexFormDisplayCondition(
-                               $displayConditionDefinition,
-                               $flexFormRowDataSubPart,
-                               $flexFormCurrentLanguage
-                       );
-               }
-               if (!$displayConditionResult) {
-                       return $resultArray;
-               }
-
                if (!is_array($flexFormDataStructureArray['sheets'][$sheetName]['ROOT']['el'])) {
                        $resultArray['html'] = 'Data Structure ERROR: No [\'ROOT\'][\'el\'] element found in flex form definition.';
                        return $resultArray;
index 453226c..fc7fd12 100644 (file)
@@ -52,20 +52,6 @@ class FlexFormTabsContainer extends AbstractContainer {
                foreach ($flexFormDataStructureArray['sheets'] as $sheetName => $sheetDataStructure) {
                        $flexFormRowSheetDataSubPart = $flexFormRowData['data'][$sheetName][$flexFormCurrentLanguage];
 
-                       // Evaluate display condition for this sheet if there is one
-                       $displayConditionResult = TRUE;
-                       if (!empty($sheetDataStructure['ROOT']['displayCond'])) {
-                               $displayConditionDefinition = $sheetDataStructure['ROOT']['displayCond'];
-                               $displayConditionResult = $this->evaluateFlexFormDisplayCondition(
-                                       $displayConditionDefinition,
-                                       $flexFormRowData['data'],
-                                       $flexFormCurrentLanguage
-                               );
-                       }
-                       if (!$displayConditionResult) {
-                               continue;
-                       }
-
                        if (!is_array($sheetDataStructure['ROOT']['el'])) {
                                $resultArray['html'] .= LF . 'No Data Structure ERROR: No [\'ROOT\'][\'el\'] found for sheet "' . $sheetName . '".';
                                continue;
index d80ab84..e2fdaba 100644 (file)
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Form\Container;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Backend\Form\ElementConditionMatcher;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -77,15 +76,6 @@ class SingleFieldContainer extends AbstractContainer {
                ) {
                        return $resultArray;
                }
-               // Evaluate display condition
-               if ($parameterArray['fieldConf']['displayCond'] && is_array($row)) {
-                       // @todo: isn't $row = array() safe somewhere above already?
-                       /** @var $elementConditionMatcher ElementConditionMatcher */
-                       $elementConditionMatcher = GeneralUtility::makeInstance(ElementConditionMatcher::class);
-                       if (!$elementConditionMatcher->match($parameterArray['fieldConf']['displayCond'], $row)) {
-                               return $resultArray;
-                       }
-               }
 
                $parameterArray['fieldTSConfig'] = [];
                if (isset($this->data['pageTsConfigMerged']['TCEFORM.'][$table . '.'][$fieldName . '.'])
diff --git a/typo3/sysext/backend/Classes/Form/ElementConditionMatcher.php b/typo3/sysext/backend/Classes/Form/ElementConditionMatcher.php
deleted file mode 100644 (file)
index fcb1019..0000000
+++ /dev/null
@@ -1,354 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Form;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
-
-/**
- * Class ElementConditionMatcher implements the TCA 'displayCond' option.
- * The display condition is a colon separated string which describes
- * the condition to decide whether a form field should be displayed.
- */
-class ElementConditionMatcher {
-
-       /**
-        * @var string
-        */
-       protected $flexformValueKey = '';
-
-       /**
-        * @var array
-        */
-       protected $record = array();
-
-       /**
-        * Evaluates the provided condition and returns TRUE if the form
-        * element should be displayed.
-        *
-        * The condition string is separated by colons and the first part
-        * indicates what type of evaluation should be performed.
-        *
-        * @param string $displayCondition
-        * @param array $record
-        * @param string $flexformValueKey
-        * @param int $recursionLevel Internal level of recursion
-        * @return bool TRUE if condition evaluates successfully
-        */
-       public function match($displayCondition, array $record = array(), $flexformValueKey = '', $recursionLevel = 0) {
-               if ($recursionLevel > 99) {
-                       // This should not happen, treat as misconfiguration
-                       return TRUE;
-               }
-               if (!is_array($displayCondition)) {
-                       // DisplayCondition is not an array - just get its value
-                       $result = $this->matchSingle($displayCondition, $record, $flexformValueKey);
-               } else {
-                       // Multiple conditions given as array ('AND|OR' => condition array)
-                       $conditionEvaluations = array(
-                               'AND' => array(),
-                               'OR' => array(),
-                       );
-                       foreach ($displayCondition as $logicalOperator => $groupedDisplayConditions) {
-                               $logicalOperator = strtoupper($logicalOperator);
-                               if (($logicalOperator !== 'AND' && $logicalOperator !== 'OR') || !is_array($groupedDisplayConditions)) {
-                                       // Invalid line. Skip it.
-                                       continue;
-                               } else {
-                                       foreach ($groupedDisplayConditions as $key => $singleDisplayCondition) {
-                                               $key = strtoupper($key);
-                                               if (($key === 'AND' || $key === 'OR') && is_array($singleDisplayCondition)) {
-                                                       // Recursion statement: condition is 'AND' or 'OR' and is pointing to an array (should be conditions again)
-                                                       $conditionEvaluations[$logicalOperator][] = $this->match(
-                                                               array($key => $singleDisplayCondition),
-                                                               $record,
-                                                               $flexformValueKey,
-                                                               $recursionLevel + 1
-                                                       );
-                                               } else {
-                                                       // Condition statement: collect evaluation of this single condition.
-                                                       $conditionEvaluations[$logicalOperator][] = $this->matchSingle(
-                                                               $singleDisplayCondition,
-                                                               $record,
-                                                               $flexformValueKey
-                                                       );
-                                               }
-                                       }
-                               }
-                       }
-                       if (!empty($conditionEvaluations['OR']) && in_array(TRUE, $conditionEvaluations['OR'], TRUE)) {
-                               // There are OR conditions and at least one of them is TRUE
-                               $result = TRUE;
-                       } elseif (!empty($conditionEvaluations['AND']) && !in_array(FALSE, $conditionEvaluations['AND'], TRUE)) {
-                               // There are AND conditions and none of them is FALSE
-                               $result = TRUE;
-                       } elseif (!empty($conditionEvaluations['OR']) || !empty($conditionEvaluations['AND'])) {
-                               // There are some conditions. But no OR was TRUE and at least one AND was FALSE
-                               $result = FALSE;
-                       } else {
-                               // There are no proper conditions - misconfiguration. Return TRUE.
-                               $result = TRUE;
-                       }
-               }
-               return $result;
-       }
-
-       /**
-        * Evaluates the provided condition and returns TRUE if the form
-        * element should be displayed.
-        *
-        * The condition string is separated by colons and the first part
-        * indicates what type of evaluation should be performed.
-        *
-        * @param string $displayCondition
-        * @param array $record
-        * @param string $flexformValueKey
-        * @return bool
-        * @see match()
-        */
-       protected function matchSingle($displayCondition, array $record = array(), $flexformValueKey = '') {
-               $this->record = $record;
-               $this->flexformValueKey = $flexformValueKey;
-               $result = FALSE;
-               list($matchType, $condition) = explode(':', $displayCondition, 2);
-               switch ($matchType) {
-                       case 'EXT':
-                               $result = $this->matchExtensionCondition($condition);
-                               break;
-                       case 'FIELD':
-                               $result = $this->matchFieldCondition($condition);
-                               break;
-                       case 'HIDE_FOR_NON_ADMINS':
-                               $result = $this->matchHideForNonAdminsCondition();
-                               break;
-                       case 'HIDE_L10N_SIBLINGS':
-                               $result = $this->matchHideL10nSiblingsCondition($condition);
-                               break;
-                       case 'REC':
-                               $result = $this->matchRecordCondition($condition);
-                               break;
-                       case 'VERSION':
-                               $result = $this->matchVersionCondition($condition);
-                               break;
-                       case 'USER':
-                               $result = $this->matchUserCondition($condition);
-                               break;
-               }
-               return $result;
-       }
-
-       /**
-        * Evaluates conditions concerning extensions
-        *
-        * Example:
-        * "EXT:saltedpasswords:LOADED:TRUE" => TRUE, if extension saltedpasswords is loaded.
-        *
-        * @param string $condition
-        * @return bool
-        */
-       protected function matchExtensionCondition($condition) {
-               $result = FALSE;
-               list($extensionKey, $operator, $operand) = explode(':', $condition, 3);
-               if ($operator === 'LOADED') {
-                       if (strtoupper($operand) === 'TRUE') {
-                               $result = ExtensionManagementUtility::isLoaded($extensionKey);
-                       } elseif (strtoupper($operand) === 'FALSE') {
-                               $result = !ExtensionManagementUtility::isLoaded($extensionKey);
-                       }
-               }
-               return $result;
-       }
-
-       /**
-        * Evaluates conditions concerning a field of the current record.
-        * Requires a record set via ->setRecord()
-        *
-        * Example:
-        * "FIELD:sys_language_uid:>:0" => TRUE, if the field 'sys_language_uid' is greater than 0
-        *
-        * @param string $condition
-        * @return bool
-        */
-       protected function matchFieldCondition($condition) {
-               list($fieldName, $operator, $operand) = explode(':', $condition, 3);
-               if ($this->flexformValueKey) {
-                       if (strpos($fieldName, 'parentRec.') !== FALSE) {
-                               $fieldNameParts = explode('.', $fieldName, 2);
-                               $fieldValue = $this->record['parentRec'][$fieldNameParts[1]];
-                       } else {
-                               $fieldValue = $this->record[$fieldName][$this->flexformValueKey];
-                       }
-               } else {
-                       $fieldValue = $this->record[$fieldName];
-               }
-
-               $result = FALSE;
-               switch ($operator) {
-                       case 'REQ':
-                               if (strtoupper($operand) === 'TRUE') {
-                                       $result = (bool)$fieldValue;
-                               } else {
-                                       $result = !$fieldValue;
-                               }
-                               break;
-                       case '>':
-                               $result = $fieldValue > $operand;
-                               break;
-                       case '<':
-                               $result = $fieldValue < $operand;
-                               break;
-                       case '>=':
-                               $result = $fieldValue >= $operand;
-                               break;
-                       case '<=':
-                               $result = $fieldValue <= $operand;
-                               break;
-                       case '-':
-                       case '!-':
-                               list($minimum, $maximum) = explode('-', $operand);
-                               $result = $fieldValue >= $minimum && $fieldValue <= $maximum;
-                               if ($operator[0] === '!') {
-                                       $result = !$result;
-                               }
-                               break;
-                       case 'IN':
-                       case '!IN':
-                       case '=':
-                       case '!=':
-                               $result = \TYPO3\CMS\Core\Utility\GeneralUtility::inList($operand, $fieldValue);
-                               if ($operator[0] === '!') {
-                                       $result = !$result;
-                               }
-                               break;
-                       case 'BIT':
-                       case '!BIT':
-                               $result = (bool)((int)$fieldValue & $operand);
-                               if ($operator[0] === '!') {
-                                       $result = !$result;
-                               }
-                               break;
-               }
-               return $result;
-       }
-
-       /**
-        * Evaluates TRUE if current backend user is an admin.
-        *
-        * @return bool
-        */
-       protected function matchHideForNonAdminsCondition() {
-               return (bool)$this->getBackendUser()->isAdmin();
-       }
-
-       /**
-        * Evaluates whether the field is a value for the default language.
-        * Works only for <langChildren>=1, otherwise it has no effect.
-        *
-        * @param string $condition
-        * @return bool
-        */
-       protected function matchHideL10nSiblingsCondition($condition) {
-               $result = FALSE;
-               if ($this->flexformValueKey === 'vDEF') {
-                       $result = TRUE;
-               } elseif ($condition === 'except_admin' && $this->getBackendUser()->isAdmin()) {
-                       $result = TRUE;
-               }
-               return $result;
-       }
-
-       /**
-        * Evaluates conditions concerning the status of the current record.
-        * Requires a record set via ->setRecord()
-        *
-        * Example:
-        * "REC:NEW:FALSE" => TRUE, if the record is already persisted (has a uid > 0)
-        *
-        * @param string $condition
-        * @return bool
-        */
-       protected function matchRecordCondition($condition) {
-               $result = FALSE;
-               list($operator, $operand) = explode(':', $condition, 2);
-               if ($operator === 'NEW') {
-                       if (strtoupper($operand) === 'TRUE') {
-                               $result = !((int)$this->record['uid'] > 0);
-                       } elseif (strtoupper($operand) === 'FALSE') {
-                               $result = ((int)$this->record['uid'] > 0);
-                       }
-               }
-               return $result;
-       }
-
-       /**
-        * Evaluates whether the current record is versioned.
-        * Requires a record set via ->setRecord()
-        *
-        * @param string $condition
-        * @return bool
-        */
-       protected function matchVersionCondition($condition) {
-               $result = FALSE;
-               list($operator, $operand) = explode(':', $condition, 2);
-               if ($operator === 'IS') {
-                       $isNewRecord = !((int)$this->record['uid'] > 0);
-                       // Detection of version can be done be detecting the workspace of the user
-                       $isUserInWorkspace = $this->getBackendUser()->workspace > 0;
-                       if ((int)$this->record['pid'] === -1 || (int)$this->record['_ORIG_pid'] === -1) {
-                               $isRecordDetectedAsVersion = TRUE;
-                       } else {
-                               $isRecordDetectedAsVersion = FALSE;
-                       }
-                       // New records in a workspace are not handled as a version record
-                       // if it's no new version, we detect versions like this:
-                       // -- if user is in workspace: always TRUE
-                       // -- if editor is in live ws: only TRUE if pid == -1
-                       $isVersion = ($isUserInWorkspace || $isRecordDetectedAsVersion) && !$isNewRecord;
-                       if (strtoupper($operand) === 'TRUE') {
-                               $result = $isVersion;
-                       } elseif (strtoupper($operand) === 'FALSE') {
-                               $result = !$isVersion;
-                       }
-               }
-               return $result;
-       }
-
-       /**
-        * Get current backend user
-        *
-        * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
-        */
-       protected function getBackendUser() {
-               return $GLOBALS['BE_USER'];
-       }
-
-       /**
-        * Evaluates via the referenced user-defined method
-        *
-        * @param string $condition
-        * @return bool
-        */
-       protected function matchUserCondition($condition) {
-               $conditionParameters = explode(':', $condition);
-               $userFunction = array_shift($conditionParameters);
-
-               $parameter = array(
-                       'record' => $this->record,
-                       'flexformValueKey' => $this->flexformValueKey,
-                       'conditionParameters' => $conditionParameters
-               );
-
-               return (bool)\TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($userFunction, $parameter, $this);
-       }
-}
diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/EvaluateDisplayConditions.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/EvaluateDisplayConditions.php
new file mode 100644 (file)
index 0000000..5937c01
--- /dev/null
@@ -0,0 +1,491 @@
+<?php
+namespace TYPO3\CMS\Backend\Form\FormDataProvider;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
+use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Class EvaluateDisplayConditions implements the TCA 'displayCond' option.
+ * The display condition is a colon separated string which describes
+ * the condition to decide whether a form field should be displayed.
+ */
+class EvaluateDisplayConditions implements FormDataProviderInterface {
+
+       /**
+        * Remove fields from processedTca columns that should not be displayed.
+        *
+        * @param array $result
+        * @return array
+        */
+       public function addData(array $result) {
+               $result = $this->removeFlexformFields($result);
+               $result = $this->removeFlexformSheets($result);
+               $result = $this->removeTcaColumns($result);
+
+               return $result;
+       }
+
+       /**
+        * Evaluate the TCA column display conditions and remove columns that are not displayed
+        *
+        * @param array $result
+        * @return array
+        */
+       protected function removeTcaColumns($result) {
+               foreach ($result['processedTca']['columns'] as $columnName => $columnConfiguration) {
+                       if (!isset($columnConfiguration['displayCond'])) {
+                               continue;
+                       }
+
+                       if (!$this->evaluateDisplayCondition($columnConfiguration['displayCond'], $result['databaseRow'])) {
+                               unset($result['processedTca']['columns'][$columnName]);
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * Remove flexform sheets from processed tca if hidden by display conditions
+        *
+        * @param array $result
+        * @return array
+        */
+       protected function removeFlexformSheets($result) {
+               foreach ($result['processedTca']['columns'] as $columnName => $columnConfiguration) {
+                       if (!isset($columnConfiguration['config']['type'])
+                               || $columnConfiguration['config']['type'] !== 'flex'
+                               || !isset($result['processedTca']['columns'][$columnName]['config']['ds']['sheets'])
+                               || !is_array($result['processedTca']['columns'][$columnName]['config']['ds']['sheets'])
+                       ) {
+                               continue;
+                       }
+
+                       $flexFormRowData = is_array($result['databaseRow'][$columnName]['data']) ? $result['databaseRow'][$columnName]['data'] : array();
+                       $flexFormRowData = $this->flattenFlexformRowData($flexFormRowData);
+                       $flexFormRowData['parentRec'] = $result['databaseRow'];
+
+                       $flexFormSheets = $result['processedTca']['columns'][$columnName]['config']['ds']['sheets'];
+                       foreach ($flexFormSheets as $sheetName => $sheetConfiguration) {
+                               if (!isset($sheetConfiguration['ROOT']['displayCond'])) {
+                                       continue;
+                               }
+                               if (!$this->evaluateDisplayCondition($sheetConfiguration['ROOT']['displayCond'], $flexFormRowData, TRUE)) {
+                                       unset($result['processedTca']['columns'][$columnName]['config']['ds']['sheets'][$sheetName]);
+                               }
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * Remove fields from flexform sheets if hidden by display conditions
+        *
+        * @param array $result
+        * @return array
+        */
+       protected function removeFlexformFields($result) {
+               foreach ($result['processedTca']['columns'] as $columnName => $columnConfiguration) {
+                       if (!isset($columnConfiguration['config']['type'])
+                               || $columnConfiguration['config']['type'] !== 'flex'
+                               || !isset($result['processedTca']['columns'][$columnName]['config']['ds']['sheets'])
+                               || !is_array($result['processedTca']['columns'][$columnName]['config']['ds']['sheets'])
+                       ) {
+                               continue;
+                       }
+
+                       $flexFormRowData = is_array($result['databaseRow'][$columnName]['data']) ? $result['databaseRow'][$columnName]['data'] : array();
+                       $flexFormRowData['parentRec'] = $result['databaseRow'];
+
+                       foreach ($result['processedTca']['columns'][$columnName]['config']['ds']['sheets'] as $sheetName => $sheetConfiguration) {
+                               $flexFormSheetRowData = $flexFormRowData[$sheetName]['lDEF'];
+                               $flexFormSheetRowData['parentRec'] = $result['databaseRow'];
+                               $result['processedTca']['columns'][$columnName]['config']['ds']['sheets'] = $this->removeFlexformFieldsRecursive(
+                                       $result['processedTca']['columns'][$columnName]['config']['ds']['sheets'],
+                                       $flexFormSheetRowData
+                               );
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
+        * Remove fields from flexform data structure
+        *
+        * @param array $structure Given hierarchy
+        * @param array $flexFormRowData
+        * @return array Modified hierarchy
+        */
+       protected function removeFlexformFieldsRecursive($structure, $flexFormRowData) {
+               $newStructure = [];
+               foreach ($structure as $key => $value) {
+                       if ($key === 'el' && is_array($value)) {
+                               $newSubStructure = [];
+                               foreach ($value as $subKey => $subValue) {
+                                       if (!isset($subValue['displayCond']) || $this->evaluateDisplayCondition($subValue['displayCond'], $flexFormRowData, TRUE)) {
+                                               $newSubStructure[$subKey] = $subValue;
+                                       }
+                               }
+                               $value = $newSubStructure;
+                       }
+                       if (is_array($value)) {
+                               $value = $this->removeFlexformFieldsRecursive($value, $flexFormRowData);
+                       }
+                       $newStructure[$key] = $value;
+               }
+
+               return $newStructure;
+       }
+
+       /**
+        * Flatten the Flexform data row for sheet level display conditions that use SheetName.FieldName
+        *
+        * @param array $flexFormRowData
+        * @return array
+        */
+       protected function flattenFlexformRowData($flexFormRowData) {
+               $flatFlexFormRowData = [];
+               foreach ($flexFormRowData as $sheetName => $sheetConfiguration) {
+                       foreach ($sheetConfiguration['lDEF'] as $fieldName => $fieldConfiguration) {
+                               $flatFlexFormRowData[$sheetName . '.' . $fieldName] = $fieldConfiguration;
+                       }
+               }
+
+               return $flatFlexFormRowData;
+       }
+
+       /**
+        * Evaluates the provided condition and returns TRUE if the form
+        * element should be displayed.
+        *
+        * The condition string is separated by colons and the first part
+        * indicates what type of evaluation should be performed.
+        *
+        * @param string $displayCondition
+        * @param array $record
+        * @param bool $flexformContext
+        * @param int $recursionLevel Internal level of recursion
+        * @return bool TRUE if condition evaluates successfully
+        */
+       protected function evaluateDisplayCondition($displayCondition, array $record = array(), $flexformContext = FALSE, $recursionLevel = 0) {
+               if ($recursionLevel > 99) {
+                       // This should not happen, treat as misconfiguration
+                       return TRUE;
+               }
+               if (!is_array($displayCondition)) {
+                       // DisplayCondition is not an array - just get its value
+                       $result = $this->evaluateSingleDisplayCondition($displayCondition, $record, $flexformContext);
+               } else {
+                       // Multiple conditions given as array ('AND|OR' => condition array)
+                       $conditionEvaluations = array(
+                               'AND' => array(),
+                               'OR' => array(),
+                       );
+                       foreach ($displayCondition as $logicalOperator => $groupedDisplayConditions) {
+                               $logicalOperator = strtoupper($logicalOperator);
+                               if (($logicalOperator !== 'AND' && $logicalOperator !== 'OR') || !is_array($groupedDisplayConditions)) {
+                                       // Invalid line. Skip it.
+                                       continue;
+                               } else {
+                                       foreach ($groupedDisplayConditions as $key => $singleDisplayCondition) {
+                                               $key = strtoupper($key);
+                                               if (($key === 'AND' || $key === 'OR') && is_array($singleDisplayCondition)) {
+                                                       // Recursion statement: condition is 'AND' or 'OR' and is pointing to an array (should be conditions again)
+                                                       $conditionEvaluations[$logicalOperator][] = $this->evaluateDisplayCondition(
+                                                               array($key => $singleDisplayCondition),
+                                                               $record,
+                                                               $flexformContext,
+                                                               $recursionLevel + 1
+                                                       );
+                                               } else {
+                                                       // Condition statement: collect evaluation of this single condition.
+                                                       $conditionEvaluations[$logicalOperator][] = $this->evaluateSingleDisplayCondition(
+                                                               $singleDisplayCondition,
+                                                               $record,
+                                                               $flexformContext
+                                                       );
+                                               }
+                                       }
+                               }
+                       }
+                       if (!empty($conditionEvaluations['OR']) && in_array(TRUE, $conditionEvaluations['OR'], TRUE)) {
+                               // There are OR conditions and at least one of them is TRUE
+                               $result = TRUE;
+                       } elseif (!empty($conditionEvaluations['AND']) && !in_array(FALSE, $conditionEvaluations['AND'], TRUE)) {
+                               // There are AND conditions and none of them is FALSE
+                               $result = TRUE;
+                       } elseif (!empty($conditionEvaluations['OR']) || !empty($conditionEvaluations['AND'])) {
+                               // There are some conditions. But no OR was TRUE and at least one AND was FALSE
+                               $result = FALSE;
+                       } else {
+                               // There are no proper conditions - misconfiguration. Return TRUE.
+                               $result = TRUE;
+                       }
+               }
+               return $result;
+       }
+
+       /**
+        * Evaluates the provided condition and returns TRUE if the form
+        * element should be displayed.
+        *
+        * The condition string is separated by colons and the first part
+        * indicates what type of evaluation should be performed.
+        *
+        * @param string $displayCondition
+        * @param array $record
+        * @param bool $flexformContext
+        * @return bool
+        * @see evaluateDisplayCondition()
+        */
+       protected function evaluateSingleDisplayCondition($displayCondition, array $record = array(), $flexformContext = FALSE) {
+               $result = FALSE;
+               list($matchType, $condition) = explode(':', $displayCondition, 2);
+               switch ($matchType) {
+                       case 'EXT':
+                               $result = $this->matchExtensionCondition($condition);
+                               break;
+                       case 'FIELD':
+                               $result = $this->matchFieldCondition($condition, $record, $flexformContext);
+                               break;
+                       case 'HIDE_FOR_NON_ADMINS':
+                               $result = $this->matchHideForNonAdminsCondition();
+                               break;
+                       case 'HIDE_L10N_SIBLINGS':
+                               $result = $this->matchHideL10nSiblingsCondition();
+                               break;
+                       case 'REC':
+                               $result = $this->matchRecordCondition($condition, $record);
+                               break;
+                       case 'VERSION':
+                               $result = $this->matchVersionCondition($condition, $record);
+                               break;
+                       case 'USER':
+                               $result = $this->matchUserCondition($condition, $record);
+                               break;
+               }
+               return $result;
+       }
+
+       /**
+        * Evaluates conditions concerning extensions
+        *
+        * Example:
+        * "EXT:saltedpasswords:LOADED:TRUE" => TRUE, if extension saltedpasswords is loaded.
+        *
+        * @param string $condition
+        * @return bool
+        */
+       protected function matchExtensionCondition($condition) {
+               $result = FALSE;
+               list($extensionKey, $operator, $operand) = explode(':', $condition, 3);
+               if ($operator === 'LOADED') {
+                       if (strtoupper($operand) === 'TRUE') {
+                               $result = ExtensionManagementUtility::isLoaded($extensionKey);
+                       } elseif (strtoupper($operand) === 'FALSE') {
+                               $result = !ExtensionManagementUtility::isLoaded($extensionKey);
+                       }
+               }
+               return $result;
+       }
+
+       /**
+        * Evaluates conditions concerning a field of the current record.
+        * Requires a record set via ->setRecord()
+        *
+        * Example:
+        * "FIELD:sys_language_uid:>:0" => TRUE, if the field 'sys_language_uid' is greater than 0
+        *
+        * @param string $condition
+        * @param array $record
+        * @param bool $flexformContext
+        * @return bool
+        */
+       protected function matchFieldCondition($condition, $record, $flexformContext = FALSE) {
+               list($fieldName, $operator, $operand) = explode(':', $condition, 3);
+               if ($flexformContext) {
+                       if (strpos($fieldName, 'parentRec.') !== FALSE) {
+                               $fieldNameParts = explode('.', $fieldName, 2);
+                               $fieldValue = $record['parentRec'][$fieldNameParts[1]];
+                       } else {
+                               $fieldValue = $record[$fieldName]['vDEF'];
+                       }
+               } else {
+                       $fieldValue = $record[$fieldName];
+               }
+               $result = FALSE;
+               switch ($operator) {
+                       case 'REQ':
+                               if (strtoupper($operand) === 'TRUE') {
+                                       $result = (bool)$fieldValue;
+                               } else {
+                                       $result = !$fieldValue;
+                               }
+                               break;
+                       case '>':
+                               $result = $fieldValue > $operand;
+                               break;
+                       case '<':
+                               $result = $fieldValue < $operand;
+                               break;
+                       case '>=':
+                               $result = $fieldValue >= $operand;
+                               break;
+                       case '<=':
+                               $result = $fieldValue <= $operand;
+                               break;
+                       case '-':
+                       case '!-':
+                               list($minimum, $maximum) = explode('-', $operand);
+                               $result = $fieldValue >= $minimum && $fieldValue <= $maximum;
+                               if ($operator[0] === '!') {
+                                       $result = !$result;
+                               }
+                               break;
+                       case 'IN':
+                       case '!IN':
+                       case '=':
+                       case '!=':
+                               $result = is_array($fieldValue)
+                                       ? in_array($operand, $fieldValue)
+                                       : GeneralUtility::inList($operand, $fieldValue);
+                               if ($operator[0] === '!') {
+                                       $result = !$result;
+                               }
+                               break;
+                       case 'BIT':
+                       case '!BIT':
+                               $result = (bool)((int)$fieldValue & $operand);
+                               if ($operator[0] === '!') {
+                                       $result = !$result;
+                               }
+                               break;
+               }
+               return $result;
+       }
+
+       /**
+        * Evaluates TRUE if current backend user is an admin.
+        *
+        * @return bool
+        */
+       protected function matchHideForNonAdminsCondition() {
+               return (bool)$this->getBackendUser()->isAdmin();
+       }
+
+       /**
+        * Evaluates whether the field is a value for the default language.
+        * Works only for <langChildren>=1, otherwise it has no effect.
+        *
+        * @return bool
+        * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
+        */
+       protected function matchHideL10nSiblingsCondition() {
+               GeneralUtility::deprecationLog('HIDE_L10N_SIBLINGS in Flexform display conditions has been deprecated with TYPO3 CMS 7 and will be removed with TYPO3 CMS 8.');
+               return TRUE;
+       }
+
+       /**
+        * Evaluates conditions concerning the status of the current record.
+        * Requires a record set via ->setRecord()
+        *
+        * Example:
+        * "REC:NEW:FALSE" => TRUE, if the record is already persisted (has a uid > 0)
+        *
+        * @param string $condition
+        * @param array $record
+        * @return bool
+        */
+       protected function matchRecordCondition($condition, $record) {
+               $result = FALSE;
+               list($operator, $operand) = explode(':', $condition, 2);
+               if ($operator === 'NEW') {
+                       if (strtoupper($operand) === 'TRUE') {
+                               $result = !((int)$record['uid'] > 0);
+                       } elseif (strtoupper($operand) === 'FALSE') {
+                               $result = ((int)$record['uid'] > 0);
+                       }
+               }
+               return $result;
+       }
+
+       /**
+        * Evaluates whether the current record is versioned.
+        * Requires a record set via ->setRecord()
+        *
+        * @param string $condition
+        * @param array $record
+        * @return bool
+        */
+       protected function matchVersionCondition($condition, $record) {
+               $result = FALSE;
+               list($operator, $operand) = explode(':', $condition, 2);
+               if ($operator === 'IS') {
+                       $isNewRecord = !((int)$record['uid'] > 0);
+                       // Detection of version can be done be detecting the workspace of the user
+                       $isUserInWorkspace = $this->getBackendUser()->workspace > 0;
+                       if ((int)$record['pid'] === -1 || (int)$record['_ORIG_pid'] === -1) {
+                               $isRecordDetectedAsVersion = TRUE;
+                       } else {
+                               $isRecordDetectedAsVersion = FALSE;
+                       }
+                       // New records in a workspace are not handled as a version record
+                       // if it's no new version, we detect versions like this:
+                       // -- if user is in workspace: always TRUE
+                       // -- if editor is in live ws: only TRUE if pid == -1
+                       $isVersion = ($isUserInWorkspace || $isRecordDetectedAsVersion) && !$isNewRecord;
+                       if (strtoupper($operand) === 'TRUE') {
+                               $result = $isVersion;
+                       } elseif (strtoupper($operand) === 'FALSE') {
+                               $result = !$isVersion;
+                       }
+               }
+               return $result;
+       }
+
+       /**
+        * Evaluates via the referenced user-defined method
+        *
+        * @param string $condition
+        * @param array $record
+        * @return bool
+        */
+       protected function matchUserCondition($condition, $record) {
+               $conditionParameters = explode(':', $condition);
+               $userFunction = array_shift($conditionParameters);
+
+               $parameter = array(
+                       'record' => $record,
+                       'flexformValueKey' => 'vDEF',
+                       'conditionParameters' => $conditionParameters
+               );
+
+               return (bool)GeneralUtility::callUserFunction($userFunction, $parameter, $this);
+       }
+
+       /**
+        * Get current backend user
+        *
+        * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+        */
+       protected function getBackendUser() {
+               return $GLOBALS['BE_USER'];
+       }
+
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Form/ElementConditionMatcherTest.php b/typo3/sysext/backend/Tests/Unit/Form/ElementConditionMatcherTest.php
deleted file mode 100644 (file)
index 4f5f676..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-<?php
-namespace TYPO3\CMS\Backend\Tests\Unit\Form\Element;
-
-/*
- * This file is part of the TYPO3 CMS project.
- *
- * It is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, either version 2
- * of the License, or any later version.
- *
- * For the full copyright and license information, please read the
- * LICENSE.txt file that was distributed with this source code.
- *
- * The TYPO3 project - inspiring people to share!
- */
-
-/**
- * Test case
- */
-class ElementConditionMatcherTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
-
-       /**
-        * @var \TYPO3\CMS\Backend\Form\ElementConditionMatcher
-        */
-       protected $subject;
-
-       /**
-        * Sets up this test case.
-        */
-       protected function setUp() {
-               $this->subject = new \TYPO3\CMS\Backend\Form\ElementConditionMatcher();
-       }
-
-       /**
-        * Returns data sets for the test matchConditionStrings
-        * Each dataset is an array with the following elements:
-        * - the condition string
-        * - the current record
-        * - the current flexform value key
-        * - the expected result
-        *
-        * @return array
-        */
-       public function conditionStringDataProvider() {
-               return array(
-                       'Invalid condition string' => array(
-                               'xINVALIDx:',
-                               array(),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Not loaded extension compares to loaded as FALSE' => array(
-                               'EXT:neverloadedext:LOADED:TRUE',
-                               array(),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Not loaded extension compares to not loaded as TRUE' => array(
-                               'EXT:neverloadedext:LOADED:FALSE',
-                               array(),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Loaded extension compares to TRUE' => array(
-                               'EXT:backend:LOADED:TRUE',
-                               array(),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Loaded extension compares to FALSE' => array(
-                               'EXT:backend:LOADED:FALSE',
-                               array(),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Field is not greater zero if not given' => array(
-                               'FIELD:uid:>:0',
-                               array(),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Field is not equal 0 if not given' => array(
-                               'FIELD:uid:=:0',
-                               array(),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Field value string comparison' => array(
-                               'FIELD:foo:=:bar',
-                               array('foo' => 'bar'),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Field value comparison of 1 against multi-value field of 5 returns true' => array(
-                               'FIELD:content:BIT:1',
-                               array('content' => '5'),
-                               NULL,
-                               TRUE
-                       ),
-                       'Field value comparison of 2 against multi-value field of 5 returns false' => array(
-                               'FIELD:content:BIT:2',
-                               array('content' => '5'),
-                               NULL,
-                               FALSE
-                       ),
-                       'Field value of 5 negated comparison against multi-value field of 5 returns false' => array(
-                               'FIELD:content:!BIT:5',
-                               array('content' => '5'),
-                               NULL,
-                               FALSE
-                       ),
-                       'Field value comparison for required value is false for different value' => array(
-                               'FIELD:foo:REQ:FALSE',
-                               array('foo' => 'bar'),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Field value string not equal comparison' => array(
-                               'FIELD:foo:!=:baz',
-                               array('foo' => 'bar'),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Field value in range' => array(
-                               'FIELD:uid:-:3-42',
-                               array('uid' => '23'),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Field value greater than' => array(
-                               'FIELD:uid:>=:42',
-                               array('uid' => '23'),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Flexform value invalid comparison' => array(
-                               'FIELD:foo:=:bar',
-                               array(
-                                       'foo' => array(
-                                               'vDEF' => 'bar'
-                                       ),
-                               ),
-                               'vDEF',
-                               TRUE,
-                       ),
-                       'Flexform value valid comparison' => array(
-                               'FIELD:parentRec.foo:=:bar',
-                               array(
-                                       'parentRec' => array(
-                                               'foo' => 'bar'
-                                       ),
-                               ),
-                               'vDEF',
-                               TRUE,
-                       ),
-                       'Field is value for default language without flexform' => array(
-                               'HIDE_L10N_SIBLINGS',
-                               array(),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Field is value for default language with flexform' => array(
-                               'HIDE_L10N_SIBLINGS',
-                               array(),
-                               'vDEF',
-                               TRUE,
-                       ),
-                       'Field is value for default language with sibling' => array(
-                               'HIDE_L10N_SIBLINGS',
-                               array(),
-                               'vEN',
-                               FALSE,
-                       ),
-                       'New is TRUE for new comparison with TRUE' => array(
-                               'REC:NEW:TRUE',
-                               array('uid' => NULL),
-                               NULL,
-                               TRUE,
-                       ),
-                       'New is FALSE for new comparison with FALSE' => array(
-                               'REC:NEW:FALSE',
-                               array('uid' => NULL),
-                               NULL,
-                               FALSE,
-                       ),
-                       'New is FALSE for not new element' => array(
-                               'REC:NEW:TRUE',
-                               array('uid' => 42),
-                               NULL,
-                               FALSE,
-                       ),
-                       'New is TRUE for not new element compared to FALSE' => array(
-                               'REC:NEW:FALSE',
-                               array('uid' => 42),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Version is TRUE for versioned row' => array(
-                               'VERSION:IS:TRUE',
-                               array(
-                                       'uid' => 42,
-                                       'pid' => -1
-                               ),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Version is TRUE for not versioned row compared with FALSE' => array(
-                               'VERSION:IS:FALSE',
-                               array(
-                                       'uid' => 42,
-                                       'pid' => 1
-                               ),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Version is TRUE for NULL row compared with TRUE' => array(
-                               'VERSION:IS:TRUE',
-                               array(
-                                       'uid' => NULL,
-                                       'pid' => NULL,
-                               ),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Multiple conditions with AND compare to TRUE if all are OK' => array(
-                               array(
-                                       'AND' => array(
-                                               'FIELD:testField:>:9',
-                                               'FIELD:testField:<:11',
-                                       ),
-                               ),
-                               array(
-                                       'testField' => 10
-                               ),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Multiple conditions with AND compare to FALSE if one fails' => array(
-                               array(
-                                       'AND' => array(
-                                               'FIELD:testField:>:9',
-                                               'FIELD:testField:<:11',
-                                       )
-                               ),
-                               array(
-                                       'testField' => 99
-                               ),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Multiple conditions with OR compare to TRUE if one is OK' => array(
-                               array(
-                                       'OR' => array(
-                                               'FIELD:testField:<:9',
-                                               'FIELD:testField:<:11',
-                                       ),
-                               ),
-                               array(
-                                       'testField' => 10
-                               ),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Multiple conditions with OR compare to FALSE is all fail' => array(
-                               array(
-                                       'OR' => array(
-                                               'FIELD:testField:<:9',
-                                               'FIELD:testField:<:11',
-                                       ),
-                               ),
-                               array(
-                                       'testField' => 99
-                               ),
-                               NULL,
-                               FALSE,
-                       ),
-                       'Multiple conditions without operator due to misconfiguration compare to TRUE' => array(
-                               array(
-                                       '' => array(
-                                               'FIELD:testField:<:9',
-                                               'FIELD:testField:>:11',
-                                       )
-                               ),
-                               array(
-                                       'testField' => 99
-                               ),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Multiple nested conditions evaluate to TRUE' => array(
-                               array(
-                                       'AND' => array(
-                                               'FIELD:testField:>:9',
-                                               'OR' => array(
-                                                       'FIELD:testField:<:100',
-                                                       'FIELD:testField:>:-100',
-                                               ),
-                                       ),
-                               ),
-                               array(
-                                       'testField' => 10
-                               ),
-                               NULL,
-                               TRUE,
-                       ),
-                       'Multiple nested conditions evaluate to FALSE' => array(
-                               array(
-                                       'AND' => array(
-                                               'FIELD:testField:>:9',
-                                               'OR' => array(
-                                                       'FIELD:testField:<:100',
-                                                       'FIELD:testField:>:-100',
-                                               ),
-                                       ),
-                               ),
-                               array(
-                                       'testField' => -999
-                               ),
-                               NULL,
-                               FALSE,
-                       ),
-               );
-       }
-
-       /**
-        * @param string $condition
-        * @param array $record
-        * @param string $flexformValueKey
-        * @param string $expectedResult
-        * @dataProvider conditionStringDataProvider
-        * @test
-        */
-       public function matchConditionStrings($condition, array $record, $flexformValueKey, $expectedResult) {
-               $this->assertEquals($expectedResult, $this->subject->match($condition, $record, $flexformValueKey));
-       }
-
-       /**
-        * @test
-        */
-       public function matchHideForNonAdminsReturnsTrueIfBackendUserIsAdmin() {
-               /** @var $backendUserMock \TYPO3\CMS\Core\Authentication\BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject */
-               $backendUserMock = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
-               $backendUserMock
-                       ->expects($this->once())
-                       ->method('isAdmin')
-                       ->will($this->returnValue(TRUE));
-               $GLOBALS['BE_USER'] = $backendUserMock;
-               $this->assertTrue($this->subject->match('HIDE_FOR_NON_ADMINS'));
-       }
-
-       /**
-        * @test
-        */
-       public function matchHideForNonAdminsReturnsFalseIfBackendUserIsNotAdmin() {
-               /** @var $backendUserMock \TYPO3\CMS\Core\Authentication\BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject */
-               $backendUserMock = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
-               $backendUserMock
-                       ->expects($this->once())
-                       ->method('isAdmin')
-                       ->will($this->returnValue(FALSE));
-               $GLOBALS['BE_USER'] = $backendUserMock;
-               $this->assertFalse($this->subject->match('HIDE_FOR_NON_ADMINS'));
-       }
-
-       /**
-        * @test
-        */
-       public function matchHideL10NSiblingsExceptAdminReturnsTrueIfBackendUserIsAdmin() {
-               /** @var $backendUserMock \TYPO3\CMS\Core\Authentication\BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject */
-               $backendUserMock = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
-               $backendUserMock
-                       ->expects($this->once())
-                       ->method('isAdmin')
-                       ->will($this->returnValue(TRUE));
-               $GLOBALS['BE_USER'] = $backendUserMock;
-               $this->assertTrue($this->subject->match('HIDE_L10N_SIBLINGS:except_admin'), array(), 'vEN');
-       }
-
-       /**
-        * @test
-        */
-       public function matchHideL10NSiblingsExceptAdminReturnsFalseIfBackendUserIsNotAdmin() {
-               /** @var $backendUserMock \TYPO3\CMS\Core\Authentication\BackendUserAuthentication|\PHPUnit_Framework_MockObject_MockObject */
-               $backendUserMock = $this->getMock(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
-               $backendUserMock
-                       ->expects($this->once())
-                       ->method('isAdmin')
-                       ->will($this->returnValue(FALSE));
-               $GLOBALS['BE_USER'] = $backendUserMock;
-               $this->assertFalse($this->subject->match('HIDE_L10N_SIBLINGS:except_admin'), array(), 'vEN');
-       }
-
-}
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/EvaluateDisplayConditionsTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/EvaluateDisplayConditionsTest.php
new file mode 100644 (file)
index 0000000..84e526d
--- /dev/null
@@ -0,0 +1,692 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Prophecy\Prophecy\ObjectProphecy;
+use TYPO3\CMS\Backend\Form\FormDataProvider\EvaluateDisplayConditions;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+
+/**
+ * Test case
+ */
+class EvaluateDisplayConditionsTest extends UnitTestCase {
+
+       /**
+        * @var EvaluateDisplayConditions
+        */
+       protected $subject;
+
+       public function setUp() {
+               $this->subject = new EvaluateDisplayConditions();
+       }
+
+       /**
+        * @test
+        */
+       public function addDataRemovesTcaColumnsHiddenByDisplayCondition() {
+               $input = [
+                       'databaseRow' => [
+                               'aField' => 'aField',
+                               'bField' => 'bField',
+                               'cField' => 1,
+                       ],
+                       'recordTypeValue' => 'aType',
+                       'processedTca' => [
+                               'types' => [
+                                       'aType' => [
+                                               'showitem' => '--palette--;aPalette;2,bField,cField'
+                                       ],
+                               ],
+                               'palettes' => [
+                                       '2' => array(
+                                               'showitem' => 'aField',
+                                               'canNotCollapse' => TRUE
+                                       ),
+                               ],
+                               'columns' => [
+                                       'aField' => [
+                                               'displayCond' => 'FIELD:cField:=:0',
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                                       'bField' => [
+                                               'displayCond' => 'FIELD:cField:=:1',
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                                       'cField' => [
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ]
+                               ]
+                       ]
+               ];
+
+               $expected = $input;
+               unset($expected['processedTca']['columns']['aField']);
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataRemovesFlexformSheetsHiddenByDisplayCondition() {
+               $input = [
+                       'databaseRow' => [
+                               'aField' => [
+                                       'data' => [
+                                               'sGeneral' => [
+                                                       'lDEF' => [
+                                                               'mmType' => [
+                                                                       'vDEF' => [
+                                                                               0 => 'video',
+                                                                       ],
+                                                               ],
+                                                               'mmUseHTML5' => [
+                                                                       'vDEF' => '0',
+                                                               ],
+                                                       ],
+                                               ],
+                                               'sVideo' => [
+                                                       'lDEF' => [],
+                                               ],
+                                               'sAudio' => [
+                                                       'lDEF' => []
+                                               ],
+                                       ]
+                               ]
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'flex',
+                                                       'ds' => [
+                                                               'meta' => [],
+                                                               'sheets' => [
+                                                                       'sGeneral' => [
+                                                                               'ROOT' => [
+                                                                                       'type' => 'array',
+                                                                                       'el' => [
+                                                                                               'mmType' => [
+                                                                                                       'config' => [
+                                                                                                               'type' => 'select',
+                                                                                                               'items' => [],
+                                                                                                       ],
+                                                                                               ],
+                                                                                               'mmUseHTML5' => [
+                                                                                                       'displayCond' => 'FIELD:mmType:!=:audio',
+                                                                                                       'config' => [
+                                                                                                               'type' => 'check',
+                                                                                                               'default' => '0',
+                                                                                                               'items' => [],
+                                                                                                       ],
+                                                                                               ],
+                                                                                       ],
+                                                                                       'sheetTitle' => 'sGeneral',
+                                                                               ],
+                                                                       ],
+                                                                       'sVideo' => [
+                                                                               'ROOT' => [
+                                                                                       'type' => 'array',
+                                                                                       'el' => [],
+                                                                                       'sheetTitle' => 'sVideo',
+                                                                                       'displayCond' => 'FIELD:sGeneral.mmType:!=:audio',
+                                                                               ],
+                                                                       ],
+                                                                       'sAudio' => [
+                                                                               'ROOT' => [
+                                                                                       'type' => 'array',
+                                                                                       'el' => [],
+                                                                                       'sheetTitle' => 'sAudio',
+                                                                                       'displayCond' => 'FIELD:sGeneral.mmType:=:audio',
+                                                                               ],
+                                                                       ],
+                                                               ],
+                                                       ],
+                                               ],
+                                       ],
+                               ],
+                       ],
+               ];
+
+               $expected = $input;
+               unset($expected['processedTca']['columns']['aField']['config']['ds']['sheets']['sAudio']);
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataRemovesFlexformFieldsHiddenByDisplayCondition() {
+               $input = [
+                       'databaseRow' => [
+                               'aField' => [
+                                       'data' => [
+                                               'sGeneral' => [
+                                                       'lDEF' => [
+                                                               'mmType' => [
+                                                                       'vDEF' => [
+                                                                               0 => 'audio',
+                                                                       ],
+                                                               ],
+                                                               'mmUseHTML5' => [
+                                                                       'vDEF' => '0',
+                                                               ],
+                                                       ],
+                                               ],
+                                       ]
+                               ]
+                       ],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'config' => [
+                                                       'type' => 'flex',
+                                                       'ds_pointerField' => 'list_type,CType',
+                                                       'ds' => [
+                                                               'meta' => [],
+                                                               'sheets' => [
+                                                                       'sGeneral' => [
+                                                                               'ROOT' => [
+                                                                                       'type' => 'array',
+                                                                                       'el' => [
+                                                                                               'mmType' => [
+                                                                                                       'config' => [
+                                                                                                               'type' => 'select',
+                                                                                                               'items' => [],
+                                                                                                       ],
+                                                                                               ],
+                                                                                               'mmUseHTML5' => [
+                                                                                                       'displayCond' => 'FIELD:mmType:!=:audio',
+                                                                                                       'config' => [
+                                                                                                               'type' => 'check',
+                                                                                                               'default' => '0',
+                                                                                                               'items' => [],
+                                                                                                       ],
+                                                                                               ],
+                                                                                       ],
+                                                                                       'sheetTitle' => 'aTitle',
+                                                                               ],
+                                                                       ],
+                                                               ],
+                                                       ],
+                                               ],
+                                       ],
+                               ],
+                       ],
+               ];
+
+               $expected = $input;
+               unset($expected['processedTca']['columns']['aField']['config']['ds']['sheets']['sGeneral']['ROOT']['el']['mmUseHTML5']);
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function matchHideForNonAdminsReturnsTrueIfBackendUserIsAdmin() {
+               $input = [
+                       'databaseRow' => [],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'displayCond' => 'HIDE_FOR_NON_ADMINS',
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ]
+                       ]
+               ];
+
+               /** @var BackendUserAuthentication|ObjectProphecy backendUserProphecy */
+               $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
+               $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
+               $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(TRUE);
+
+               $expected = $input;
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function matchHideForNonAdminsReturnsFalseIfBackendUserIsNotAdmin() {
+               $input = [
+                       'databaseRow' => [],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'displayCond' => 'HIDE_FOR_NON_ADMINS',
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ]
+                       ]
+               ];
+
+               /** @var BackendUserAuthentication|ObjectProphecy backendUserProphecy */
+               $backendUserProphecy = $this->prophesize(BackendUserAuthentication::class);
+               $GLOBALS['BE_USER'] = $backendUserProphecy->reveal();
+               $backendUserProphecy->isAdmin()->shouldBeCalled()->willReturn(FALSE);
+
+               $expected = $input;
+               unset($expected['processedTca']['columns']['aField']);
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * The HIDE_L10N_SIBLINGS condition is deprecated, this test only ensures that it can be successfully parsed
+        *
+        * @test
+        */
+       public function matchHideL10NSiblingsReturnsTrue() {
+               $input = [
+                       'databaseRow' => [],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'displayCond' => 'HIDE_L10N_SIBLINGS',
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ]
+                       ]
+               ];
+
+               $expected = $input;
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function matchHideL10NSiblingsExceptAdminReturnsTrue() {
+               $input = [
+                       'databaseRow' => [],
+                       'processedTca' => [
+                               'columns' => [
+                                       'aField' => [
+                                               'displayCond' => 'HIDE_L10N_SIBLINGS:except_admin',
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ]
+                       ]
+               ];
+
+               $expected = $input;
+
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * Returns data sets for the test matchConditionStrings
+        * Each data set is an array with the following elements:
+        * - the condition string
+        * - the current record
+        * - the expected result
+        *
+        * @return array
+        */
+       public function conditionStringDataProvider() {
+               return [
+                       'Invalid condition string' => [
+                               'xINVALIDx:',
+                               [],
+                               FALSE,
+                       ],
+                       'Not loaded extension compares to loaded as FALSE' => [
+                               'EXT:neverloadedext:LOADED:TRUE',
+                               [],
+                               FALSE,
+                       ],
+                       'Not loaded extension compares to not loaded as TRUE' => [
+                               'EXT:neverloadedext:LOADED:FALSE',
+                               [],
+                               TRUE,
+                       ],
+                       'Loaded extension compares to TRUE' => [
+                               'EXT:backend:LOADED:TRUE',
+                               [],
+                               TRUE,
+                       ],
+                       'Loaded extension compares to FALSE' => [
+                               'EXT:backend:LOADED:FALSE',
+                               [],
+                               FALSE,
+                       ],
+                       'Field is not greater zero if not given' => [
+                               'FIELD:uid:>:0',
+                               [],
+                               FALSE,
+                       ],
+                       'Field is not equal 0 if not given' => [
+                               'FIELD:uid:=:0',
+                               [],
+                               FALSE,
+                       ],
+                       'Field value string comparison' => [
+                               'FIELD:foo:=:bar',
+                               ['foo' => 'bar'],
+                               TRUE,
+                       ],
+                       'Field value comparison of 1 against multi-value field of 5 returns true' => [
+                               'FIELD:content:BIT:1',
+                               ['content' => '5'],
+                               TRUE
+                       ],
+                       'Field value comparison of 2 against multi-value field of 5 returns false' => [
+                               'FIELD:content:BIT:2',
+                               ['content' => '5'],
+                               FALSE
+                       ],
+                       'Field value of 5 negated comparison against multi-value field of 5 returns false' => [
+                               'FIELD:content:!BIT:5',
+                               ['content' => '5'],
+                               FALSE
+                       ],
+                       'Field value comparison for required value is false for different value' => [
+                               'FIELD:foo:REQ:FALSE',
+                               ['foo' => 'bar'],
+                               FALSE,
+                       ],
+                       'Field value string not equal comparison' => [
+                               'FIELD:foo:!=:baz',
+                               ['foo' => 'bar'],
+                               TRUE,
+                       ],
+                       'Field value in range' => [
+                               'FIELD:uid:-:3-42',
+                               ['uid' => '23'],
+                               TRUE,
+                       ],
+                       'Field value greater than' => [
+                               'FIELD:uid:>=:42',
+                               ['uid' => '23'],
+                               FALSE,
+                       ],
+                       'Field is value for default language without flexform' => [
+                               'HIDE_L10N_SIBLINGS',
+                               [],
+                               TRUE,
+                       ],
+                       'New is TRUE for new comparison with TRUE' => [
+                               'REC:NEW:TRUE',
+                               ['uid' => NULL],
+                               TRUE,
+                       ],
+                       'New is FALSE for new comparison with FALSE' => [
+                               'REC:NEW:FALSE',
+                               ['uid' => NULL],
+                               FALSE,
+                       ],
+                       'New is FALSE for not new element' => [
+                               'REC:NEW:TRUE',
+                               ['uid' => 42],
+                               FALSE,
+                       ],
+                       'New is TRUE for not new element compared to FALSE' => [
+                               'REC:NEW:FALSE',
+                               ['uid' => 42],
+                               TRUE,
+                       ],
+                       'Version is TRUE for versioned row' => [
+                               'VERSION:IS:TRUE',
+                               [
+                                       'uid' => 42,
+                                       'pid' => -1
+                               ],
+                               TRUE,
+                       ],
+                       'Version is TRUE for not versioned row compared with FALSE' => [
+                               'VERSION:IS:FALSE',
+                               [
+                                       'uid' => 42,
+                                       'pid' => 1
+                               ],
+                               TRUE,
+                       ],
+                       'Version is TRUE for NULL row compared with TRUE' => [
+                               'VERSION:IS:TRUE',
+                               [
+                                       'uid' => NULL,
+                                       'pid' => NULL,
+                               ],
+                               FALSE,
+                       ],
+                       'Multiple conditions with AND compare to TRUE if all are OK' => [
+                               [
+                                       'AND' => [
+                                               'FIELD:testField:>:9',
+                                               'FIELD:testField:<:11',
+                                       ],
+                               ],
+                               [
+                                       'testField' => 10
+                               ],
+                               TRUE,
+                       ],
+                       'Multiple conditions with AND compare to FALSE if one fails' => [
+                               [
+                                       'AND' => [
+                                               'FIELD:testField:>:9',
+                                               'FIELD:testField:<:11',
+                                       ]
+                               ],
+                               [
+                                       'testField' => 99
+                               ],
+                               FALSE,
+                       ],
+                       'Multiple conditions with OR compare to TRUE if one is OK' => [
+                               [
+                                       'OR' => [
+                                               'FIELD:testField:<:9',
+                                               'FIELD:testField:<:11',
+                                       ],
+                               ],
+                               [
+                                       'testField' => 10
+                               ],
+                               TRUE,
+                       ],
+                       'Multiple conditions with OR compare to FALSE is all fail' => [
+                               [
+                                       'OR' => [
+                                               'FIELD:testField:<:9',
+                                               'FIELD:testField:<:11',
+                                       ],
+                               ],
+                               [
+                                       'testField' => 99
+                               ],
+                               FALSE,
+                       ],
+                       'Multiple conditions without operator due to misconfiguration compare to TRUE' => [
+                               [
+                                       '' => [
+                                               'FIELD:testField:<:9',
+                                               'FIELD:testField:>:11',
+                                       ]
+                               ],
+                               [
+                                       'testField' => 99
+                               ],
+                               TRUE,
+                       ],
+                       'Multiple nested conditions evaluate to TRUE' => [
+                               [
+                                       'AND' => [
+                                               'FIELD:testField:>:9',
+                                               'OR' => [
+                                                       'FIELD:testField:<:100',
+                                                       'FIELD:testField:>:-100',
+                                               ],
+                                       ],
+                               ],
+                               [
+                                       'testField' => 10
+                               ],
+                               TRUE,
+                       ],
+                       'Multiple nested conditions evaluate to FALSE' => [
+                               [
+                                       'AND' => [
+                                               'FIELD:testField:>:9',
+                                               'OR' => [
+                                                       'FIELD:testField:<:100',
+                                                       'FIELD:testField:>:-100',
+                                               ],
+                                       ],
+                               ],
+                               [
+                                       'testField' => -999
+                               ],
+                               FALSE,
+                       ],
+               ];
+       }
+
+       /**
+        * @param string $condition
+        * @param array $record
+        * @param string $expectedResult
+        * @dataProvider conditionStringDataProvider
+        * @test
+        */
+       public function matchConditionStrings($condition, array $record, $expectedResult) {
+               $input = [
+                       'databaseRow' => $record,
+                       'processedTca' => [
+                               'columns' => [
+                                       'testField' => [
+                                               'displayCond' => $condition,
+                                               'config' => [
+                                                       'type' => 'input',
+                                               ]
+                                       ],
+                               ]
+                       ]
+               ];
+
+               $expected = $input;
+               if (!$expectedResult) {
+                       unset($expected['processedTca']['columns']['testField']);
+               }
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * Returns data sets for the test matchConditionStrings
+        * Each data set is an array with the following elements:
+        * - the condition string
+        * - the current record
+        * - the expected result
+        *
+        * @return array
+        */
+       public function flexformConditionStringDataProvider() {
+               return [
+                       'Flexform value invalid comparison' => [
+                               'FIELD:foo:=:bar',
+                               [
+                                       'foo' => 'bar',
+                                       'testField' => [
+                                               'data' => [
+                                                       'sDEF' => [
+                                                               'lDEF' => [],
+                                                       ],
+                                               ],
+                                       ],
+                               ],
+                               FALSE,
+                       ],
+                       'Flexform value valid comparison' => [
+                               'FIELD:parentRec.foo:=:bar',
+                               [
+                                       'foo' => 'bar',
+                                       'testField' => [
+                                               'data' => [
+                                                       'sDEF' => [
+                                                               'lDEF' => [],
+                                                       ],
+                                               ],
+                                       ],
+                               ],
+                               TRUE,
+                       ],
+               ];
+       }
+
+       /**
+        * @param string $condition
+        * @param array $record
+        * @param string $expectedResult
+        * @dataProvider flexformConditionStringDataProvider
+        * @test
+        */
+       public function matchFlexformConditionStrings($condition, array $record, $expectedResult) {
+               $input = [
+                       'databaseRow' => $record,
+                       'processedTca' => [
+                               'columns' => [
+                                       'testField' => [
+                                               'config' => [
+                                                       'type' => 'flex',
+                                                       'ds' => [
+                                                               'meta' => [],
+                                                               'sheets' => [
+                                                                       'sDEF' => [
+                                                                               'ROOT' => [
+                                                                                       'type' => 'array',
+                                                                                       'el' => [
+                                                                                               'flexTestField' => [
+                                                                                                       'displayCond' => $condition,
+                                                                                                       'config' => [
+                                                                                                               'type' => 'input',
+                                                                                                       ],
+                                                                                               ],
+                                                                                       ],
+                                                                               ],
+                                                                       ],
+                                                               ]
+                                                       ],
+                                               ],
+                                       ],
+                               ],
+                       ],
+               ];
+
+               $expected = $input;
+               if (!$expectedResult) {
+                       unset($expected['processedTca']['columns']['testField']['config']['ds']['sheets']['sDEF']['ROOT']['el']['flexTestField']);
+               }
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+}
index ec3c1c4..f4cf33c 100644 (file)
@@ -435,7 +435,7 @@ return array(
                                        \TYPO3\CMS\Backend\Form\FormDataProvider\TcaRadioItems::class => array(
                                                'depends' => array(
                                                        \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class,
-                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaFlexFetch::class,
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaFlexProcess::class,
                                                ),
                                        ),
                                        \TYPO3\CMS\Backend\Form\FormDataProvider\TcaCheckboxItems::class => array(
@@ -461,6 +461,11 @@ return array(
                                                        \TYPO3\CMS\Backend\Form\FormDataProvider\TcaSelectItems::class,
                                                ),
                                        ),
+                                       \TYPO3\CMS\Backend\Form\FormDataProvider\EvaluateDisplayConditions::class => array(
+                                               'depends' => array(
+                                                       \TYPO3\CMS\Backend\Form\FormDataProvider\TcaInline::class,
+                                               ),
+                                       ),
                                ),
                                'flexFormSegment' => array(
                                        \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class => array(),
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-69938-HIDE_L10N_SIBLINGSFlexFormdisplayCond.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-69938-HIDE_L10N_SIBLINGSFlexFormdisplayCond.rst
new file mode 100644 (file)
index 0000000..1259cdf
--- /dev/null
@@ -0,0 +1,15 @@
+============================================================
+Deprecation: #69938 - HIDE_L10N_SIBLINGS FlexFormdisplayCond
+============================================================
+
+Description
+===========
+
+The flexform HIDE_L10N_SIBLINGS display condition has been deprecated and will be removed with CMS 8.
+The condition could only be used with translation mode `langChildren=1` to only show the field for the default language.
+
+
+Impact
+======
+
+FlexForms using this condition will show the field separately for each language again.
\ No newline at end of file