From 906684cbe3acbb4a0f3c892a77be56be2d97d4b3 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Tue, 10 Oct 2017 19:38:01 +0200
Subject: [PATCH] [TASK] Deprecate ConfigurationForm

The call tree of the extension manager "configuration form"
ext_conf_template.txt parser is a mess:
The ext:extensionmanager ConfigurationUtility calls ext:core
ConfigurationForm which is a class that extends ExtendedTemplateService
which extends TemplateService. The "TypoScript" a-like parsing then uses
class TypoScriptParser. This compiles to a huge list of dependencies.

The patch compiles this mess down to a series of methods within
ConfigurationUtility directly, effectively adding needed parts
of TypoScriptParser and ConfigurationForm as protected methods.
The class ends up with way less direct and indirect dependencies.

The various detail parsing methods are still messy and hard to follow,
but rewriting the parser heart does not really make sense since the
ext_conf_template.txt format will bite the dust sooner or later anyway
and having all in one place is already much better than before.
So putting some days of energy into rewriting these specific parts
of the TypoScript parsing did not seem to be worth it, even if it in
the end could probably solved with 1/4 of code.

Class ConfigurationForm is deprecated but could also be removed
as breaking patch later if anyone wants to refactor the remaining
ExtendedTemplateService and TemplateService classes in v9.

Note this patch is an intermediate step before the ConfigurationUtility
class form ext:em is moved into the install tool.

Change-Id: I62d9fafb6444d954e17c980358e6367a83b033b8
Resolves: #82725
Releases: master
Reviewed-on: https://review.typo3.org/54362
Reviewed-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog <susanne.moog@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Tested-by: Mona Muzaffar <mona.muzaffar@gmx.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../Classes/TypoScript/ConfigurationForm.php  |   8 +
 ...ation-82725-DeprecateConfigurationForm.rst |  36 ++
 .../Classes/Utility/ConfigurationUtility.php  | 423 +++++++++++++++++-
 .../Unit/Utility/ConfigurationUtilityTest.php |  41 +-
 .../Utility/Fixtures/ext_conf_template.txt    |   5 +
 .../ExtensionScanner/Php/ClassNameMatcher.php |   5 +
 .../Classes/Report/Status/SecurityStatus.php  |   3 +-
 .../ExtensionManagerConfigurationUtility.php  |  19 +-
 8 files changed, 478 insertions(+), 62 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Deprecation-82725-DeprecateConfigurationForm.rst
 create mode 100644 typo3/sysext/extensionmanager/Tests/Unit/Utility/Fixtures/ext_conf_template.txt

diff --git a/typo3/sysext/core/Classes/TypoScript/ConfigurationForm.php b/typo3/sysext/core/Classes/TypoScript/ConfigurationForm.php
index cb75f2f3ad9c..23ae47558f26 100644
--- a/typo3/sysext/core/Classes/TypoScript/ConfigurationForm.php
+++ b/typo3/sysext/core/Classes/TypoScript/ConfigurationForm.php
@@ -52,6 +52,14 @@ class ConfigurationForm extends ExtendedTemplateService
      */
     protected $ext_realValues = [];
 
+    /**
+     * Deprecate this class
+     */
+    public function __construct()
+    {
+        trigger_error('Class ConfigurationForm has been deprecated with v9 and will be removed in v10', E_USER_DEPRECATED);
+    }
+
     /**
      * @param string $configTemplate
      * @return array
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82725-DeprecateConfigurationForm.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82725-DeprecateConfigurationForm.rst
new file mode 100644
index 000000000000..2dd905a5dfae
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-82725-DeprecateConfigurationForm.rst
@@ -0,0 +1,36 @@
+.. include:: ../../Includes.txt
+
+=================================================
+Deprecation: #82725 - Deprecate ConfigurationForm
+=================================================
+
+See :issue:`82725`
+
+Description
+===========
+
+Class :php:`TYPO3\CMS\Core\TypoScript\ConfigurationForm` has been deprecated and should
+not be used any longer.
+
+
+Impact
+======
+
+Extending or instantiating this class will throw a deprecation warning.
+
+
+Affected Installations
+======================
+
+Instance with extensions using this class.
+
+
+Migration
+=========
+
+Class :php:`ConfigurationForm` was used to parse the ext_conf_template.txt file of extensions. 
+The parser has been integrated at a different place in the core. The
+class is mostly core internal and extensions should not have needed to parse that syntax directly.
+There is no direct substitution for this functionality usable by extensions in the core.
+
+.. index:: Backend, PHP-API, FullyScanned
\ No newline at end of file
diff --git a/typo3/sysext/extensionmanager/Classes/Utility/ConfigurationUtility.php b/typo3/sysext/extensionmanager/Classes/Utility/ConfigurationUtility.php
index 63beddafb669..7c8081d0a4a3 100644
--- a/typo3/sysext/extensionmanager/Classes/Utility/ConfigurationUtility.php
+++ b/typo3/sysext/extensionmanager/Classes/Utility/ConfigurationUtility.php
@@ -14,14 +14,90 @@ namespace TYPO3\CMS\Extensionmanager\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Core\TypoScript\ConfigurationForm;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
+use TYPO3\CMS\Lang\LanguageService;
 
 /**
  * Utility for dealing with ext_emconf and ext_conf_template settings
  */
 class ConfigurationUtility implements \TYPO3\CMS\Core\SingletonInterface
 {
+    /**
+     * TypoScript hierarchy being build during parsing.
+     *
+     * @var array
+     */
+    protected $setup = [];
+
+    /**
+     * Raw data, the input string exploded by LF
+     *
+     * @var array
+     */
+    protected $raw;
+
+    /**
+     * Pointer to entry in raw data array
+     *
+     * @var int
+     */
+    protected $rawP = 0;
+
+    /**
+     * Holding the value of the last comment
+     *
+     * @var string
+     */
+    protected $lastComment = '';
+
+    /**
+     * Internally set, used as internal flag to create a multi-line comment (one of those like /* ... * /
+     *
+     * @var bool
+     */
+    protected $commentSet = false;
+
+    /**
+     * Internally set, when in brace. Counter.
+     *
+     * @var int
+     */
+    protected $inBrace = 0;
+
+    /**
+     * This will be filled with the available categories of the current template.
+     *
+     * @var array
+     */
+    protected $subCategories = [
+        // Standard categories:
+        'enable' => ['Enable features', 'a'],
+        'dims' => ['Dimensions, widths, heights, pixels', 'b'],
+        'file' => ['Files', 'c'],
+        'typo' => ['Typography', 'd'],
+        'color' => ['Colors', 'e'],
+        'links' => ['Links and targets', 'f'],
+        'language' => ['Language specific constants', 'g'],
+        // subcategories based on the default content elements
+        'cheader' => ['Content: \'Header\'', 'ma'],
+        'cheader_g' => ['Content: \'Header\', Graphical', 'ma'],
+        'ctext' => ['Content: \'Text\'', 'mb'],
+        'cimage' => ['Content: \'Image\'', 'md'],
+        'ctextmedia' => ['Content: \'Textmedia\'', 'ml'],
+        'cbullets' => ['Content: \'Bullet list\'', 'me'],
+        'ctable' => ['Content: \'Table\'', 'mf'],
+        'cuploads' => ['Content: \'Filelinks\'', 'mg'],
+        'cmultimedia' => ['Content: \'Multimedia\'', 'mh'],
+        'cmedia' => ['Content: \'Media\'', 'mr'],
+        'cmailform' => ['Content: \'Form\'', 'mi'],
+        'csearch' => ['Content: \'Search\'', 'mj'],
+        'clogin' => ['Content: \'Login\'', 'mk'],
+        'cmenu' => ['Content: \'Menu/Sitemap\'', 'mm'],
+        'cshortcut' => ['Content: \'Insert records\'', 'mn'],
+        'clist' => ['Content: \'List of records\'', 'mo'],
+        'chtml' => ['Content: \'HTML\'', 'mq']
+    ];
+
     /**
      * @var \TYPO3\CMS\Extbase\Object\ObjectManager
      */
@@ -121,25 +197,29 @@ class ConfigurationUtility implements \TYPO3\CMS\Core\SingletonInterface
     public function getDefaultConfigurationFromExtConfTemplateAsValuedArray($extensionKey)
     {
         $rawConfigurationString = $this->getDefaultConfigurationRawString($extensionKey);
-
         $theConstants = [];
-
         if ((string)$rawConfigurationString !== '') {
-            /** @var ConfigurationForm $tsStyleConfig */
-            $tsStyleConfig = $this->objectManager->get(ConfigurationForm::class);
-            $tsStyleConfig->doNotSortCategoriesBeforeMakingForm = true;
-
-            $theConstants = $tsStyleConfig->ext_initTSstyleConfig($rawConfigurationString);
+            $this->raw = explode(LF, $rawConfigurationString);
+            $this->parseSub($this->setup);
+            if ($this->inBrace) {
+                throw new \RuntimeException(
+                    'Line ' . ($this->rawP - 1) . ': The script is short of ' . $this->inBrace . ' end brace(s)',
+                    1507645348
+                );
+            }
+            $parsedConstants = $this->setup;
+            $flatSetup = $this->flattenSetup($parsedConstants);
+            $theConstants = $this->parseComments($flatSetup);
 
             // Loop through configuration items, see if it is assigned to a sub category
             // and add the sub category label to the item property if so.
             foreach ($theConstants as $configurationOptionName => $configurationOption) {
                 if (
                     array_key_exists('subcat_name', $configurationOption)
-                    && isset($tsStyleConfig->subCategories[$configurationOption['subcat_name']])
-                    && isset($tsStyleConfig->subCategories[$configurationOption['subcat_name']][0])
+                    && isset($this->subCategories[$configurationOption['subcat_name']])
+                    && isset($this->subCategories[$configurationOption['subcat_name']][0])
                 ) {
-                    $theConstants[$configurationOptionName]['subcat_label'] = $tsStyleConfig->subCategories[$configurationOption['subcat_name']][0];
+                    $theConstants[$configurationOptionName]['subcat_label'] = $this->subCategories[$configurationOption['subcat_name']][0];
                 }
             }
         }
@@ -228,4 +308,325 @@ class ConfigurationUtility implements \TYPO3\CMS\Core\SingletonInterface
         );
         return $configuration;
     }
+
+    /**
+     * This flattens a hierarchical TypoScript array to $this->flatSetup
+     *
+     * @param array $setupArray TypoScript array
+     * @param string $prefix Prefix to the object path. Used for recursive calls to this function.
+     * @return array
+     */
+    protected function flattenSetup($setupArray, $prefix = '')
+    {
+        $flatSetup = [];
+        if (is_array($setupArray)) {
+            foreach ($setupArray as $key => $val) {
+                if (is_array($val)) {
+                    $flatSetup = array_merge($flatSetup, $this->flattenSetup($val, $prefix . $key));
+                } else {
+                    $flatSetup[$prefix . $key] = $val;
+                }
+            }
+        }
+        return $flatSetup;
+    }
+
+    /**
+     * This function compares the flattened constants (default and all).
+     * Returns an array with the constants from the whole template which may be edited by the module.
+     *
+     * @param array $flatSetup
+     * @return array
+     */
+    protected function parseComments($flatSetup)
+    {
+        $categoryLabels = [];
+        $editableComments = [];
+        $counter = 0;
+        foreach ($flatSetup as $const => $value) {
+            if (substr($const, -2) === '..' || !isset($flatSetup[$const . '..'])) {
+                continue;
+            }
+            $counter++;
+            $comment = trim($flatSetup[$const . '..']);
+            $c_arr = explode(LF, $comment);
+            foreach ($c_arr as $k => $v) {
+                $line = trim(preg_replace('/^[#\\/]*/', '', $v));
+                if (!$line) {
+                    continue;
+                }
+                $parts = explode(';', $line);
+                foreach ($parts as $par) {
+                    if (strstr($par, '=')) {
+                        $keyValPair = explode('=', $par, 2);
+                        switch (trim(strtolower($keyValPair[0]))) {
+                            case 'type':
+                                // Type:
+                                $editableComments[$const]['type'] = trim($keyValPair[1]);
+                                break;
+                            case 'cat':
+                                // List of categories.
+                                $catSplit = explode('/', strtolower($keyValPair[1]));
+                                $catSplit[0] = trim($catSplit[0]);
+                                if (isset($categoryLabels[$catSplit[0]])) {
+                                    $catSplit[0] = $categoryLabels[$catSplit[0]];
+                                }
+                                $editableComments[$const]['cat'] = $catSplit[0];
+                                // This is the subcategory. Must be a key in $this->subCategories[].
+                                // catSplit[2] represents the search-order within the subcat.
+                                $catSplit[1] = trim($catSplit[1]);
+                                if ($catSplit[1] && isset($this->subCategories[$catSplit[1]])) {
+                                    $editableComments[$const]['subcat_name'] = $catSplit[1];
+                                    $orderIdentifier = isset($catSplit[2]) ? trim($catSplit[2]) : $counter;
+                                    $editableComments[$const]['subcat'] = $this->subCategories[$catSplit[1]][1]
+                                        . '/' . $catSplit[1] . '/' . $orderIdentifier . 'z';
+                                } elseif (isset($catSplit[2])) {
+                                    $editableComments[$const]['subcat'] = 'x' . '/' . trim($catSplit[2]) . 'z';
+                                } else {
+                                    $editableComments[$const]['subcat'] = 'x' . '/' . $counter . 'z';
+                                }
+                                break;
+                            case 'label':
+                                // Label
+                                $editableComments[$const]['label'] = trim($keyValPair[1]);
+                                break;
+                            case 'customcategory':
+                                // Custom category label
+                                $customCategory = explode('=', $keyValPair[1], 2);
+                                if (trim($customCategory[0])) {
+                                    $categoryKey = strtolower($customCategory[0]);
+                                    $categoryLabels[$categoryKey] = $this->getLanguageService()->sL($customCategory[1]);
+                                }
+                                break;
+                            case 'customsubcategory':
+                                // Custom subCategory label
+                                $customSubcategory = explode('=', $keyValPair[1], 2);
+                                if (trim($customSubcategory[0])) {
+                                    $subCategoryKey = strtolower($customSubcategory[0]);
+                                    $this->subCategories[$subCategoryKey][0] = $this->getLanguageService()->sL($customSubcategory[1]);
+                                }
+                                break;
+                        }
+                    }
+                }
+            }
+            if (isset($editableComments[$const])) {
+                $editableComments[$const]['name'] = $const;
+                $editableComments[$const]['value'] = trim($value);
+                $editableComments[$const]['default_value'] = trim($value);
+            }
+        }
+        return $editableComments;
+    }
+
+    /**
+     * Parsing the $this->raw TypoScript lines from pointer, $this->rawP
+     *
+     * @param array $setup Reference to the setup array in which to accumulate the values.
+     */
+    protected function parseSub(array &$setup)
+    {
+        while (isset($this->raw[$this->rawP])) {
+            $line = ltrim($this->raw[$this->rawP]);
+            $this->rawP++;
+            // Set comment flag?
+            if (strpos($line, '/*') === 0) {
+                $this->commentSet = 1;
+            }
+            if (!$this->commentSet && ($line)) {
+                if ($line[0] !== '}' && $line[0] !== '#' && $line[0] !== '/') {
+                    // If not brace-end or comment
+                    // Find object name string until we meet an operator
+                    $varL = strcspn($line, TAB . ' {=<>(');
+                    // check for special ":=" operator
+                    if ($varL > 0 && substr($line, $varL-1, 2) === ':=') {
+                        --$varL;
+                    }
+                    // also remove tabs after the object string name
+                    $objStrName = substr($line, 0, $varL);
+                    if ($objStrName !== '') {
+                        $r = [];
+                        if (preg_match('/[^[:alnum:]_\\\\\\.:-]/i', $objStrName, $r)) {
+                            throw new \RuntimeException(
+                                'Line ' . ($this->rawP - 1) . ': Object Name String, "' . htmlspecialchars($objStrName) . '" contains invalid character "' . $r[0] . '". Must be alphanumeric or one of: "_:-\\."',
+                                1507645381
+                            );
+                        }
+                        $line = ltrim(substr($line, $varL));
+                        if ($line === '') {
+                            throw new \RuntimeException(
+                                    'Line ' . ($this->rawP - 1) . ': Object Name String, "' . htmlspecialchars($objStrName) . '" was not followed by any operator, =<>({',
+                                    1507645417
+                                );
+                        }
+                        switch ($line[0]) {
+                                    case '=':
+                                        if (strpos($objStrName, '.') !== false) {
+                                            $value = [];
+                                            $value[0] = trim(substr($line, 1));
+                                            $this->setVal($objStrName, $setup, $value);
+                                        } else {
+                                            $setup[$objStrName] = trim(substr($line, 1));
+                                            if ($this->lastComment) {
+                                                // Setting comment..
+                                                $setup[$objStrName . '..'] .= $this->lastComment;
+                                            }
+                                        }
+                                        break;
+                                    case '{':
+                                        $this->inBrace++;
+                                        if (strpos($objStrName, '.') !== false) {
+                                            $this->rollParseSub($objStrName, $setup);
+                                        } else {
+                                            if (!isset($setup[$objStrName . '.'])) {
+                                                $setup[$objStrName . '.'] = [];
+                                            }
+                                            $this->parseSub($setup[$objStrName . '.']);
+                                        }
+                                        break;
+                                    default:
+                                        throw new \RuntimeException(
+                                            'Line ' . ($this->rawP - 1) . ': Object Name String, "' . htmlspecialchars($objStrName) . '" was not followed by any operator, =<>({',
+                                            1507645445
+                                        );
+                                }
+
+                        $this->lastComment = '';
+                    }
+                } elseif ($line[0] === '}') {
+                    $this->inBrace--;
+                    $this->lastComment = '';
+                    if ($this->inBrace < 0) {
+                        throw new \RuntimeException(
+                            'Line ' . ($this->rawP - 1) . ': An end brace is in excess.',
+                            1507645489
+                        );
+                    }
+                    break;
+                } else {
+                    $this->lastComment .= rtrim($line) . LF;
+                }
+            }
+            // Unset comment
+            if ($this->commentSet) {
+                if (strpos($line, '*/') === 0) {
+                    $this->commentSet = 0;
+                }
+            }
+        }
+    }
+
+    /**
+     * Parsing of TypoScript keys inside a curly brace where the key is composite of at least two keys,
+     * thus having to recursively call itself to get the value
+     *
+     * @param string $string The object sub-path, eg "thisprop.another_prot
+     * @param array $setup The local setup array from the function calling this function
+     */
+    protected function rollParseSub($string, array &$setup)
+    {
+        if ((string)$string === '') {
+            return;
+        }
+        list($key, $remainingKey) = $this->parseNextKeySegment($string);
+        $key .= '.';
+        if (!isset($setup[$key])) {
+            $setup[$key] = [];
+        }
+        $remainingKey === ''
+            ? $this->parseSub($setup[$key])
+            : $this->rollParseSub($remainingKey, $setup[$key]);
+    }
+
+    /**
+     * Setting a value/property of an object string in the setup array.
+     *
+     * @param string $string The object sub-path, eg "thisprop.another_prot
+     * @param array $setup The local setup array from the function calling this function.
+     * @param void
+     */
+    protected function setVal($string, array &$setup, $value)
+    {
+        if ((string)$string === '') {
+            return;
+        }
+
+        list($key, $remainingKey) = $this->parseNextKeySegment($string);
+        $subKey = $key . '.';
+        if ($remainingKey === '') {
+            if (isset($value[0])) {
+                $setup[$key] = $value[0];
+            }
+            if (isset($value[1])) {
+                $setup[$subKey] = $value[1];
+            }
+            if ($this->lastComment) {
+                $setup[$key . '..'] .= $this->lastComment;
+            }
+        } else {
+            if (!isset($setup[$subKey])) {
+                $setup[$subKey] = [];
+            }
+            $this->setVal($remainingKey, $setup[$subKey], $value);
+        }
+    }
+
+    /**
+     * Determines the first key segment of a TypoScript key by searching for the first
+     * unescaped dot in the given key string.
+     *
+     * Since the escape characters are only needed to correctly determine the key
+     * segment any escape characters before the first unescaped dot are
+     * stripped from the key.
+     *
+     * @param string $key The key, possibly consisting of multiple key segments separated by unescaped dots
+     * @return array Array with key segment and remaining part of $key
+     */
+    protected function parseNextKeySegment($key)
+    {
+        // if no dot is in the key, nothing to do
+        $dotPosition = strpos($key, '.');
+        if ($dotPosition === false) {
+            return [$key, ''];
+        }
+
+        if (strpos($key, '\\') !== false) {
+            // backslashes are in the key, so we do further parsing
+            while ($dotPosition !== false) {
+                if ($dotPosition > 0 && $key[$dotPosition - 1] !== '\\' || $dotPosition > 1 && $key[$dotPosition - 2] === '\\') {
+                    break;
+                }
+                // escaped dot found, continue
+                $dotPosition = strpos($key, '.', $dotPosition + 1);
+            }
+
+            if ($dotPosition === false) {
+                // no regular dot found
+                $keySegment = $key;
+                $remainingKey = '';
+            } else {
+                if ($dotPosition > 1 && $key[$dotPosition - 2] === '\\' && $key[$dotPosition - 1] === '\\') {
+                    $keySegment = substr($key, 0, $dotPosition - 1);
+                } else {
+                    $keySegment = substr($key, 0, $dotPosition);
+                }
+                $remainingKey = substr($key, $dotPosition + 1);
+            }
+
+            // fix key segment by removing escape sequences
+            $keySegment = str_replace('\\.', '.', $keySegment);
+        } else {
+            // no backslash in the key, we're fine off
+            list($keySegment, $remainingKey) = explode('.', $key, 2);
+        }
+        return [$keySegment, $remainingKey];
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService()
+    {
+        return $GLOBALS['LANG'];
+    }
 }
diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/ConfigurationUtilityTest.php b/typo3/sysext/extensionmanager/Tests/Unit/Utility/ConfigurationUtilityTest.php
index e9949c7bede4..c838ed6544df 100644
--- a/typo3/sysext/extensionmanager/Tests/Unit/Utility/ConfigurationUtilityTest.php
+++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/ConfigurationUtilityTest.php
@@ -123,49 +123,16 @@ class ConfigurationUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTes
         $configurationUtility
             ->expects($this->once())
             ->method('getDefaultConfigurationRawString')
-            ->will($this->returnValue('foo'));
-
-        $tsStyleConfig = $this->getMockBuilder(\TYPO3\CMS\Core\TypoScript\ConfigurationForm::class)->getMock();
+            ->will($this->returnValue(file_get_contents(__DIR__ . '/Fixtures/ext_conf_template.txt')));
 
         $objectManagerMock = $this->getMockBuilder(\TYPO3\CMS\Extbase\Object\ObjectManagerInterface::class)->getMock();
         $configurationUtility->_set('objectManager', $objectManagerMock);
-        $objectManagerMock
-            ->expects($this->once())
-            ->method('get')
-            ->with(\TYPO3\CMS\Core\TypoScript\ConfigurationForm::class)
-            ->will($this->returnValue($tsStyleConfig));
-
-        $constants = [
-            'checkConfigurationFE' => [
-                'cat' => 'basic',
-                'subcat_name' => 'enable',
-                'subcat' => 'a/enable/z',
-                'type' => 'user[TYPO3\\CMS\\Saltedpasswords\\Utility\\ExtensionManagerConfigurationUtility->checkConfigurationFrontend]',
-                'label' => 'Frontend configuration check',
-                'name' => 'checkConfigurationFE',
-                'value' => '0',
-                'default_value' => '0'
-            ],
-            'BE.forceSalted' => [
-                'cat' => 'advancedbackend',
-                'subcat' => 'x/z',
-                'type' => 'boolean',
-                'label' => 'Force salted passwords: Enforce usage of SaltedPasswords. Old MD5 hashed passwords will stop working.',
-                'name' => 'BE.forceSalted',
-                'value' => '0',
-                'default_value' => '0'
-            ]
-        ];
-        $tsStyleConfig
-            ->expects($this->once())
-            ->method('ext_initTSstyleConfig')
-            ->will($this->returnValue($constants));
 
         $expected = [
             'checkConfigurationFE' => [
                 'cat' => 'basic',
                 'subcat_name' => 'enable',
-                'subcat' => 'a/enable/z',
+                'subcat' => 'a/enable/1z',
                 'type' => 'user[TYPO3\\CMS\\Saltedpasswords\\Utility\\ExtensionManagerConfigurationUtility->checkConfigurationFrontend]',
                 'label' => 'Frontend configuration check',
                 'name' => 'checkConfigurationFE',
@@ -174,8 +141,8 @@ class ConfigurationUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTes
                 'subcat_label' => 'Enable features',
             ],
             'BE.forceSalted' => [
-                'cat' => 'advancedbackend',
-                'subcat' => 'x/z',
+                'cat' => 'backend',
+                'subcat' => 'x/2z',
                 'type' => 'boolean',
                 'label' => 'Force salted passwords: Enforce usage of SaltedPasswords. Old MD5 hashed passwords will stop working.',
                 'name' => 'BE.forceSalted',
diff --git a/typo3/sysext/extensionmanager/Tests/Unit/Utility/Fixtures/ext_conf_template.txt b/typo3/sysext/extensionmanager/Tests/Unit/Utility/Fixtures/ext_conf_template.txt
new file mode 100644
index 000000000000..1d8ab7160d78
--- /dev/null
+++ b/typo3/sysext/extensionmanager/Tests/Unit/Utility/Fixtures/ext_conf_template.txt
@@ -0,0 +1,5 @@
+# cat=Basic/enable; type=user[TYPO3\CMS\Saltedpasswords\Utility\ExtensionManagerConfigurationUtility->checkConfigurationFrontend]; label=Frontend configuration check
+checkConfigurationFE=0
+
+# cat=Backend; type=boolean; label=Force salted passwords: Enforce usage of SaltedPasswords. Old MD5 hashed passwords will stop working.
+BE.forceSalted = 0
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
index 63b7b6937cf4..db71de87bc80 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/ClassNameMatcher.php
@@ -389,6 +389,11 @@ return [
             'Breaking-82689-BackendAbstractWizardControllerNotExtendsAbstractModule.rst',
         ],
     ],
+    'TYPO3\CMS\Core\TypoScript\ConfigurationForm' => [
+        'restFiles' => [
+            'Deprecation-82725-DeprecateConfigurationForm.rst',
+        ],
+    ],
 
     // Removed interfaces
     'TYPO3\CMS\Backend\Form\DatabaseFileIconsHookInterface' => [
diff --git a/typo3/sysext/reports/Classes/Report/Status/SecurityStatus.php b/typo3/sysext/reports/Classes/Report/Status/SecurityStatus.php
index d48b5ab8031e..2beb0f053e58 100644
--- a/typo3/sysext/reports/Classes/Report/Status/SecurityStatus.php
+++ b/typo3/sysext/reports/Classes/Report/Status/SecurityStatus.php
@@ -19,7 +19,6 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
-use TYPO3\CMS\Core\TypoScript\ConfigurationForm;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Reports\Status as ReportStatus;
 use TYPO3\CMS\Reports\StatusProviderInterface;
@@ -185,7 +184,7 @@ class SecurityStatus implements StatusProviderInterface
         $configCheck = GeneralUtility::makeInstance(ExtensionManagerConfigurationUtility::class);
         $message = '<p>' . $this->getLanguageService()->getLL('status_saltedPasswords_infoText') . '</p>';
         $messageDetail = '';
-        $resultCheck = $configCheck->checkConfigurationBackend([], new ConfigurationForm());
+        $resultCheck = $configCheck->checkConfigurationBackend([]);
         switch ($resultCheck['errorType']) {
             case FlashMessage::INFO:
                 $messageDetail .= $resultCheck['html'];
diff --git a/typo3/sysext/saltedpasswords/Classes/Utility/ExtensionManagerConfigurationUtility.php b/typo3/sysext/saltedpasswords/Classes/Utility/ExtensionManagerConfigurationUtility.php
index 91e3000d34a8..38af2cbeab4f 100644
--- a/typo3/sysext/saltedpasswords/Classes/Utility/ExtensionManagerConfigurationUtility.php
+++ b/typo3/sysext/saltedpasswords/Classes/Utility/ExtensionManagerConfigurationUtility.php
@@ -158,10 +158,9 @@ class ExtensionManagerConfigurationUtility
      * $params['propertyName'] is set or not.
      *
      * @param array $params Field information to be rendered
-     * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
      * @return array|string array with errorType and HTML or only the HTML as string
      */
-    public function checkConfigurationBackend(array $params, $pObj)
+    public function checkConfigurationBackend(array $params)
     {
         $this->init();
         $extConf = $this->extConf['BE'];
@@ -267,10 +266,9 @@ class ExtensionManagerConfigurationUtility
      * $params['propertyName'] is set or not.
      *
      * @param array $params Field information to be rendered
-     * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
      * @return array|string array with errorType and HTML or only the HTML as string
      */
-    public function checkConfigurationFrontend(array $params, $pObj)
+    public function checkConfigurationFrontend(array $params)
     {
         $this->init();
         $extConf = $this->extConf['FE'];
@@ -356,11 +354,10 @@ class ExtensionManagerConfigurationUtility
      * Renders a selector element that allows to select the hash method to be used.
      *
      * @param array $params Field information to be rendered
-     * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
      * @param string $disposal The configuration disposal ('FE' or 'BE')
      * @return string The HTML selector
      */
-    protected function buildHashMethodSelector(array $params, $pObj, $disposal)
+    protected function buildHashMethodSelector(array $params, $disposal)
     {
         $this->init();
         $propertyName = $params['propertyName'];
@@ -385,12 +382,11 @@ class ExtensionManagerConfigurationUtility
      * used (frontend disposal).
      *
      * @param array $params Field information to be rendered
-     * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
      * @return string The HTML selector
      */
-    public function buildHashMethodSelectorFE(array $params, $pObj)
+    public function buildHashMethodSelectorFE(array $params)
     {
-        return $this->buildHashMethodSelector($params, $pObj, 'FE');
+        return $this->buildHashMethodSelector($params, 'FE');
     }
 
     /**
@@ -398,12 +394,11 @@ class ExtensionManagerConfigurationUtility
      * be used (backend disposal)
      *
      * @param array $params Field information to be rendered
-     * @param \TYPO3\CMS\Core\TypoScript\ConfigurationForm $pObj The calling parent object.
      * @return string The HTML selector
      */
-    public function buildHashMethodSelectorBE(array $params, $pObj)
+    public function buildHashMethodSelectorBE(array $params)
     {
-        return $this->buildHashMethodSelector($params, $pObj, 'BE');
+        return $this->buildHashMethodSelector($params, 'BE');
     }
 
     /**
-- 
GitLab