[BUGFIX] Use proper configuration when processing FlexForms in DataHandler 02/60902/6
authorBenni Mack <benni@typo3.org>
Mon, 17 Jun 2019 06:37:15 +0000 (08:37 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Wed, 19 Jun 2019 06:42:42 +0000 (08:42 +0200)
This change removes the "TCEforms" option when parsing
FlexForms data in DataHandler, when dealing with FlexForms
that contain sheets.

This way, FlexForms RTE configuration is properly set
and no double spacings for linebreaks are used.

According to the issue, this only happened when
fields specifically within sheets are configured,
for fields without sheets, this has been working
already.

In order to ensure both cases are working, tests
are applied for both variants.

Resolves: #80778
Resolves: #81748
Releases: master, 9.5, 8.7
Change-Id: I38facfa9e1065d4730f895aa178a049c07c443f8
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/60902
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Jan Kornblum <jan.kornblum@gmx.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Jan Kornblum <jan.kornblum@gmx.de>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/core/Classes/DataHandling/DataHandler.php
typo3/sysext/core/Tests/Functional/DataHandling/Flexform/ActionTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/LiveDefaultElements.csv [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/LiveDefaultPages.csv [new file with mode: 0644]

index bf282d1..5b7429c 100644 (file)
@@ -2838,30 +2838,32 @@ class DataHandler implements LoggerAwareInterface
                     $this->checkValue_flex_procInData_travDS($dataValues[$key]['el'], $dataValues_current[$key]['el'], $uploadedFiles[$key]['el'], $DSelements[$key]['el'], $pParams, $callBackFunc, $structurePath . $key . '/el/', $workspaceOptions);
                 }
             } else {
+                // When having no specific sheets, it's "TCEforms.config", when having a sheet, it's just "config"
+                $fieldConfiguration = $dsConf['TCEforms']['config'] ?? $dsConf['config'] ?? null;
                 // init with value from config for passthrough fields
-                if (!empty($dsConf['TCEforms']['config']['type']) && $dsConf['TCEforms']['config']['type'] === 'passthrough') {
+                if (!empty($fieldConfiguration['type']) && $fieldConfiguration['type'] === 'passthrough') {
                     if (!empty($dataValues_current[$key]['vDEF'])) {
                         // If there is existing value, keep it
                         $dataValues[$key]['vDEF'] = $dataValues_current[$key]['vDEF'];
                     } elseif (
-                        !empty($dsConf['TCEforms']['config']['default'])
+                        !empty($fieldConfiguration['default'])
                         && isset($pParams[1])
                         && !MathUtility::canBeInterpretedAsInteger($pParams[1])
                     ) {
                         // If is new record and a default is specified for field, use it.
-                        $dataValues[$key]['vDEF'] = $dsConf['TCEforms']['config']['default'];
+                        $dataValues[$key]['vDEF'] = $fieldConfiguration['default'];
                     }
                 }
-                if (!is_array($dsConf['TCEforms']['config']) || !is_array($dataValues[$key])) {
+                if (!is_array($fieldConfiguration) || !is_array($dataValues[$key])) {
                     continue;
                 }
 
                 foreach ($dataValues[$key] as $vKey => $data) {
                     if ($callBackFunc) {
                         if (is_object($this->callBackObj)) {
-                            $res = $this->callBackObj->{$callBackFunc}($pParams, $dsConf['TCEforms']['config'], $dataValues[$key][$vKey], $dataValues_current[$key][$vKey], $uploadedFiles[$key][$vKey], $structurePath . $key . '/' . $vKey . '/', $workspaceOptions);
+                            $res = $this->callBackObj->{$callBackFunc}($pParams, $fieldConfiguration, $dataValues[$key][$vKey], $dataValues_current[$key][$vKey], $uploadedFiles[$key][$vKey], $structurePath . $key . '/' . $vKey . '/', $workspaceOptions);
                         } else {
-                            $res = $this->{$callBackFunc}($pParams, $dsConf['TCEforms']['config'], $dataValues[$key][$vKey], $dataValues_current[$key][$vKey], $uploadedFiles[$key][$vKey], $structurePath . $key . '/' . $vKey . '/', $workspaceOptions);
+                            $res = $this->{$callBackFunc}($pParams, $fieldConfiguration, $dataValues[$key][$vKey], $dataValues_current[$key][$vKey], $uploadedFiles[$key][$vKey], $structurePath . $key . '/' . $vKey . '/', $workspaceOptions);
                         }
                     } else {
                         // Default
@@ -2872,7 +2874,7 @@ class DataHandler implements LoggerAwareInterface
                             'flexFormPath' => trim(rtrim($structurePath, '/') . '/' . $key . '/' . $vKey, '/'),
                         ];
 
-                        $res = $this->checkValue_SW([], $dataValues[$key][$vKey], $dsConf['TCEforms']['config'], $CVtable, $CVid, $dataValues_current[$key][$vKey], $CVstatus, $CVrealPid, $CVrecFID, '', $uploadedFiles[$key][$vKey], $CVtscPID, $additionalData);
+                        $res = $this->checkValue_SW([], $dataValues[$key][$vKey], $fieldConfiguration, $CVtable, $CVid, $dataValues_current[$key][$vKey], $CVstatus, $CVrealPid, $CVrecFID, '', $uploadedFiles[$key][$vKey], $CVtscPID, $additionalData);
                     }
                     // Adding the value:
                     if (isset($res['value'])) {
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Flexform/ActionTest.php b/typo3/sysext/core/Tests/Functional/DataHandling/Flexform/ActionTest.php
new file mode 100644 (file)
index 0000000..3f8eaf7
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\DataHandling\Flexform;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\Functional\DataHandling\AbstractDataHandlerActionTestCase;
+
+class ActionTest extends AbstractDataHandlerActionTestCase
+{
+    const VALUE_ContentId = 100;
+    /**
+     * @var string
+     */
+    protected $scenarioDataSetDirectory = 'typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/';
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+        $this->importScenarioDataSet('LiveDefaultPages');
+        $this->importScenarioDataSet('LiveDefaultElements');
+    }
+
+    /**
+     * @test
+     */
+    public function transformationAppliesForRichTextFieldsWithoutSheets()
+    {
+        $GLOBALS['TCA']['tt_content']['columns']['pi_flexform']['config']['ds']['default'] = '<?xml version="1.0" encoding="UTF-8"?>
+<T3DataStructure>
+    <meta>
+        <langDisable>0</langDisable>
+    </meta>
+    <ROOT type="array">
+        <type>array</type>
+        <el type="array">
+            <settings.bodytext>
+                <TCEforms type="array">
+                    <label>Random Bodytext</label>
+                    <config type="array">
+                        <type>text</type>
+                        <cols>48</cols>
+                        <rows>5</rows>
+                        <enableRichtext>1</enableRichtext>
+                        <richtextConfiguration>default</richtextConfiguration>
+                    </config>
+                </TCEforms>
+            </settings.bodytext>
+        </el>
+    </ROOT>
+</T3DataStructure>';
+
+        $expected = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<T3FlexForms>
+    <data>
+        <sheet index="sDEF">
+            <language index="lDEF">
+                <field index="settings.isNotDefined">1</field>
+                <field index="settings.bodytext">
+                    <value index="vDEF">&lt;p class=&quot;align-right&quot;&gt;First line&lt;/p&gt;
+&lt;p&gt;Last line&lt;/p&gt;</value>
+                </field>
+            </language>
+        </sheet>
+    </data>
+</T3FlexForms>';
+
+        $this->getActionService()->modifyRecords(1, [
+            'tt_content' => [
+                'uid' => self::VALUE_ContentId,
+                'pi_flexform' => [
+                    'data' => [
+                        'sDEF' => [
+                            'lDEF' => [
+                                'settings.isNotDefined' => '1',
+                                'settings.bodytext' => [
+                                    'vDEF' => '<p class="align-right">First line</p>
+
+<p>Last line</p>'
+                                ]
+                            ]
+                        ]
+                    ]
+                ]
+            ]
+        ]);
+
+        $queryBuilder = $this->getConnectionPool()
+            ->getQueryBuilderForTable('tt_content');
+        $queryBuilder->getRestrictions()->removeAll();
+        $flexFormContent = $queryBuilder
+            ->select('pi_flexform')
+            ->from('tt_content')
+            ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter(self::VALUE_ContentId, \PDO::PARAM_INT)))
+            ->execute()
+            ->fetchColumn(0);
+
+        $this->assertEquals($expected, $flexFormContent);
+    }
+
+    /**
+     * @test
+     */
+    public function transformationAppliesForRichTextFieldsWithSheets()
+    {
+        $GLOBALS['TCA']['tt_content']['columns']['pi_flexform']['config']['ds']['default'] = '<T3DataStructure>
+    <meta>
+        <langDisable>1</langDisable>
+    </meta>
+    <sheets>
+        <sheet1>
+            <ROOT>
+                <TCEforms>
+                    <sheetTitle>Text Example with an RTE field</sheetTitle>
+                </TCEforms>
+                <type>array</type>
+                <el>
+                    <settings.bodytext>
+                        <label>Random Bodytext</label>
+                        <config>
+                            <type>text</type>
+                            <rows>5</rows>
+                            <cols>30</cols>
+                            <eval>trim,required</eval>
+                            <enableRichtext>1</enableRichtext>
+                            <richtextConfiguration>default</richtextConfiguration>
+                        </config>
+                    </settings.bodytext>
+                </el>
+            </ROOT>
+        </sheet1>
+    </sheets>
+</T3DataStructure>';
+
+        $expected = '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<T3FlexForms>
+    <data>
+        <sheet index="sheet1">
+            <language index="lDEF">
+                <field index="settings.isNotDefined">1</field>
+                <field index="settings.bodytext">
+                    <value index="vDEF">&lt;p class=&quot;align-right&quot;&gt;First line&lt;/p&gt;
+&lt;p&gt;Last line&lt;/p&gt;</value>
+                </field>
+            </language>
+        </sheet>
+    </data>
+</T3FlexForms>';
+
+        $this->getActionService()->modifyRecords(1, [
+            'tt_content' => [
+                'uid' => self::VALUE_ContentId,
+                'pi_flexform' => [
+                    'data' => [
+                        'sheet1' => [
+                            'lDEF' => [
+                                'settings.isNotDefined' => '1',
+                                'settings.bodytext' => [
+                                    'vDEF' => '<p class="align-right">First line</p>
+
+<p>Last line</p>'
+                                ]
+                            ]
+                        ]
+                    ]
+                ]
+            ]
+        ]);
+
+        $queryBuilder = $this->getConnectionPool()
+            ->getQueryBuilderForTable('tt_content');
+        $queryBuilder->getRestrictions()->removeAll();
+        $flexFormContent = $queryBuilder
+            ->select('pi_flexform')
+            ->from('tt_content')
+            ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter(self::VALUE_ContentId, \PDO::PARAM_INT)))
+            ->execute()
+            ->fetchColumn(0);
+
+        $this->assertEquals($expected, $flexFormContent);
+    }
+}
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/LiveDefaultElements.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/LiveDefaultElements.csv
new file mode 100644 (file)
index 0000000..753456e
--- /dev/null
@@ -0,0 +1,3 @@
+"tt_content",,,,,,,,,,,,,,,
+,"uid","pid","CType","sorting","deleted","sys_language_uid","l18n_parent","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","header","pi_flexform"
+,100,1,"list",256,0,0,0,0,0,0,0,0,0,"Content #1",""
diff --git a/typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/LiveDefaultPages.csv b/typo3/sysext/core/Tests/Functional/DataHandling/Flexform/DataSet/LiveDefaultPages.csv
new file mode 100644 (file)
index 0000000..2521e0a
--- /dev/null
@@ -0,0 +1,4 @@
+"pages",,,,,,,,,,,
+,"uid","pid","sorting","deleted","t3_origuid","t3ver_wsid","t3ver_state","t3ver_stage","t3ver_oid","t3ver_move_id","title"
+,1,0,256,0,0,0,0,0,0,0,"DataHandlerTest"
+,2,1,256,0,0,0,0,0,0,0,"Second Test page"