diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php b/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
new file mode 100644
index 0000000000000000000000000000000000000000..390ea7b2be432329a6b8502b9066f4111dcb4200
--- /dev/null
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
@@ -0,0 +1,354 @@
+<?php
+namespace TYPO3\CMS\Backend\Controller\Wizard;
+
+/*
+ * 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 Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Form\Wizard\SuggestWizardDefaultReceiver;
+use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Utility\MathUtility;
+
+/**
+ * Receives ajax request from FormEngine suggest wizard and creates suggest answer as json result
+ */
+class SuggestWizardController
+{
+    /**
+     * Ajax handler for the "suggest" feature in FormEngine.
+     *
+     * @param ServerRequestInterface $request
+     * @param ResponseInterface $response
+     * @throws \RuntimeException for incomplete or invalid arguments
+     * @return ResponseInterface
+     */
+    public function searchAction(ServerRequestInterface $request, ResponseInterface $response)
+    {
+        $parsedBody = $request->getParsedBody();
+
+        if (!isset($parsedBody['value'])
+            || !isset($parsedBody['table'])
+            || !isset($parsedBody['field'])
+            || !isset($parsedBody['uid'])
+            || !isset($parsedBody['dataStructureIdentifier'])
+            || !isset($parsedBody['hmac'])
+        ) {
+            throw new \RuntimeException(
+                'Missing at least one of the required arguments "value", "table", "field", "uid"'
+                . ', "dataStructureIdentifier" or "hmac"',
+                1478607036
+            );
+        }
+
+        $search = $parsedBody['value'];
+        $table = $parsedBody['table'];
+        $field = $parsedBody['field'];
+        $uid = $parsedBody['uid'];
+        $pid = (int)$parsedBody['pid'];
+
+        // flex form section container identifiers are created on js side dynamically "onClick". Those are
+        // not within the generated hmac ... the js side adds "idx{dateInMilliseconds}-", so this is removed here again.
+        // example outgoing in renderSuggestSelector():
+        // flex_1|data|sSuggestCheckCombination|lDEF|settings.subelements|el|ID-356586b0d3-form|item|el|content|vDEF
+        // incoming here:
+        // flex_1|data|sSuggestCheckCombination|lDEF|settings.subelements|el|ID-356586b0d3-idx1478611729574-form|item|el|content|vDEF
+        // Note: For existing containers, these parts are numeric, so "ID-356586b0d3-idx1478611729574-form" becomes 1 or 2, etc.
+        // @todo: This could be kicked is the flex form section containers are moved to an ajax call on creation
+        $fieldForHmac = preg_replace('/idx\d{13}-/', '', $field);
+
+        $dataStructureIdentifierString = '';
+        if (!empty($parsedBody['dataStructureIdentifier'])) {
+            $dataStructureIdentifierString = json_encode($parsedBody['dataStructureIdentifier']);
+        }
+
+        $incomingHmac = $parsedBody['hmac'];
+        $calculatedHmac = GeneralUtility::hmac(
+            $table . $fieldForHmac . $uid . $pid . $dataStructureIdentifierString,
+            'formEngineSuggest'
+        );
+        if ($incomingHmac !== $calculatedHmac) {
+            throw new \RuntimeException(
+                'Incoming and calculated hmac do not match',
+                1478608245
+            );
+        }
+
+        // If the $uid is numeric (existing page) and a suggest wizard in pages is handled, the effective
+        // pid is the uid of that page - important for page ts config configuration.
+        if (MathUtility::canBeInterpretedAsInteger($uid) && $table === 'pages') {
+            $pid = $uid;
+        }
+        $TSconfig = BackendUtility::getPagesTSconfig($pid);
+
+        // Determine TCA config of field
+        if (empty($dataStructureIdentifierString)) {
+            // Normal columns field
+            $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
+        } else {
+            // A flex flex form field
+            $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
+            $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifierString);
+            $parts = explode('|', $field);
+            $fieldConfig = $this->getFlexFieldConfiguration($parts, $dataStructureArray);
+            // Flexform field name levels are separated with | instead of encapsulation in [];
+            // reverse this here to be compatible with regular field names.
+            $field = str_replace('|', '][', $field);
+        }
+
+        $wizardConfig = $fieldConfig['wizards']['suggest'];
+
+        $queryTables = $this->getTablesToQueryFromFieldConfiguration($fieldConfig);
+        $whereClause = $this->getWhereClause($fieldConfig);
+
+        $resultRows = [];
+
+        // fetch the records for each query table. A query table is a table from which records are allowed to
+        // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA
+        foreach ($queryTables as $queryTable) {
+            // if the table does not exist, skip it
+            if (!is_array($GLOBALS['TCA'][$queryTable]) || empty($GLOBALS['TCA'][$queryTable])) {
+                continue;
+            }
+
+            $config = $this->getConfigurationForTable($queryTable, $wizardConfig, $TSconfig, $table, $field);
+
+            // process addWhere
+            if (!isset($config['addWhere']) && $whereClause) {
+                $config['addWhere'] = $whereClause;
+            }
+            if (isset($config['addWhere'])) {
+                $replacement = [
+                    '###THIS_UID###' => (int)$uid,
+                    '###CURRENT_PID###' => (int)$pid
+                ];
+                if (isset($TSconfig['TCEFORM.'][$table . '.'][$field . '.'])) {
+                    $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.'];
+                    if (isset($fieldTSconfig['PAGE_TSCONFIG_ID'])) {
+                        $replacement['###PAGE_TSCONFIG_ID###'] = (int)$fieldTSconfig['PAGE_TSCONFIG_ID'];
+                    }
+                    if (isset($fieldTSconfig['PAGE_TSCONFIG_IDLIST'])) {
+                        $replacement['###PAGE_TSCONFIG_IDLIST###'] =  implode(',', GeneralUtility::intExplode(',', $fieldTSconfig['PAGE_TSCONFIG_IDLIST']));
+                    }
+                    if (isset($fieldTSconfig['PAGE_TSCONFIG_STR'])) {
+                        $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($fieldConfig['foreign_table']);
+                        // nasty hack, but it's currently not possible to just quote anything "inside" the value but not escaping
+                        // the whole field as it is not known where it is used in the WHERE clause
+                        $replacement['###PAGE_TSCONFIG_STR###'] = trim($connection->quote($fieldTSconfig['PAGE_TSCONFIG_STR']), '\'');
+                    }
+                }
+                $config['addWhere'] = strtr(' ' . $config['addWhere'], $replacement);
+            }
+
+            // instantiate the class that should fetch the records for this $queryTable
+            $receiverClassName = $config['receiverClass'];
+            if (!class_exists($receiverClassName)) {
+                $receiverClassName = SuggestWizardDefaultReceiver::class;
+            }
+            $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
+            $params = ['value' => $search];
+            $rows = $receiverObj->queryTable($params);
+            if (empty($rows)) {
+                continue;
+            }
+            $resultRows = $rows + $resultRows;
+            unset($rows);
+        }
+
+        // Limit the number of items in the result list
+        $maxItems = isset($config['maxItemsInResultList']) ? $config['maxItemsInResultList'] : 10;
+        $maxItems = min(count($resultRows), $maxItems);
+
+        array_splice($resultRows, $maxItems);
+
+        $response->getBody()->write(json_encode(array_values($resultRows)));
+        return $response;
+    }
+
+    /**
+     * Returns TRUE if a table has been marked as hidden in the configuration
+     *
+     * @param array $tableConfig
+     * @return bool
+     */
+    protected function isTableHidden(array $tableConfig)
+    {
+        return (bool)$tableConfig['ctrl']['hideTable'];
+    }
+
+    /**
+     * Checks if the current backend user is allowed to access the given table, based on the ctrl-section of the
+     * table's configuration array (TCA) entry.
+     *
+     * @param array $tableConfig
+     * @return bool
+     */
+    protected function currentBackendUserMayAccessTable(array $tableConfig)
+    {
+        if ($this->getBackendUser()->isAdmin()) {
+            return true;
+        }
+
+        // If the user is no admin, they may not access admin-only tables
+        if ($tableConfig['ctrl']['adminOnly']) {
+            return false;
+        }
+
+        // allow access to root level pages if security restrictions should be bypassed
+        return !$tableConfig['ctrl']['rootLevel'] || $tableConfig['ctrl']['security']['ignoreRootLevelRestriction'];
+    }
+
+    /**
+     * Get 'config' section of field from resolved data structure specified by flex form path in $parts
+     *
+     * @param array $parts
+     * @param array $dataStructure
+     * @return array
+     */
+    protected function getFlexFieldConfiguration(array $parts, array $dataStructure)
+    {
+        if (count($parts) === 6) {
+            // Search a flex field, example:
+            // flex_1|data|sDb|lDEF|group_db_1|vDEF
+            if (!isset($dataStructure['sheets'][$parts[2]]['ROOT']['el'][$parts[4]]['TCEforms']['config'])) {
+                throw new \RuntimeException(
+                    'Specified path ' . implode('|', $parts) . ' not found in flex form data structure',
+                    1480609491
+                );
+            }
+            $fieldConfig = $dataStructure['sheets'][$parts[2]]['ROOT']['el'][$parts[4]]['TCEforms']['config'];
+        } elseif (count($parts) === 11) {
+            // Search a flex field in a section container, example:
+            // flex_1|data|sSuggestCheckCombination|lDEF|settings.subelements|el|1|item|el|content|vDEF
+            if (!isset($dataStructure['sheets'][$parts[2]]['ROOT']['el'][$parts[4]]['el'][$parts[7]]['el'][$parts[9]]['TCEforms']['config'])) {
+                throw new \RuntimeException(
+                    'Specified path ' . implode('|', $parts) . ' not found in flex form section container data structure',
+                    1480611208
+                );
+            }
+            $fieldConfig = $dataStructure['sheets'][$parts[2]]['ROOT']['el'][$parts[4]]['el'][$parts[7]]['el'][$parts[9]]['TCEforms']['config'];
+        } else {
+            throw new \RuntimeException(
+                'Invalid flex form path ' . implode('|', $parts),
+                1480611252
+            );
+        }
+        return $fieldConfig;
+    }
+
+    /**
+     * Returns the configuration for the suggest wizard for the given table. This does multiple overlays from the
+     * TSconfig.
+     *
+     * @param string $queryTable The table to query
+     * @param array $wizardConfig The configuration for the wizard as configured in the data structure
+     * @param array $TSconfig The TSconfig array of the current page
+     * @param string $table The table where the wizard is used
+     * @param string $field The field where the wizard is used
+     * @return array
+     */
+    protected function getConfigurationForTable($queryTable, array $wizardConfig, array $TSconfig, $table, $field)
+    {
+        $config = (array)$wizardConfig['default'];
+
+        if (is_array($wizardConfig[$queryTable])) {
+            ArrayUtility::mergeRecursiveWithOverrule($config, $wizardConfig[$queryTable]);
+        }
+        $globalSuggestTsConfig = $TSconfig['TCEFORM.']['suggest.'];
+        $currentFieldSuggestTsConfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'];
+
+        // merge the configurations of different "levels" to get the working configuration for this table and
+        // field (i.e., go from the most general to the most special configuration)
+        if (is_array($globalSuggestTsConfig['default.'])) {
+            ArrayUtility::mergeRecursiveWithOverrule($config, $globalSuggestTsConfig['default.']);
+        }
+
+        if (is_array($globalSuggestTsConfig[$queryTable . '.'])) {
+            ArrayUtility::mergeRecursiveWithOverrule($config, $globalSuggestTsConfig[$queryTable . '.']);
+        }
+
+        // use $table instead of $queryTable here because we overlay a config
+        // for the input-field here, not for the queried table
+        if (is_array($currentFieldSuggestTsConfig['default.'])) {
+            ArrayUtility::mergeRecursiveWithOverrule($config, $currentFieldSuggestTsConfig['default.']);
+        }
+
+        if (is_array($currentFieldSuggestTsConfig[$queryTable . '.'])) {
+            ArrayUtility::mergeRecursiveWithOverrule($config, $currentFieldSuggestTsConfig[$queryTable . '.']);
+        }
+
+        return $config;
+    }
+
+    /**
+     * Checks the given field configuration for the tables that should be used for querying and returns them as an
+     * array.
+     *
+     * @param array $fieldConfig
+     * @return array
+     */
+    protected function getTablesToQueryFromFieldConfiguration(array $fieldConfig)
+    {
+        $queryTables = [];
+
+        if (isset($fieldConfig['allowed'])) {
+            if ($fieldConfig['allowed'] !== '*') {
+                // list of allowed tables
+                $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
+            } else {
+                // all tables are allowed, if the user can access them
+                foreach ($GLOBALS['TCA'] as $tableName => $tableConfig) {
+                    if (!$this->isTableHidden($tableConfig) && $this->currentBackendUserMayAccessTable($tableConfig)) {
+                        $queryTables[] = $tableName;
+                    }
+                }
+                unset($tableName, $tableConfig);
+            }
+        } elseif (isset($fieldConfig['foreign_table'])) {
+            // use the foreign table
+            $queryTables = [$fieldConfig['foreign_table']];
+        }
+
+        return $queryTables;
+    }
+
+    /**
+     * Returns the SQL WHERE clause to use for querying records. This is currently only relevant if a foreign_table
+     * is configured and should be used; it could e.g. be used to limit to a certain subset of records from the
+     * foreign table
+     *
+     * @param array $fieldConfig
+     * @return string
+     */
+    protected function getWhereClause(array $fieldConfig)
+    {
+        if (!isset($fieldConfig['foreign_table'])) {
+            return '';
+        }
+
+        // strip ORDER BY clause
+        return trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $fieldConfig['foreign_table_where']));
+    }
+
+    /**
+     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
+     */
+    protected function getBackendUser()
+    {
+        return $GLOBALS['BE_USER'];
+    }
+}
diff --git a/typo3/sysext/backend/Classes/Form/Wizard/SuggestWizard.php b/typo3/sysext/backend/Classes/Form/Wizard/SuggestWizard.php
index 2fc6c07a7673bb54a799f566b655ebbd8c89243a..1f7b3216ff05043224dada87d4c58ec8b513eec2 100644
--- a/typo3/sysext/backend/Classes/Form/Wizard/SuggestWizard.php
+++ b/typo3/sysext/backend/Classes/Form/Wizard/SuggestWizard.php
@@ -14,19 +14,12 @@ namespace TYPO3\CMS\Backend\Form\Wizard;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Backend\Utility\BackendUtility;
-use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
-use TYPO3\CMS\Lang\LanguageService;
 
 /**
- * Wizard for rendering an AJAX selector for records
+ * Wizard for rendering an AJAX selector for records.
+ * See SuggestWizardController for the ajax handling counterpart.
  */
 class SuggestWizard
 {
@@ -116,392 +109,6 @@ class SuggestWizard
         return $this->view->render();
     }
 
-    /**
-     * Ajax handler for the "suggest" feature in FormEngine.
-     *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
-     * @throws \RuntimeException for incomplete or invalid arguments
-     * @return ResponseInterface
-     */
-    public function searchAction(ServerRequestInterface $request, ResponseInterface $response)
-    {
-        $parsedBody = $request->getParsedBody();
-
-        if (!isset($parsedBody['value'])
-            || !isset($parsedBody['table'])
-            || !isset($parsedBody['field'])
-            || !isset($parsedBody['uid'])
-            || !isset($parsedBody['dataStructureIdentifier'])
-            || !isset($parsedBody['hmac'])
-        ) {
-            throw new \RuntimeException(
-                'Missing at least one of the required arguments "value", "table", "field", "uid"'
-                . ', "dataStructureIdentifier" or "hmac"',
-                1478607036
-            );
-        }
-
-        $search = $parsedBody['value'];
-        $table = $parsedBody['table'];
-        $field = $parsedBody['field'];
-        $uid = $parsedBody['uid'];
-        $pid = (int)$parsedBody['pid'];
-
-        // flex form section container identifiers are created on js side dynamically "onClick". Those are
-        // not within the generated hmac ... the js side adds "idx{dateInMilliseconds}-", so this is removed here again.
-        // example outgoing in renderSuggestSelector():
-        // flex_1|data|sSuggestCheckCombination|lDEF|settings.subelements|el|ID-356586b0d3-form|item|el|content|vDEF
-        // incoming here:
-        // flex_1|data|sSuggestCheckCombination|lDEF|settings.subelements|el|ID-356586b0d3-idx1478611729574-form|item|el|content|vDEF
-        // Note: For existing containers, these parts are numeric, so "ID-356586b0d3-idx1478611729574-form" becomes 1 or 2, etc.
-        // @todo: This could be kicked is the flex form section containers are moved to an ajax call on creation
-        $fieldForHmac = preg_replace('/idx\d{13}-/', '', $field);
-
-        $dataStructureIdentifierString = '';
-        if (!empty($parsedBody['dataStructureIdentifier'])) {
-            $dataStructureIdentifierString = json_encode($parsedBody['dataStructureIdentifier']);
-        }
-
-        $incomingHmac = $parsedBody['hmac'];
-        $calculatedHmac = GeneralUtility::hmac(
-            $table . $fieldForHmac . $uid . $pid . $dataStructureIdentifierString,
-            'formEngineSuggest'
-        );
-        if ($incomingHmac !== $calculatedHmac) {
-            throw new \RuntimeException(
-                'Incoming and calculated hmac do not match',
-                1478608245
-            );
-        }
-
-        // If the $uid is numeric (existing page) and a suggest wizard in pages is handled, the effective
-        // pid is the uid of that page - important for page ts config configuration.
-        if (MathUtility::canBeInterpretedAsInteger($uid) && $table === 'pages') {
-            $pid = $uid;
-        }
-        $TSconfig = BackendUtility::getPagesTSconfig($pid);
-
-        // Determine TCA config of field
-        if (empty($dataStructureIdentifierString)) {
-            // Normal columns field
-            $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
-        } else {
-            // A flex flex form field
-            $flexFormTools = GeneralUtility::makeInstance(FlexFormTools::class);
-            $dataStructureArray = $flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifierString);
-            $parts = explode('|', $field);
-            $fieldConfig = $this->getFieldConfiguration($parts, $dataStructureArray);
-            // Flexform field name levels are separated with | instead of encapsulation in [];
-            // reverse this here to be compatible with regular field names.
-            $field = str_replace('|', '][', $field);
-        }
-
-        $wizardConfig = $fieldConfig['wizards']['suggest'];
-
-        $queryTables = $this->getTablesToQueryFromFieldConfiguration($fieldConfig);
-        $whereClause = $this->getWhereClause($fieldConfig);
-
-        $resultRows = [];
-
-        // fetch the records for each query table. A query table is a table from which records are allowed to
-        // be added to the TCEForm selector, originally fetched from the "allowed" config option in the TCA
-        foreach ($queryTables as $queryTable) {
-            // if the table does not exist, skip it
-            if (!is_array($GLOBALS['TCA'][$queryTable]) || empty($GLOBALS['TCA'][$queryTable])) {
-                continue;
-            }
-
-            $config = $this->getConfigurationForTable($queryTable, $wizardConfig, $TSconfig, $table, $field);
-
-            // process addWhere
-            if (!isset($config['addWhere']) && $whereClause) {
-                $config['addWhere'] = $whereClause;
-            }
-            if (isset($config['addWhere'])) {
-                $replacement = [
-                    '###THIS_UID###' => (int)$uid,
-                    '###CURRENT_PID###' => (int)$pid
-                ];
-                if (isset($TSconfig['TCEFORM.'][$table . '.'][$field . '.'])) {
-                    $fieldTSconfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.'];
-                    if (isset($fieldTSconfig['PAGE_TSCONFIG_ID'])) {
-                        $replacement['###PAGE_TSCONFIG_ID###'] = (int)$fieldTSconfig['PAGE_TSCONFIG_ID'];
-                    }
-                    if (isset($fieldTSconfig['PAGE_TSCONFIG_IDLIST'])) {
-                        $replacement['###PAGE_TSCONFIG_IDLIST###'] =  implode(',', GeneralUtility::intExplode(',', $fieldTSconfig['PAGE_TSCONFIG_IDLIST']));
-                    }
-                    if (isset($fieldTSconfig['PAGE_TSCONFIG_STR'])) {
-                        $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($fieldConfig['foreign_table']);
-                        // nasty hack, but it's currently not possible to just quote anything "inside" the value but not escaping
-                        // the whole field as it is not known where it is used in the WHERE clause
-                        $replacement['###PAGE_TSCONFIG_STR###'] = trim($connection->quote($fieldTSconfig['PAGE_TSCONFIG_STR']), '\'');
-                    }
-                }
-                $config['addWhere'] = strtr(' ' . $config['addWhere'], $replacement);
-            }
-
-            // instantiate the class that should fetch the records for this $queryTable
-            $receiverClassName = $config['receiverClass'];
-            if (!class_exists($receiverClassName)) {
-                $receiverClassName = SuggestWizardDefaultReceiver::class;
-            }
-            $receiverObj = GeneralUtility::makeInstance($receiverClassName, $queryTable, $config);
-            $params = ['value' => $search];
-            $rows = $receiverObj->queryTable($params);
-            if (empty($rows)) {
-                continue;
-            }
-            $resultRows = $rows + $resultRows;
-            unset($rows);
-        }
-
-        // Limit the number of items in the result list
-        $maxItems = isset($config['maxItemsInResultList']) ? $config['maxItemsInResultList'] : 10;
-        $maxItems = min(count($resultRows), $maxItems);
-
-        array_splice($resultRows, $maxItems);
-
-        $response->getBody()->write(json_encode(array_values($resultRows)));
-        return $response;
-    }
-
-    /**
-     * Returns TRUE if a table has been marked as hidden in the configuration
-     *
-     * @param array $tableConfig
-     * @return bool
-     */
-    protected function isTableHidden(array $tableConfig)
-    {
-        return (bool)$tableConfig['ctrl']['hideTable'];
-    }
-
-    /**
-     * Checks if the current backend user is allowed to access the given table, based on the ctrl-section of the
-     * table's configuration array (TCA) entry.
-     *
-     * @param array $tableConfig
-     * @return bool
-     */
-    protected function currentBackendUserMayAccessTable(array $tableConfig)
-    {
-        if ($this->getBackendUser()->isAdmin()) {
-            return true;
-        }
-
-        // If the user is no admin, they may not access admin-only tables
-        if ($tableConfig['ctrl']['adminOnly']) {
-            return false;
-        }
-
-        // allow access to root level pages if security restrictions should be bypassed
-        return !$tableConfig['ctrl']['rootLevel'] || $tableConfig['ctrl']['security']['ignoreRootLevelRestriction'];
-    }
-
-    /**
-     * Get configuration for given field by traversing the flexform path to field
-     * given in $parts
-     *
-     * @param array $parts
-     * @param array $flexformDSArray
-     * @return array
-     */
-    protected function getFieldConfiguration(array $parts, array $flexformDSArray)
-    {
-        $relevantParts = [];
-        foreach ($parts as $part) {
-            if ($this->isRelevantFlexField($part)) {
-                $relevantParts[] = $part;
-            }
-        }
-        // throw away db field name for flexform field
-        array_shift($relevantParts);
-
-        $flexformElement = array_pop($relevantParts);
-        $sheetName = array_shift($relevantParts);
-        $flexSubDataStructure = $flexformDSArray['sheets'][$sheetName];
-        foreach ($relevantParts as $relevantPart) {
-            $flexSubDataStructure = $this->getSubConfigurationForSections($flexSubDataStructure, $relevantPart);
-        }
-        $fieldConfig = $this->getNestedDsFieldConfig($flexSubDataStructure, $flexformElement);
-        return $fieldConfig;
-    }
-
-    /**
-     * Recursively get sub sections in data structure by name
-     *
-     * @param array $dataStructure
-     * @param string $fieldName
-     * @return array
-     */
-    protected function getSubConfigurationForSections(array $dataStructure, $fieldName)
-    {
-        $fieldConfig = [];
-        $elements = $dataStructure['ROOT']['el'] ? $dataStructure['ROOT']['el'] : $dataStructure['el'];
-        if (is_array($elements)) {
-            foreach ($elements as $k => $ds) {
-                if ($k === $fieldName) {
-                    $fieldConfig = $ds;
-                    break;
-                } elseif (isset($ds['el'][$fieldName])) {
-                    $fieldConfig = $ds['el'][$fieldName];
-                    break;
-                } else {
-                    $fieldConfig = $this->getSubConfigurationForSections($ds, $fieldName);
-                }
-            }
-        }
-        return $fieldConfig;
-    }
-
-    /**
-     * Search a data structure array recursively -- including within nested
-     * (repeating) elements -- for a particular field config.
-     *
-     * @param array $dataStructure The data structure
-     * @param string $fieldName The field name
-     * @return array
-     */
-    protected function getNestedDsFieldConfig(array $dataStructure, $fieldName)
-    {
-        $fieldConfig = [];
-        $elements = $dataStructure['ROOT']['el'] ? $dataStructure['ROOT']['el'] : $dataStructure['el'];
-        if (is_array($elements)) {
-            foreach ($elements as $k => $ds) {
-                if ($k === $fieldName) {
-                    $fieldConfig = $ds['TCEforms']['config'];
-                    break;
-                } elseif (isset($ds['el'][$fieldName]['TCEforms']['config'])) {
-                    $fieldConfig = $ds['el'][$fieldName]['TCEforms']['config'];
-                    break;
-                } else {
-                    $fieldConfig = $this->getNestedDsFieldConfig($ds, $fieldName);
-                }
-            }
-        }
-        return $fieldConfig;
-    }
-
-    /**
-     * Checks whether the field is an actual identifier or just "array filling"
-     *
-     * @param string $fieldName
-     * @return bool
-     */
-    protected function isRelevantFlexField($fieldName)
-    {
-        return !(
-            strpos($fieldName, 'ID-') === 0 ||
-            $fieldName === 'lDEF' ||
-            $fieldName === 'vDEF' ||
-            $fieldName === 'data' ||
-            $fieldName === 'el'
-        );
-    }
-
-    /**
-     * Returns the configuration for the suggest wizard for the given table. This does multiple overlays from the
-     * TSconfig.
-     *
-     * @param string $queryTable The table to query
-     * @param array $wizardConfig The configuration for the wizard as configured in the data structure
-     * @param array $TSconfig The TSconfig array of the current page
-     * @param string $table The table where the wizard is used
-     * @param string $field The field where the wizard is used
-     * @return array
-     */
-    protected function getConfigurationForTable($queryTable, array $wizardConfig, array $TSconfig, $table, $field)
-    {
-        $config = (array)$wizardConfig['default'];
-
-        if (is_array($wizardConfig[$queryTable])) {
-            ArrayUtility::mergeRecursiveWithOverrule($config, $wizardConfig[$queryTable]);
-        }
-        $globalSuggestTsConfig = $TSconfig['TCEFORM.']['suggest.'];
-        $currentFieldSuggestTsConfig = $TSconfig['TCEFORM.'][$table . '.'][$field . '.']['suggest.'];
-
-        // merge the configurations of different "levels" to get the working configuration for this table and
-        // field (i.e., go from the most general to the most special configuration)
-        if (is_array($globalSuggestTsConfig['default.'])) {
-            ArrayUtility::mergeRecursiveWithOverrule($config, $globalSuggestTsConfig['default.']);
-        }
-
-        if (is_array($globalSuggestTsConfig[$queryTable . '.'])) {
-            ArrayUtility::mergeRecursiveWithOverrule($config, $globalSuggestTsConfig[$queryTable . '.']);
-        }
-
-        // use $table instead of $queryTable here because we overlay a config
-        // for the input-field here, not for the queried table
-        if (is_array($currentFieldSuggestTsConfig['default.'])) {
-            ArrayUtility::mergeRecursiveWithOverrule($config, $currentFieldSuggestTsConfig['default.']);
-        }
-
-        if (is_array($currentFieldSuggestTsConfig[$queryTable . '.'])) {
-            ArrayUtility::mergeRecursiveWithOverrule($config, $currentFieldSuggestTsConfig[$queryTable . '.']);
-        }
-
-        return $config;
-    }
-
-    /**
-     * Checks the given field configuration for the tables that should be used for querying and returns them as an
-     * array.
-     *
-     * @param array $fieldConfig
-     * @return array
-     */
-    protected function getTablesToQueryFromFieldConfiguration(array $fieldConfig)
-    {
-        $queryTables = [];
-
-        if (isset($fieldConfig['allowed'])) {
-            if ($fieldConfig['allowed'] !== '*') {
-                // list of allowed tables
-                $queryTables = GeneralUtility::trimExplode(',', $fieldConfig['allowed']);
-            } else {
-                // all tables are allowed, if the user can access them
-                foreach ($GLOBALS['TCA'] as $tableName => $tableConfig) {
-                    if (!$this->isTableHidden($tableConfig) && $this->currentBackendUserMayAccessTable($tableConfig)) {
-                        $queryTables[] = $tableName;
-                    }
-                }
-                unset($tableName, $tableConfig);
-            }
-        } elseif (isset($fieldConfig['foreign_table'])) {
-            // use the foreign table
-            $queryTables = [$fieldConfig['foreign_table']];
-        }
-
-        return $queryTables;
-    }
-
-    /**
-     * Returns the SQL WHERE clause to use for querying records. This is currently only relevant if a foreign_table
-     * is configured and should be used; it could e.g. be used to limit to a certain subset of records from the
-     * foreign table
-     *
-     * @param array $fieldConfig
-     * @return string
-     */
-    protected function getWhereClause(array $fieldConfig)
-    {
-        if (!isset($fieldConfig['foreign_table'])) {
-            return '';
-        }
-
-        // strip ORDER BY clause
-        return trim(preg_replace('/ORDER[[:space:]]+BY.*/i', '', $fieldConfig['foreign_table_where']));
-    }
-
-    /**
-     * @return LanguageService
-     */
-    protected function getLanguageService()
-    {
-        return $GLOBALS['LANG'];
-    }
-
     /**
      * Returns a new standalone view, shorthand function
      *
@@ -526,12 +133,4 @@ class SuggestWizard
         $view->getRequest()->setControllerExtensionName('Backend');
         return $view;
     }
-
-    /**
-     * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
-     */
-    protected function getBackendUser()
-    {
-        return $GLOBALS['BE_USER'];
-    }
 }
diff --git a/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php b/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php
index 242de565d92c5cd005a59e8d965a9178da519265..3002df2f88f4d7d717755e646c60cb2d1ed8524f 100644
--- a/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php
+++ b/typo3/sysext/backend/Configuration/Backend/AjaxRoutes.php
@@ -52,10 +52,10 @@ return [
         'target' => Controller\FormInlineAjaxController::class . '::expandOrCollapseAction'
     ],
 
-    // Search records
+    // FormEngine suggest wizard result generator
     'record_suggest' => [
         'path' => '/wizard/suggest/search',
-        'target' => \TYPO3\CMS\Backend\Form\Wizard\SuggestWizard::class . '::searchAction'
+        'target' => \TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController::class . '::searchAction'
     ],
 
     // Fetch the tree-structured data from a record for the tree selection
diff --git a/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php b/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..fe2f736602aaa6dc7c692f81279aafb490e697d2
--- /dev/null
+++ b/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php
@@ -0,0 +1,300 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Controller\Wizard;
+
+/*
+ * 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 Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController;
+use TYPO3\CMS\Core\Tests\AccessibleObjectInterface;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Fluid\View\StandaloneView;
+
+/**
+ * Test case
+ */
+class SuggestWizardControllerTest extends UnitTestCase
+{
+    /**
+     * @test
+     */
+    public function searchActionThrowsExceptionWithMissingArgument()
+    {
+        $viewProphecy = $this->prophesize(StandaloneView::class);
+        $responseProphecy = $this->prophesize(ResponseInterface::class);
+        $serverRequestProphecy = $this->prophesize(ServerRequestInterface::class);
+        $serverRequestProphecy->getParsedBody()->willReturn([
+            'value' => 'theSearchValue',
+            'table' => 'aTable',
+            'field' => 'aField',
+            'uid' => 'aUid',
+            'dataStructureIdentifier' => 'anIdentifier',
+            // hmac missing
+        ]);
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1478607036);
+        (new SuggestWizardController($viewProphecy->reveal()))
+            ->searchAction($serverRequestProphecy->reveal(), $responseProphecy->reveal());
+    }
+
+    /**
+     * @test
+     */
+    public function searchActionThrowsExceptionWithWrongHmac()
+    {
+        $viewProphecy = $this->prophesize(StandaloneView::class);
+        $responseProphecy = $this->prophesize(ResponseInterface::class);
+        $serverRequestProphecy = $this->prophesize(ServerRequestInterface::class);
+        $serverRequestProphecy->getParsedBody()->willReturn([
+            'value' => 'theSearchValue',
+            'table' => 'aTable',
+            'field' => 'aField',
+            'uid' => 'aUid',
+            'dataStructureIdentifier' => 'anIdentifier',
+            'hmac' => 'wrongHmac'
+        ]);
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1478608245);
+        (new SuggestWizardController($viewProphecy->reveal()))
+            ->searchAction($serverRequestProphecy->reveal(), $responseProphecy->reveal());
+    }
+
+    /**
+     * @test
+     */
+    public function getFlexFieldConfigurationThrowsExceptionIfSimpleFlexFieldIsNotFound()
+    {
+        $dataStructure = [
+            'sheets' => [
+                'sDb' => [
+                    'ROOT' => [
+                        'el' => [
+                            'differentField' => [
+                                'TCEforms' => [
+                                    'config' => [
+                                        'Sublevel field configuration',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $parts = [
+            0 => 'flex_1',
+            1 => 'data',
+            2 => 'sDb',
+            3 => 'lDEF',
+            4 => 'group_db_1',
+            5 => 'vDEF',
+        ];
+
+        /** @var SuggestWizardController|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
+        $subject = $this->getAccessibleMock(SuggestWizardController::class, ['dummy'], [], '', false);
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1480609491);
+        $subject->_call('getFlexFieldConfiguration', $parts, $dataStructure);
+    }
+
+    /**
+     * @test
+     */
+    public function getFlexFieldConfigurationThrowsExceptionIfSectionContainerFlexFieldIsNotFound()
+    {
+        $dataStructure = [
+            'sheets' => [
+                'sDb' => [
+                    'ROOT' => [
+                        'el' => [
+                            'notTheFieldYouAreLookingFor' => [
+                                'TCEforms' => [
+                                    'config' => [
+                                        'Sublevel field configuration',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $parts = [
+            0 => 'flex_1',
+            1 => 'data',
+            2 => 'sSuggestCheckCombination',
+            3 => 'lDEF',
+            4 => 'settings.subelements',
+            5 => 'el',
+            6 => '1',
+            7 => 'item',
+            8 => 'el',
+            9 => 'content',
+            10 => 'vDEF',
+        ];
+
+        /** @var SuggestWizardController|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
+        $subject = $this->getAccessibleMock(SuggestWizardController::class, ['dummy'], [], '', false);
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1480611208);
+        $subject->_call('getFlexFieldConfiguration', $parts, $dataStructure);
+    }
+
+    /**
+     * @test
+     */
+    public function getFlexFieldConfigurationThrowsExceptionPartsIsOfUnexpectedLength()
+    {
+        /** @var SuggestWizardController|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
+        $subject = $this->getAccessibleMock(SuggestWizardController::class, ['dummy'], [], '', false);
+        $this->expectException(\RuntimeException::class);
+        $this->expectExceptionCode(1480611252);
+        $subject->_call('getFlexFieldConfiguration', [], []);
+    }
+
+    /**
+     * @test
+     */
+    public function getFlexFieldConfigurationFindsConfigurationOfSimpleFlexField()
+    {
+        $dataStructure = [
+            'sheets' => [
+                'sDb' => [
+                    'ROOT' => [
+                        'el' => [
+                            'group_db_1' => [
+                                'TCEforms' => [
+                                    'config' => [
+                                        'Sublevel field configuration',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $parts = [
+            0 => 'flex_1',
+            1 => 'data',
+            2 => 'sDb',
+            3 => 'lDEF',
+            4 => 'group_db_1',
+            5 => 'vDEF',
+        ];
+
+        $expected = $dataStructure['sheets']['sDb']['ROOT']['el']['group_db_1']['TCEforms']['config'];
+
+        /** @var SuggestWizardController|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
+        $subject = $this->getAccessibleMock(SuggestWizardController::class, ['dummy'], [], '', false);
+        $result = $subject->_call('getFlexFieldConfiguration', $parts, $dataStructure);
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function getFlexFieldConfigurationFindsConfigurationOfSectionContainerField()
+    {
+        $dataStructure = [
+            'sheets' => [
+                'sSuggestCheckCombination' => [
+                    'ROOT' => [
+                        'type' => 'array',
+                        'el' => [
+                            'settings.subelements' => [
+                                'title' => 'Subelements',
+                                'section' => 1,
+                                'type' => 'array',
+                                'el' => [
+                                    'item' => [
+                                        'type' => 'array',
+                                        'title' => 'Subelement',
+                                        'el' => [
+                                            'content' => [
+                                                'TCEforms' => [
+                                                    'label' => 'Content',
+                                                    'config' => [
+                                                        'type' => 'group',
+                                                        'internal_type' => 'db',
+                                                        'allowed' => 'pages',
+                                                        'size' => 5,
+                                                        'maxitems' => 10,
+                                                        'minitems' => 1,
+                                                        'show_thumbs' => 1,
+                                                        'wizards' => [
+                                                            'suggest' => [
+                                                                'type' => 'suggest',
+                                                            ],
+                                                        ],
+                                                    ],
+                                                ],
+                                            ],
+                                        ],
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        $parts = [
+            0 => 'flex_1',
+            1 => 'data',
+            2 => 'sSuggestCheckCombination',
+            3 => 'lDEF',
+            4 => 'settings.subelements',
+            5 => 'el',
+            6 => '1',
+            7 => 'item',
+            8 => 'el',
+            9 => 'content',
+            10 => 'vDEF',
+        ];
+
+        $expected = $dataStructure['sheets']['sSuggestCheckCombination']['ROOT']['el']['settings.subelements']
+            ['el']['item']['el']['content']['TCEforms']['config'];
+
+        /** @var SuggestWizardController|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
+        $subject = $this->getAccessibleMock(SuggestWizardController::class, ['dummy'], [], '', false);
+        $result = $subject->_call('getFlexFieldConfiguration', $parts, $dataStructure);
+        $this->assertEquals($expected, $result);
+    }
+
+    /**
+     * @test
+     * @dataProvider isTableHiddenIsProperlyRetrievedDataProvider
+     */
+    public function isTableHiddenIsProperlyRetrieved($expected, $array)
+    {
+        $subject = $this->getAccessibleMock(SuggestWizardController::class, ['dummy'], [], '', false);
+        $this->assertEquals($expected, $subject->_call('isTableHidden', $array));
+    }
+
+    public function isTableHiddenIsProperlyRetrievedDataProvider()
+    {
+        return [
+          'notSetValue' => [false, ['ctrl' => ['hideTable' => null]]],
+          'true' => [true, ['ctrl' => ['hideTable' => true]]],
+          'false' => [false, ['ctrl' => ['hideTable' => false]]],
+          'string with true' => [true, ['ctrl' => ['hideTable' => '1']]],
+          'string with false' => [false, ['ctrl' => ['hideTable' => '0']]],
+        ];
+    }
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Form/Wizard/SuggestWizardTest.php b/typo3/sysext/backend/Tests/Unit/Form/Wizard/SuggestWizardTest.php
index 2d0a79b75d3e6c859a701a8cd403d22d3d454453..586f23924ff62a7c9afd90dc7c0d2dc08eb19b35 100644
--- a/typo3/sysext/backend/Tests/Unit/Form/Wizard/SuggestWizardTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Form/Wizard/SuggestWizardTest.php
@@ -14,10 +14,7 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Form\Wizard;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Form\Wizard\SuggestWizard;
-use TYPO3\CMS\Core\Tests\AccessibleObjectInterface;
 use TYPO3\CMS\Core\Tests\UnitTestCase;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
@@ -48,195 +45,4 @@ class SuggestWizardTest extends UnitTestCase
             ]
         );
     }
-
-    /**
-     * @test
-     */
-    public function searchActionThrowsExceptionWithMissingArgument()
-    {
-        $viewProphecy = $this->prophesize(StandaloneView::class);
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
-        $serverRequestProphecy = $this->prophesize(ServerRequestInterface::class);
-        $serverRequestProphecy->getParsedBody()->willReturn([
-            'value' => 'theSearchValue',
-            'table' => 'aTable',
-            'field' => 'aField',
-            'uid' => 'aUid',
-            'dataStructureIdentifier' => 'anIdentifier',
-            // hmac missing
-        ]);
-        $this->expectException(\RuntimeException::class);
-        $this->expectExceptionCode(1478607036);
-        (new SuggestWizard($viewProphecy->reveal()))
-            ->searchAction($serverRequestProphecy->reveal(), $responseProphecy->reveal());
-    }
-
-    /**
-     * @test
-     */
-    public function searchActionThrowsExceptionWithWrongHmac()
-    {
-        $viewProphecy = $this->prophesize(StandaloneView::class);
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
-        $serverRequestProphecy = $this->prophesize(ServerRequestInterface::class);
-        $serverRequestProphecy->getParsedBody()->willReturn([
-            'value' => 'theSearchValue',
-            'table' => 'aTable',
-            'field' => 'aField',
-            'uid' => 'aUid',
-            'dataStructureIdentifier' => 'anIdentifier',
-            'hmac' => 'wrongHmac'
-        ]);
-        $this->expectException(\RuntimeException::class);
-        $this->expectExceptionCode(1478608245);
-        (new SuggestWizard($viewProphecy->reveal()))
-            ->searchAction($serverRequestProphecy->reveal(), $responseProphecy->reveal());
-    }
-
-    /**
-     * @test
-     */
-    public function getFieldConfigurationFetchesConfigurationDependentOnTheFullPathToField()
-    {
-        $config = [
-            'el' => [
-                'content' => [
-                    'TCEforms' => [
-                        'config' => [
-                            'Sublevel field configuration',
-                        ],
-                    ],
-                ],
-            ],
-        ];
-
-        $dataStructure['sheets']['sSuggestCheckCombination']['ROOT']['el'] = [
-            'settings.topname1' => [
-                'el' => [
-                    'item' => [
-                        'el' => [
-                            'content' => [
-                                'TCEforms' => [
-                                    'config' => [
-                                        'different foo config for field with same name',
-                                    ],
-                                ],
-                            ],
-                        ],
-                    ],
-                ],
-            ],
-            'settings.topname3' => [
-                'el' => ['item' => $config]
-            ],
-            'settings.topname2' => [
-                'el' => [
-                    'item' => [
-                        'el' => [
-                            'content' => [
-                                'TCEforms' => [
-                                    'config' => [
-                                        'different foo config for field with same name',
-                                    ],
-                                ],
-                            ],
-                        ],
-                    ],
-                ],
-            ],
-        ];
-        $parts = [
-            0 => 'flex_1',
-            1 => 'data',
-            2 => 'sSuggestCheckCombination',
-            3 => 'lDEF',
-            4 => 'settings.topname3',
-            5 => 'el',
-            6 => 'ID-efa3ff7ed5-idx1460636854058-form',
-            7 => 'item',
-            8 => 'el',
-            9 => 'content',
-            10 => 'vDEF',
-        ];
-
-        /** @var SuggestWizard|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
-        $subject = $this->getAccessibleMock(SuggestWizard::class, ['getNestedDsFieldConfig'], [], '', false);
-        $subject
-            ->expects($this->once())
-            ->method('getNestedDsFieldConfig')
-            ->with($config, 'content');
-        $subject->_call('getFieldConfiguration', $parts, $dataStructure);
-    }
-
-    /**
-     * @test
-     */
-    public function getFieldConfigurationFetchesConfigurationForFieldsWithoutSheets()
-    {
-        $config = [
-            'ROOT' => [
-                'type' => 'array',
-                'el' => [
-                    'content' => [
-                        'TCEforms' => [
-                            'label' => 'group_db_1 wizard suggest',
-                            'config' => [
-                                'type' => 'group',
-                                'internal_type' => 'db',
-                                'allowed' => 'tx_styleguide_staticdata',
-                                'wizards' => [
-                                    'suggest' => [
-                                        'type' => 'suggest',
-                                    ],
-                                ],
-                            ],
-                        ],
-                    ],
-                ],
-            ]
-        ];
-        $dataStructure = [
-            'sheets' => [
-                'sDEF' => $config
-            ],
-        ];
-        $parts = [
-            0 => 'flex_1',
-            1 => 'data',
-            2 => 'sDEF',
-            3 => 'lDEF',
-            4 => 'content',
-            5 => 'vDEF',
-        ];
-
-        /** @var SuggestWizard|AccessibleObjectInterface|\PHPUnit_Framework_MockObject_MockObject $subject */
-        $subject = $this->getAccessibleMock(SuggestWizard::class, ['getNestedDsFieldConfig'], [], '', false);
-        $subject
-            ->expects($this->once())
-            ->method('getNestedDsFieldConfig')
-            ->with($config, 'content');
-
-        $subject->_call('getFieldConfiguration', $parts, $dataStructure);
-    }
-
-    /**
-     * @test
-     * @dataProvider isTableHiddenIsProperlyRetrievedDataProvider
-     */
-    public function isTableHiddenIsProperlyRetrieved($expected, $array)
-    {
-        $subject = $this->getAccessibleMock(SuggestWizard::class, ['dummy'], [], '', false);
-        $this->assertEquals($expected, $subject->_call('isTableHidden', $array));
-    }
-
-    public function isTableHiddenIsProperlyRetrievedDataProvider()
-    {
-        return [
-          'notSetValue' => [false, ['ctrl' => ['hideTable' => null]]],
-          'true' => [true, ['ctrl' => ['hideTable' => true]]],
-          'false' => [false, ['ctrl' => ['hideTable' => false]]],
-          'string with true' => [true, ['ctrl' => ['hideTable' => '1']]],
-          'string with false' => [false, ['ctrl' => ['hideTable' => '0']]],
-        ];
-    }
 }