From 021d393ee0c3bbf748669487734f14562e84d959 Mon Sep 17 00:00:00 2001 From: Oliver Hader <oliver@typo3.org> Date: Fri, 8 Sep 2017 12:43:03 +0200 Subject: [PATCH] [BUGFIX] Fix multi-checkbox/radiobox labels for values containing dots 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> --- .../Classes/Service/TranslationService.php | 13 +++--- .../TranslateElementPropertyViewHelper.php | 40 +++++++++++++++++-- .../Frontend/Partials/MultiCheckbox.html | 2 +- .../Frontend/Partials/RadioButton.html | 2 +- .../Unit/Service/TranslationServiceTest.php | 24 +++++------ 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/typo3/sysext/form/Classes/Service/TranslationService.php b/typo3/sysext/form/Classes/Service/TranslationService.php index 989c297e3b13..79d36dc10079 100644 --- a/typo3/sysext/form/Classes/Service/TranslationService.php +++ b/typo3/sysext/form/Classes/Service/TranslationService.php @@ -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; } diff --git a/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php b/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php index 3e401d111ef6..e3544ed3b59f 100644 --- a/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php +++ b/typo3/sysext/form/Classes/ViewHelpers/TranslateElementPropertyViewHelper.php @@ -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 + ); + } } } diff --git a/typo3/sysext/form/Resources/Private/Frontend/Partials/MultiCheckbox.html b/typo3/sysext/form/Resources/Private/Frontend/Partials/MultiCheckbox.html index 1998a699c496..7f209e440129 100644 --- a/typo3/sysext/form/Resources/Private/Frontend/Partials/MultiCheckbox.html +++ b/typo3/sysext/form/Resources/Private/Frontend/Partials/MultiCheckbox.html @@ -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> diff --git a/typo3/sysext/form/Resources/Private/Frontend/Partials/RadioButton.html b/typo3/sysext/form/Resources/Private/Frontend/Partials/RadioButton.html index b707826cf2ee..f736e9193533 100644 --- a/typo3/sysext/form/Resources/Private/Frontend/Partials/RadioButton.html +++ b/typo3/sysext/form/Resources/Private/Frontend/Partials/RadioButton.html @@ -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> diff --git a/typo3/sysext/form/Tests/Unit/Service/TranslationServiceTest.php b/typo3/sysext/form/Tests/Unit/Service/TranslationServiceTest.php index d71a003983b1..76377e931e87 100644 --- a/typo3/sysext/form/Tests/Unit/Service/TranslationServiceTest.php +++ b/typo3/sysext/form/Tests/Unit/Service/TranslationServiceTest.php @@ -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)); } } -- GitLab