[BUGFIX] Override flex form field label with page TSConfig 39/47939/2
authorChristian Kuhn <lolli@schwarzbu.ch>
Tue, 26 Apr 2016 12:42:04 +0000 (14:42 +0200)
committerMorton Jonuschat <m.jonuschat@mojocode.de>
Wed, 27 Apr 2016 17:40:42 +0000 (19:40 +0200)
Move the data handling to calculate a final field label
value from PaletteAndSingleFieldContainer to an own data
provider and register this provider for full database records
and for flex form processing.
This way flex form field label overrides via page TSConfig are fixed,
eg. this changes the "Order By" label of ext:news flex form:

TCEFORM.tt_content.pi_flexform.news_pi1.sDEF.settings\.orderBy.label = override

Language specific overrides in flex fields now work as well

...settings\.orderBy.label.fr = French override

Change-Id: I02474e9cca9db3e949c217f21f5704ec16641545
Resolves: #75606
Releases: master, 7.6
Reviewed-on: https://review.typo3.org/47939
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Morton Jonuschat <m.jonuschat@mojocode.de>
Tested-by: Morton Jonuschat <m.jonuschat@mojocode.de>
typo3/sysext/backend/Classes/Form/Container/PaletteAndSingleContainer.php
typo3/sysext/backend/Classes/Form/FormDataProvider/TcaColumnsProcessFieldLabels.php [new file with mode: 0644]
typo3/sysext/backend/Classes/Form/FormDataProvider/TcaTypesShowitem.php
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseRowInitializeNewTest.php
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaColumnsProcessFieldLabelsTest.php [new file with mode: 0644]
typo3/sysext/core/Configuration/DefaultConfiguration.php

index 288c673..006c44f 100644 (file)
@@ -137,10 +137,14 @@ class PaletteAndSingleContainer extends AbstractContainer
 
                 if (!empty($childResultArray['html'])) {
                     $mainStructureCounter ++;
+                    $fieldLabel = '';
+                    if (!empty($this->data['processedTca']['columns'][$fieldName]['label'])) {
+                        $fieldLabel = $this->data['processedTca']['columns'][$fieldName]['label'];
+                    }
                     $targetStructure[$mainStructureCounter] = array(
                         'type' => 'single',
                         'fieldName' => $fieldConfiguration['fieldName'],
-                        'fieldLabel' => $this->getSingleFieldLabel($fieldName, $fieldConfiguration['fieldLabel']),
+                        'fieldLabel' => $fieldLabel,
                         'fieldHtml' => $childResultArray['html'],
                     );
                 }
@@ -212,10 +216,14 @@ class PaletteAndSingleContainer extends AbstractContainer
 
                 if (!empty($singleFieldContentArray['html'])) {
                     $foundRealElement = true;
+                    $fieldLabel = '';
+                    if (!empty($this->data['processedTca']['columns'][$fieldName]['label'])) {
+                        $fieldLabel = $this->data['processedTca']['columns'][$fieldName]['label'];
+                    }
                     $resultStructure[] = array(
                         'type' => 'single',
                         'fieldName' => $fieldName,
-                        'fieldLabel' => $this->getSingleFieldLabel($fieldName, $fieldArray['fieldLabel']),
+                        'fieldLabel' => $fieldLabel,
                         'fieldHtml' => $singleFieldContentArray['html'],
                     );
                     $singleFieldContentArray['html'] = '';
@@ -376,41 +384,6 @@ class PaletteAndSingleContainer extends AbstractContainer
     }
 
     /**
-     * Determine label of a single field (not a palette label)
-     *
-     * @param string $fieldName The field name to calculate the label for
-     * @param string $labelFromShowItem Given label, typically from show item configuration
-     * @return string Field label
-     */
-    protected function getSingleFieldLabel($fieldName, $labelFromShowItem)
-    {
-        $languageService = $this->getLanguageService();
-        $table = $this->data['tableName'];
-        $label = $labelFromShowItem;
-        if (!empty($this->data['processedTca']['columns'][$fieldName]['label'])) {
-            $label = $this->data['processedTca']['columns'][$fieldName]['label'];
-        }
-        if (!empty($labelFromShowItem)) {
-            $label = $labelFromShowItem;
-        }
-
-        $fieldTSConfig = [];
-        if (isset($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'])
-            && is_array($this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'])
-        ) {
-            $fieldTSConfig = $this->data['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'];
-        }
-
-        if (!empty($fieldTSConfig['label'])) {
-            $label = $fieldTSConfig['label'];
-        }
-        if (!empty($fieldTSConfig['label.'][$languageService->lang])) {
-            $label = $fieldTSConfig['label.'][$languageService->lang];
-        }
-        return $languageService->sL($label);
-    }
-
-    /**
      * TRUE if field is of type user and to wrapping is requested
      *
      * @param array $element Current element from "target structure" array
diff --git a/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaColumnsProcessFieldLabels.php b/typo3/sysext/backend/Classes/Form/FormDataProvider/TcaColumnsProcessFieldLabels.php
new file mode 100644 (file)
index 0000000..dad8242
--- /dev/null
@@ -0,0 +1,162 @@
+<?php
+namespace TYPO3\CMS\Backend\Form\FormDataProvider;
+
+/*
+ * 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\Backend\Form\FormDataProviderInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * Works on processedTca to determine the final value of field labels.
+ *
+ * processedTca['columns]['aField']['label']
+ */
+class TcaColumnsProcessFieldLabels implements FormDataProviderInterface
+{
+    /**
+     * Iterate over all processedTca columns fields
+     *
+     * @param array $result Result array
+     * @return array Modified result array
+     */
+    public function addData(array $result)
+    {
+        $result = $this->setLabelFromShowitemAndPalettes($result);
+        $result = $this->setLabelFromPageTsConfig($result);
+        $result = $this->translatelabels($result);
+        return $result;
+    }
+
+    /**
+     * The label of a single field can be set in the showitem configuration
+     * of the record type and as palettes showitem as second ";" separated argument:
+     *
+     * processedTca['types']['aType']['showitem'] = 'aFieldName;aLabelOverride, --palette--;;aPaletteName'
+     * processedTca['palettes']['aPaletteName']['showitem'] = 'anotherFieldName;anotherLabelOverride'
+     *
+     *
+     * @param array $result Result array
+     * @return array Modified result array
+     */
+    protected function setLabelFromShowitemAndPalettes(array $result)
+    {
+        $recordTypeValue = $result['recordTypeValue'];
+        // flex forms don't have a showitem / palettes configuration - early return
+        if (!isset($result['processedTca']['types'][$recordTypeValue]['showitem'])) {
+            return $result;
+        }
+        $showItemArray = GeneralUtility::trimExplode(',', $result['processedTca']['types'][$recordTypeValue]['showitem']);
+        foreach ($showItemArray as $aShowItemFieldString) {
+            $aShowItemFieldArray = GeneralUtility::trimExplode(';', $aShowItemFieldString);
+            $aShowItemFieldArray = [
+                'fieldName' => $aShowItemFieldArray[0],
+                'fieldLabel' => $aShowItemFieldArray[1] ?: null,
+                'paletteName' => $aShowItemFieldArray[2] ?: null,
+            ];
+            if ($aShowItemFieldArray['fieldName'] === '--div--') {
+                // tabs are not of interest here
+                continue;
+            } elseif ($aShowItemFieldArray['fieldName'] === '--palette--') {
+                // showitem references to a palette field. unpack the palette and process
+                // label overrides that may be in there.
+                if (!isset($result['processedTca']['palettes'][$aShowItemFieldArray['paletteName']]['showitem'])) {
+                    // No palette with this name found? Skip it.
+                    continue;
+                }
+                $palettesArray = GeneralUtility::trimExplode(
+                    ',',
+                    $result['processedTca']['palettes'][$aShowItemFieldArray['paletteName']]['showitem']
+                );
+                foreach ($palettesArray as $aPalettesString) {
+                    $aPalettesArray = GeneralUtility::trimExplode(';', $aPalettesString);
+                    $aPalettesArray = [
+                        'fieldName' => $aPalettesArray[0],
+                        'fieldLabel' => $aPalettesArray[1] ?: null,
+                    ];
+                    if (!empty($aPalettesArray['fieldLabel'])
+                        && isset($result['processedTca']['columns'][$aPalettesArray['fieldName']])
+                    ) {
+                        $result['processedTca']['columns'][$aPalettesArray['fieldName']]['label'] = $aPalettesArray['fieldLabel'];
+                    }
+                }
+            } else {
+                // If the field has a label in the showitem configuration of this record type, use it.
+                // showitem = 'aField, aFieldWithLabelOverride;theLabel, anotherField'
+                if (!empty($aShowItemFieldArray['fieldLabel'])
+                    && isset($result['processedTca']['columns'][$aShowItemFieldArray['fieldName']])
+                ) {
+                    $result['processedTca']['columns'][$aShowItemFieldArray['fieldName']]['label'] = $aShowItemFieldArray['fieldLabel'];
+                }
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * pageTsConfig can override labels:
+     *
+     * TCEFORM.aTable.aField.label = 'override'
+     * TCEFORM.aTable.aField.label.en = 'override'
+     *
+     * @param array $result Result array
+     * @return array Modified result array
+     */
+    protected function setLabelFromPageTsConfig(array $result)
+    {
+        $languageService = $this->getLanguageService();
+        $table = $result['tableName'];
+        foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfiguration) {
+            $fieldTSConfig = [];
+            if (isset($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'])
+                && is_array($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'])
+            ) {
+                $fieldTSConfig = $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.'];
+            }
+            if (!empty($fieldTSConfig['label'])) {
+                $result['processedTca']['columns'][$fieldName]['label'] = $fieldTSConfig['label'];
+            }
+            if (!empty($fieldTSConfig['label.'][$languageService->lang])) {
+                $result['processedTca']['columns'][$fieldName]['label'] = $fieldTSConfig['label.'][$languageService->lang];
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Translate all labels if needed.
+     *
+     * @param array $result Result array
+     * @return array Modified result array
+     */
+    protected function translateLabels(array $result)
+    {
+        $languageService = $this->getLanguageService();
+        foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfiguration) {
+            if (!isset($fieldConfiguration['label'])) {
+                continue;
+            }
+            $result['processedTca']['columns'][$fieldName]['label'] = $languageService->sL($fieldConfiguration['label']);
+        }
+        return $result;
+    }
+
+    /**
+     * @return LanguageService
+     */
+    protected function getLanguageService()
+    {
+        return $GLOBALS['LANG'];
+    }
+}
index c674c8e..40d325e 100644 (file)
@@ -21,7 +21,7 @@ use TYPO3\CMS\Core\Utility\MathUtility;
 /**
  * Create final showitem configuration in processedTca for types and palette
  * fields
- * Handles all the nasty defails like subtypes_addlist and friends.
+ * Handles all the nasty details like subtypes_addlist and friends.
  */
 class TcaTypesShowitem implements FormDataProviderInterface
 {
index 11c1588..854bed6 100644 (file)
@@ -89,7 +89,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFormUserTsIfColumnIsDefinedInTca()
+    public function addDataSetsDefaultDataFromUserTsIfColumnIsDefinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -120,7 +120,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataDoesNotSetDefaultDataFormUserTsIfColumnIsMissingInTca()
+    public function addDataDoesNotSetDefaultDataFromUserTsIfColumnIsMissingInTca()
     {
         $input = [
             'command' => 'new',
@@ -148,7 +148,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFormPageTsIfColumnIsDefinedInTca()
+    public function addDataSetsDefaultDataFromPageTsIfColumnIsDefinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -179,7 +179,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataDoesNotSetDefaultDataFormPageTsIfColumnIsMissingInTca()
+    public function addDataDoesNotSetDefaultDataFromPageTsIfColumnIsMissingInTca()
     {
         $input = [
             'command' => 'new',
@@ -207,7 +207,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataOverrulingFormPageTs()
+    public function addDataSetsDefaultDataOverrulingFromPageTs()
     {
         $input = [
             'command' => 'new',
@@ -319,7 +319,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFormGetIfColumnIsDenfinedInTca()
+    public function addDataSetsDefaultDataFromGetIfColumnIsDefinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -350,7 +350,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataSetsDefaultDataFromPostIfColumnIsDenfinedInTca()
+    public function addDataSetsDefaultDataFromPostIfColumnIsDefinedInTca()
     {
         $input = [
             'command' => 'new',
@@ -419,7 +419,7 @@ class DatabaseRowInitializeNewTest extends UnitTestCase
     /**
      * @test
      */
-    public function addDataDoesNotSetDefaultDataFormGetPostIfColumnIsMissingInTca()
+    public function addDataDoesNotSetDefaultDataFromGetPostIfColumnIsMissingInTca()
     {
         $input = [
             'command' => 'new',
diff --git a/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaColumnsProcessFieldLabelsTest.php b/typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/TcaColumnsProcessFieldLabelsTest.php
new file mode 100644 (file)
index 0000000..7e79cd0
--- /dev/null
@@ -0,0 +1,189 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Form\FormDataProvider;
+
+/*
+ * 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\Backend\Form\FormDataProvider\TcaColumnsProcessFieldLabels;
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Lang\LanguageService;
+
+/**
+ * Test case
+ */
+class TcaColumnsProcessFieldLabelsTest extends UnitTestCase
+{
+    /**
+     * @var TcaColumnsProcessFieldLabels
+     */
+    protected $subject;
+
+    protected function setUp()
+    {
+        $this->subject = new TcaColumnsProcessFieldLabels();
+    }
+
+    /**
+     * @test
+     */
+    public function addDataKeepsLabelAsIsIfNoOverrideIsGiven()
+    {
+        $input = [
+            'processedTca' => [
+                'columns' => [
+                    'aField' => [
+                        'label' => 'foo',
+                    ],
+                ],
+            ],
+        ];
+        $languageServiceProphecy = $this->prophesize(LanguageService::class);
+        $languageServiceProphecy->sL('foo')->shouldBeCalled()->willReturnArgument(0);
+        $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
+
+        $expected = $input;
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
+
+    /**
+     * @test
+     */
+    public function addDataSetsLabelFromShowitem()
+    {
+        $input = [
+            'processedTca' => [
+                'columns' => [
+                    'aField' => [
+                        'label' => 'origLabel',
+                    ],
+                ],
+                'types' => [
+                    'aType' => [
+                        'showitem' => 'aField;aLabelOverride',
+                    ],
+                ],
+            ],
+            'recordTypeValue' => 'aType',
+        ];
+        $languageServiceProphecy = $this->prophesize(LanguageService::class);
+        $languageServiceProphecy->sL('aLabelOverride')->shouldBeCalled()->willReturnArgument(0);
+        $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
+
+        $expected = $input;
+        $expected['processedTca']['columns']['aField']['label'] = 'aLabelOverride';
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
+
+    /**
+     * @test
+     */
+    public function addDataSetsLabelFromPalettesShowitem()
+    {
+        $input = [
+            'processedTca' => [
+                'columns' => [
+                    'aField' => [
+                        'label' => 'origLabel',
+                    ],
+                ],
+                'types' => [
+                    'aType' => [
+                        'showitem' => '--palette--;;aPalette',
+                    ],
+                ],
+                'palettes' => [
+                    'aPalette' => [
+                        'showitem' => 'aField;aLabelOverride',
+                    ],
+                ],
+            ],
+            'recordTypeValue' => 'aType',
+        ];
+        $languageServiceProphecy = $this->prophesize(LanguageService::class);
+        $languageServiceProphecy->sL('aLabelOverride')->shouldBeCalled()->willReturnArgument(0);
+        $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
+
+        $expected = $input;
+        $expected['processedTca']['columns']['aField']['label'] = 'aLabelOverride';
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
+
+    /**
+     * @test
+     */
+    public function addDataSetsLabelFromPageTsConfig()
+    {
+        $input = [
+            'tableName' => 'aTable',
+            'processedTca' => [
+                'columns' => [
+                    'aField' => [
+                        'label' => 'origLabel',
+                    ],
+                ],
+            ],
+            'pageTsConfig' => [
+                'TCEFORM.' => [
+                    'aTable.' => [
+                        'aField.' => [
+                            'label' => 'aLabelOverride',
+                        ],
+                    ],
+                ],
+            ],
+        ];
+        $languageServiceProphecy = $this->prophesize(LanguageService::class);
+        $languageServiceProphecy->sL('aLabelOverride')->shouldBeCalled()->willReturnArgument(0);
+        $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
+
+        $expected = $input;
+        $expected['processedTca']['columns']['aField']['label'] = 'aLabelOverride';
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
+
+    /**
+     * @test
+     */
+    public function addDataSetsLabelFromPageTsConfigForSpecificLanguage()
+    {
+        $input = [
+            'tableName' => 'aTable',
+            'processedTca' => [
+                'columns' => [
+                    'aField' => [
+                        'label' => 'origLabel',
+                    ],
+                ],
+            ],
+            'pageTsConfig' => [
+                'TCEFORM.' => [
+                    'aTable.' => [
+                        'aField.' => [
+                            'label.' => [
+                                'fr' => 'aLabelOverride',
+                            ],
+                        ],
+                    ],
+                ],
+            ],
+        ];
+        $languageServiceProphecy = $this->prophesize(LanguageService::class);
+        $languageServiceProphecy->lang = 'fr';
+        $languageServiceProphecy->sL('aLabelOverride')->shouldBeCalled()->willReturnArgument(0);
+        $GLOBALS['LANG'] = $languageServiceProphecy->reveal();
+
+        $expected = $input;
+        $expected['processedTca']['columns']['aField']['label'] = 'aLabelOverride';
+        $this->assertSame($expected, $this->subject->addData($input));
+    }
+}
index 901668f..5a7f4d5 100644 (file)
@@ -471,7 +471,12 @@ return array(
                             \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRecordTypeValue::class,
                             \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseSystemLanguageRows::class,
                             \TYPO3\CMS\Backend\Form\FormDataProvider\InitializeProcessedTca::class,
-                            \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsRemoveUnused::class
+                            \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsRemoveUnused::class,
+                        ),
+                    ),
+                    \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsProcessFieldLabels::class => array(
+                        'depends' => array(
+                            \TYPO3\CMS\Backend\Form\FormDataProvider\TcaTypesShowitem::class,
                         ),
                     ),
                     \TYPO3\CMS\Backend\Form\FormDataProvider\TcaFlexFetch::class => array(
@@ -480,6 +485,7 @@ return array(
                             \TYPO3\CMS\Backend\Form\FormDataProvider\UserTsConfig::class,
                             \TYPO3\CMS\Backend\Form\FormDataProvider\PageTsConfigMerged::class,
                             \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsRemoveUnused::class,
+                            \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsProcessFieldLabels::class,
                         ),
                     ),
                     \TYPO3\CMS\Backend\Form\FormDataProvider\TcaFlexPrepare::class => array(
@@ -555,11 +561,16 @@ return array(
                 ),
                 'flexFormSegment' => array(
                     \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class => array(),
-                    \TYPO3\CMS\Backend\Form\FormDataProvider\TcaGroup::class => array(
+                    \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsProcessFieldLabels::class => array(
                         'depends' => array(
                             \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class,
                         ),
                     ),
+                    \TYPO3\CMS\Backend\Form\FormDataProvider\TcaGroup::class => array(
+                        'depends' => array(
+                            \TYPO3\CMS\Backend\Form\FormDataProvider\TcaColumnsProcessFieldLabels::class,
+                        ),
+                    ),
                     \TYPO3\CMS\Backend\Form\FormDataProvider\TcaRadioItems::class => array(
                         'depends' => array(
                             \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseRowDefaultValues::class,