From 71e191e24c6d6edd516d6e42b9c76f73c45924ce Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Thu, 1 Dec 2016 14:30:26 +0100
Subject: [PATCH] [BUGFIX] Opening be_groups records may throw exception

The new flex form data structure handling in more picky and throws
exception if a given data structure identifier can not be resolved.
The FormEngine logic that displays exclude fields of flex forms
has to do some guess work to find possible data structures. This
may fail, resulting in an exception.
The patch changes the according general exception to a specific one,
catches it in the find flex form access rights logic, and adds
more docu on what exactly is happening in this code.

Change-Id: I2b808cbe804ba4ab967c8d95b17c0a12ec65ffd4
Resolves: #78852
Related: #78581
Releases: master
Reviewed-on: https://review.typo3.org/50820
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Alexander Stehlik <alexander.stehlik@gmail.com>
Tested-by: Alexander Stehlik <alexander.stehlik@gmail.com>
Reviewed-by: Alexander Rothmund <alexander@rothmund.ch>
Tested-by: Alexander Rothmund <alexander@rothmund.ch>
Reviewed-by: Jan Helke <typo3@helke.de>
Tested-by: Jan Helke <typo3@helke.de>
---
 .../FormDataProvider/AbstractItemProvider.php | 25 +++++++++++++++----
 .../Configuration/FlexForm/FlexFormTools.php  |  6 +++--
 .../FlexForm/FlexFormToolsTest.php            |  2 +-
 3 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
index 717b674b1e4c..58f001feb7c2 100644
--- a/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
+++ b/typo3/sysext/backend/Classes/Form/FormDataProvider/AbstractItemProvider.php
@@ -18,6 +18,7 @@ use Doctrine\DBAL\DBALException;
 use TYPO3\CMS\Backend\Module\ModuleLoader;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidIdentifierException;
 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
@@ -793,11 +794,20 @@ abstract class AbstractItemProvider
     }
 
     /**
-     * Returns all registered FlexForm definitions
+     * Returns FlexForm data structures it finds. Used in select "special" for be_groups
+     * to set "exclude" flags for single flex form fields.
      *
-     * Note: This only finds flex forms registered in 'ds' config sections.
+     * This only finds flex forms registered in 'ds' config sections.
      * This does not resolve other sophisticated flex form data structure references.
      *
+     * @todo: This approach is limited and doesn't find everything. It works for casual tt_content plugins, though:
+     * @todo: The data structure identifier determination depends on data row, but we don't have all rows at hand here.
+     * @todo: The code thus "guesses" some standard data structure identifier scenarios and tries to resolve those.
+     * @todo: This guessing can not be solved in a good way. A general registry of "all" possible data structures is
+     * @todo: probably not wanted, since that wouldn't work for truly dynamic DS calculations. Probably the only
+     * @todo: thing we could do here is a hook to allow extensions declaring specific data structures to
+     * @todo: allow backend admins to set exclude flags for certain fields in those cases.
+     *
      * @param string $table Table to handle
      * @return array Data structures
      */
@@ -815,7 +825,6 @@ abstract class AbstractItemProvider
                     // Get extension identifier (uses second value if it's not empty, "list" or "*", else first one)
                     $identFields = GeneralUtility::trimExplode(',', $flexFormKey);
                     $extIdent = $identFields[0];
-                    // @todo: This approach is limited and doesn't find everything. It works for tt_content plugins, though.
                     if (!empty($identFields[1]) && $identFields[1] !== 'list' && $identFields[1] !== '*') {
                         $extIdent = $identFields[1];
                     }
@@ -825,8 +834,14 @@ abstract class AbstractItemProvider
                         'fieldName' => $tableField,
                         'dataStructureKey' => $flexFormKey,
                     ]);
-                    $dataStructure = $flexFormTools->parseDataStructureByIdentifier($flexFormDataStructureIdentifier);
-                    $flexForms[$tableField][$extIdent] = $dataStructure;
+                    try {
+                        $dataStructure = $flexFormTools->parseDataStructureByIdentifier($flexFormDataStructureIdentifier);
+                        $flexForms[$tableField][$extIdent] = $dataStructure;
+                    } catch (InvalidIdentifierException $e) {
+                        // Deliberately empty: The DS identifier is guesswork and the flex ds parser throws
+                        // this exception if it can not resolve to a valid data structure. This is "ok" here
+                        // and the exception is just eaten.
+                    }
                 }
             }
         }
diff --git a/typo3/sysext/core/Classes/Configuration/FlexForm/FlexFormTools.php b/typo3/sysext/core/Classes/Configuration/FlexForm/FlexFormTools.php
index 12783d2772aa..ca25544dea7b 100644
--- a/typo3/sysext/core/Classes/Configuration/FlexForm/FlexFormTools.php
+++ b/typo3/sysext/core/Classes/Configuration/FlexForm/FlexFormTools.php
@@ -689,9 +689,11 @@ class FlexFormTools
             $dataStructure = GeneralUtility::xml2array($dataStructure);
         }
 
-        // Throw if it still is not an array, probably because GeneralUtility::xml2array() failed
+        // Throw if it still is not an array, probably because GeneralUtility::xml2array() failed.
+        // This also may happen if artificial identifiers were constructed which don't resolve. The
+        // flex form "exclude" access rights systems does that -> catchable
         if (!is_array($dataStructure)) {
-            throw new \RuntimeException(
+            throw new InvalidIdentifierException(
                 'Parse error: Data structure could not be resolved to a valid structure.',
                 1478106090
             );
diff --git a/typo3/sysext/core/Tests/Unit/Configuration/FlexForm/FlexFormToolsTest.php b/typo3/sysext/core/Tests/Unit/Configuration/FlexForm/FlexFormToolsTest.php
index 47c6df434c99..28aa2d6b86f5 100644
--- a/typo3/sysext/core/Tests/Unit/Configuration/FlexForm/FlexFormToolsTest.php
+++ b/typo3/sysext/core/Tests/Unit/Configuration/FlexForm/FlexFormToolsTest.php
@@ -1314,7 +1314,7 @@ class FlexFormToolsTest extends UnitTestCase
             </T3DataStructure>
         ';
         $identifier = '{"type":"tca","tableName":"aTableName","fieldName":"aFieldName","dataStructureKey":"default"}';
-        $this->expectException(\RuntimeException::class);
+        $this->expectException(InvalidIdentifierException::class);
         $this->expectExceptionCode(1478106090);
         (new FlexFormTools())->parseDataStructureByIdentifier($identifier);
     }
-- 
GitLab