[BUGFIX] Fix multi-checkbox/radiobox labels for values containing dots 07/54007/7
authorOliver Hader <oliver@typo3.org>
Fri, 8 Sep 2017 10:43:03 +0000 (12:43 +0200)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Sat, 11 Nov 2017 15:57:29 +0000 (16:57 +0100)
If checkbox/radiobox values contain dots, these are falsely evaluated as
array lookup paths. Fix this by passing in separate path segments instead
which may contain dots.

Resolves: #82210
Releases: master, 8.7
Change-Id: Ib3d0d1abbeb4fdf84da427f6bea0d597ba9aade6
Reviewed-on: https://review.typo3.org/54007
Reviewed-by: Daniel Lorenz <daniel.lorenz@extco.de>
Tested-by: Daniel Lorenz <daniel.lorenz@extco.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
typo3/sysext/form/Classes/Service/TranslationService.php
typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php
typo3/sysext/form/Resources/Private/Frontend/Partials/MultiCheckbox.html
typo3/sysext/form/Resources/Private/Frontend/Partials/RadioButton.html
typo3/sysext/form/Tests/Unit/Service/TranslationServiceTest.php

index 989c297..79d36dc 100644 (file)
@@ -272,7 +272,7 @@ class TranslationService implements SingletonInterface
 
     /**
      * @param RootRenderableInterface $element
-     * @param string $property
+     * @param array $propertyParts
      * @param FormRuntime $formRuntime
      * @return string|array
      * @throws \InvalidArgumentException
@@ -280,14 +280,15 @@ class TranslationService implements SingletonInterface
      */
     public function translateFormElementValue(
         RootRenderableInterface $element,
-        string $property,
+        array $propertyParts,
         FormRuntime $formRuntime
     ) {
-        if (empty($property)) {
-            throw new \InvalidArgumentException('The argument "property" is empty', 1476216007);
+        if (empty($propertyParts)) {
+            throw new \InvalidArgumentException('The argument "propertyParts" is empty', 1476216007);
         }
 
         $propertyType = 'properties';
+        $property = implode('.', $propertyParts);
         $renderingOptions = $element->getRenderingOptions();
 
         if ($property === 'label') {
@@ -295,14 +296,14 @@ class TranslationService implements SingletonInterface
         } else {
             if ($element instanceof FormElementInterface) {
                 try {
-                    $defaultValue = ArrayUtility::getValueByPath($element->getProperties(), $property, '.');
+                    $defaultValue = ArrayUtility::getValueByPath($element->getProperties(), $propertyParts, '.');
                 } catch (\RuntimeException $exception) {
                     $defaultValue = null;
                 }
             } else {
                 $propertyType = 'renderingOptions';
                 try {
-                    $defaultValue = ArrayUtility::getValueByPath($renderingOptions, $property, '.');
+                    $defaultValue = ArrayUtility::getValueByPath($renderingOptions, $propertyParts, '.');
                 } catch (\RuntimeException $exception) {
                     $defaultValue = null;
                 }
index 3e401d1..e3544ed 100644 (file)
@@ -20,6 +20,7 @@ use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
 use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
 use TYPO3\CMS\Form\Service\TranslationService;
 use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
+use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
 
 /**
@@ -41,8 +42,8 @@ class TranslateElementPropertyViewHelper extends AbstractViewHelper
     {
         parent::initializeArguments();
         $this->registerArgument('element', RootRenderableInterface::class, 'Form Element to translate', true);
-        $this->registerArgument('property', 'string', 'Property to translate', false);
-        $this->registerArgument('renderingOptionProperty', 'string', 'Property to translate', false);
+        $this->registerArgument('property', 'mixed', 'Property to translate', false);
+        $this->registerArgument('renderingOptionProperty', 'mixed', 'Property to translate', false);
     }
 
     /**
@@ -56,6 +57,8 @@ class TranslateElementPropertyViewHelper extends AbstractViewHelper
      */
     public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
     {
+        static::assertArgumentTypes($arguments);
+
         $element = $arguments['element'];
 
         $property = null;
@@ -65,11 +68,42 @@ class TranslateElementPropertyViewHelper extends AbstractViewHelper
             $property = $arguments['renderingOptionProperty'];
         }
 
+        if (empty($property)) {
+            $propertyParts = [];
+        } elseif (is_array($property)) {
+            $propertyParts = $property;
+        } else {
+            $propertyParts = [$property];
+        }
+
         /** @var FormRuntime $formRuntime */
         $formRuntime =  $renderingContext
             ->getViewHelperVariableContainer()
             ->get(RenderRenderableViewHelper::class, 'formRuntime');
 
-        return TranslationService::getInstance()->translateFormElementValue($element, $property, $formRuntime);
+        return TranslationService::getInstance()->translateFormElementValue($element, $propertyParts, $formRuntime);
+    }
+
+    /**
+     * @param array $arguments
+     */
+    protected static function assertArgumentTypes(array $arguments)
+    {
+        foreach (['property', 'renderingOptionProperty'] as $argumentName) {
+            if (
+                !isset($arguments[$argumentName])
+                || is_string($arguments[$argumentName])
+                || is_array($arguments[$argumentName])
+            ) {
+                continue;
+            }
+            throw new Exception(
+                sprintf(
+                    'Arguments "%s" either must be string or array',
+                    $argumentName
+                ),
+                1504871830
+            );
+        }
     }
 }
index 1998a69..7f209e4 100644 (file)
@@ -13,7 +13,7 @@
                                                        errorClass="{element.properties.elementErrorClassAttribute}"
                                                        additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                                                />
-                                               <span>{formvh:translateElementProperty(element: element, property: 'options.{value}')}</span>
+                                               <span>{formvh:translateElementProperty(element: element, property: '{0: \'options\', 1: value}')}</span>
                                        </label>
                                </div>
                        </f:for>
index b707826..f736e91 100644 (file)
@@ -15,7 +15,7 @@
                                                                        errorClass="{element.properties.elementErrorClassAttribute}"
                                                                        additionalAttributes="{formvh:translateElementProperty(element: element, property: 'fluidAdditionalAttributes')}"
                                                                />
-                                                               <span>{formvh:translateElementProperty(element: element, property: 'options.{value}')}</span>
+                                                               <span>{formvh:translateElementProperty(element: element, property: '{0: \'options\', 1: value}')}</span>
                                                        </label>
                                                </div>
                                        </f:for>
index d71a003..76377e9 100644 (file)
@@ -340,7 +340,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 
     /**
@@ -384,7 +384,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 
     /**
@@ -428,7 +428,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 
     /**
@@ -472,7 +472,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 
     /**
@@ -516,7 +516,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 
     /**
@@ -563,7 +563,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'placeholder', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['placeholder'], $mockFormRuntime));
     }
 
     /**
@@ -610,7 +610,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'placeholder', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['placeholder'], $mockFormRuntime));
     }
 
     /**
@@ -658,7 +658,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'nextButtonLabel', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['nextButtonLabel'], $mockFormRuntime));
     }
 
     /**
@@ -711,7 +711,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'options', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['options'], $mockFormRuntime));
     }
 
     /**
@@ -764,7 +764,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'options', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['options'], $mockFormRuntime));
     }
 
     /**
@@ -873,7 +873,7 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 
     /**
@@ -955,6 +955,6 @@ class TranslationServiceTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestC
         $mockFormRuntime->expects($this->any())->method('getIdentifier')->willReturn($formRuntimeIdentifier);
         $mockFormRuntime->expects($this->any())->method('getRenderingOptions')->willReturn($formRuntimeRenderingOptions);
 
-        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, 'label', $mockFormRuntime));
+        $this->assertEquals($expected, $this->mockTranslationService->_call('translateFormElementValue', $mockFormElement, ['label'], $mockFormRuntime));
     }
 }