From 2f6df56cfeec04132bd9624bce2ab75b1080e863 Mon Sep 17 00:00:00 2001
From: Nikita Hovratov <nikita.h@live.de>
Date: Thu, 7 Oct 2021 18:16:16 +0200
Subject: [PATCH] [BUGFIX] Fix validation in form override settings

The FinisherOptionGenerator of the form extension
generates the data structure for the form setting
overrides on the fly. By doing so, it didn't make
a distinction between normal TCA fields and flexform
specific sections/containers and added the wrapper
"TCEforms" to sections as well, which broke the
validation in DataHandler for the fields inside the
container (E.g. the email field).

The patch checks if section is set to "true" and
adds the "TCEforms" key only for normal TCA field
configurations.

Unit tests have been added for the DataHandler
checkValue_flex_procInData_travDS method, which
show cases with and without the "TCEforms" key.

Also, since this works now, a PHP 8 warning
appeared. This is fixed now, too.

Resolves: #95441
Releases: main, 11.5
Change-Id: Ib12a0484bcbdc827664181ca6af89edfadee13d8
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/71490
Tested-by: core-ci <typo3@b13.com>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Benni Mack <benni@typo3.org>
---
 .../core/Classes/DataHandling/DataHandler.php |   2 +-
 .../Unit/DataHandling/DataHandlerTest.php     | 182 ++++++++++++++++++
 .../Processors/FinisherOptionGenerator.php    |   6 +-
 3 files changed, 188 insertions(+), 2 deletions(-)

diff --git a/typo3/sysext/core/Classes/DataHandling/DataHandler.php b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
index 90b3346c6429..5c8657cd194a 100644
--- a/typo3/sysext/core/Classes/DataHandling/DataHandler.php
+++ b/typo3/sysext/core/Classes/DataHandling/DataHandler.php
@@ -2910,7 +2910,7 @@ class DataHandler implements LoggerAwareInterface
         foreach ($DSelements as $key => $dsConf) {
             // Array/Section:
             if (isset($DSelements[$key]['type']) && $DSelements[$key]['type'] === 'array') {
-                if (!is_array($dataValues[$key]['el'])) {
+                if (!is_array($dataValues[$key]['el'] ?? null)) {
                     continue;
                 }
 
diff --git a/typo3/sysext/core/Tests/Unit/DataHandling/DataHandlerTest.php b/typo3/sysext/core/Tests/Unit/DataHandling/DataHandlerTest.php
index 18d6fb5ababe..ac446a9888a6 100644
--- a/typo3/sysext/core/Tests/Unit/DataHandling/DataHandlerTest.php
+++ b/typo3/sysext/core/Tests/Unit/DataHandling/DataHandlerTest.php
@@ -652,6 +652,188 @@ class DataHandlerTest extends UnitTestCase
         $this->subject->_call('checkValueForFlex', [], [], [], '', 0, '', '', 0, 0, 0, '');
     }
 
+    public function checkValue_flex_procInData_travDSDataProvider(): iterable
+    {
+        yield 'Flat structure with TCEForms' => [
+            'dataValues' => [
+                'field1' => [
+                    'vDEF' => 'wrong input',
+                ],
+            ],
+            'DSelements' => [
+                'field1' => [
+                    'TCEforms' => [
+                        'label' => 'A field',
+                        'config' => [
+                            'type' => 'input',
+                            'eval' => 'required,int',
+                        ],
+                    ],
+                ],
+            ],
+            'expected' => [
+                'field1' => [
+                    'vDEF' => 0,
+                ],
+            ],
+        ];
+
+        yield 'Flat structure without TCEForms' => [
+            'dataValues' => [
+                'field1' => [
+                    'vDEF' => 'wrong input',
+                ],
+            ],
+            'DSelements' => [
+                'field1' => [
+                    'label' => 'A field',
+                    'config' => [
+                        'type' => 'input',
+                        'eval' => 'required,int',
+                    ],
+                ],
+            ],
+            'expected' => [
+                'field1' => [
+                    'vDEF' => 0,
+                ],
+            ],
+        ];
+
+        yield 'Array structure with TCEforms key' => [
+            'dataValues' => [
+                'section' => [
+                    'el' => [
+                        '1' => [
+                            'container1' => [
+                                'el' => [
+                                    'field1' => [
+                                        'vDEF' => 'wrong input',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            'DSelements' => [
+                'section' => [
+                    'type' => 'array',
+                    'section' => true,
+                    'el' => [
+                        'container1' => [
+                            'type' => 'array',
+                            'el' => [
+                                'field1' => [
+                                    'TCEforms' => [
+                                        'label' => 'A field',
+                                        'config' => [
+                                            'type' => 'input',
+                                            'eval' => 'required,int',
+                                        ],
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            'expected' => [
+                'section' => [
+                    'el' => [
+                        '1' => [
+                            'container1' => [
+                                'el' => [
+                                    'field1' => [
+                                        'vDEF' => 0,
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+
+        yield 'Array structure without TCEforms key' => [
+            'dataValues' => [
+                'section' => [
+                    'el' => [
+                        '1' => [
+                            'container_1' => [
+                                'el' => [
+                                    'field1' => [
+                                        'vDEF' => 'wrong input',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            'DSelements' => [
+                'section' => [
+                    'type' => 'array',
+                    'section' => true,
+                    'el' => [
+                        'container_1' => [
+                            'type' => 'array',
+                            'el' => [
+                                'field1' => [
+                                    'label' => 'A field',
+                                    'config' => [
+                                        'type' => 'input',
+                                        'eval' => 'required,int',
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+            'expected' => [
+                'section' => [
+                    'el' => [
+                        '1' => [
+                            'container_1' => [
+                                'el' => [
+                                    'field1' => [
+                                        'vDEF' => 0,
+                                    ],
+                                ],
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+    }
+
+    /**
+     * This test ensures, that the eval method checkValue_SW is called on
+     * flexform structures.
+     *
+     * @test
+     * @dataProvider checkValue_flex_procInData_travDSDataProvider
+     */
+    public function checkValue_flex_procInData_travDS(array $dataValues, array $DSelements, array $expected): void
+    {
+        $pParams = [
+            'tt_content',
+            777,
+            '<?xml ... ?>',
+            'update',
+            1,
+            'tt_content:777:pi_flexform',
+            0,
+        ];
+
+        $languageServiceProphecy = $this->prophesize(LanguageService::class);
+        $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
+        $this->subject->checkValue_flex_procInData_travDS($dataValues, [], $DSelements, $pParams, '', '');
+        self::assertSame($expected, $dataValues);
+    }
+
     /////////////////////////////////////
     // Tests concerning log
     /////////////////////////////////////
diff --git a/typo3/sysext/form/Classes/Domain/Configuration/FlexformConfiguration/Processors/FinisherOptionGenerator.php b/typo3/sysext/form/Classes/Domain/Configuration/FlexformConfiguration/Processors/FinisherOptionGenerator.php
index 1ac281f2edd0..1ab63eecd768 100644
--- a/typo3/sysext/form/Classes/Domain/Configuration/FlexformConfiguration/Processors/FinisherOptionGenerator.php
+++ b/typo3/sysext/form/Classes/Domain/Configuration/FlexformConfiguration/Processors/FinisherOptionGenerator.php
@@ -88,7 +88,11 @@ class FinisherOptionGenerator extends AbstractProcessor
         }
 
         $sheetElements = $this->converterDto->getResult();
-        $sheetElements['settings.finishers.' . $finisherIdentifier . '.' . $optionKey]['TCEforms'] = $elementConfiguration;
+        if ($elementConfiguration['section'] ?? false) {
+            $sheetElements['settings.finishers.' . $finisherIdentifier . '.' . $optionKey] = $elementConfiguration;
+        } else {
+            $sheetElements['settings.finishers.' . $finisherIdentifier . '.' . $optionKey]['TCEforms'] = $elementConfiguration;
+        }
 
         $this->converterDto->setResult($sheetElements);
     }
-- 
GitLab