[BUGFIX] Fix property mapping of checkbox arrays 85/21685/4
authorHelmut Hummel <helmut.hummel@typo3.org>
Thu, 27 Jun 2013 18:09:37 +0000 (20:09 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Fri, 28 Jun 2013 07:47:54 +0000 (09:47 +0200)
If multiple checkboxes are rendered but none of it is
selected, an exception is thrown as the value of the hidden field,
that is submitted is a string.

This must be the case because we need to be able to clear out
selected checkboxes and cannot craft a hidden field that will
be translated to a GET/POST arument which is an empty array.

Because of that the ArrayConverter must be able to convert
empty strings to an empty array, just like the "old"
property mapper did.

Change-Id: I115831014caca4868d1f421eb968e01178e1169b
Resolves: #47832
Releases: 6.2, 6.1, 6.0
Reviewed-on: https://review.typo3.org/21685
Reviewed-by: Wouter Wolters
Tested-by: Wouter Wolters
Reviewed-by: Georg Ringer
Tested-by: Georg Ringer
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
typo3/sysext/extbase/Classes/Property/TypeConverter/ArrayConverter.php
typo3/sysext/extbase/Tests/Unit/Property/TypeConverter/ArrayConverterTest.php

index 9f5c777..f2652d0 100644 (file)
@@ -30,7 +30,7 @@ class ArrayConverter extends \TYPO3\CMS\Extbase\Property\TypeConverter\AbstractT
        /**
         * @var array<string>
         */
-       protected $sourceTypes = array('array');
+       protected $sourceTypes = array('array', 'string');
 
        /**
         * @var string
@@ -43,9 +43,21 @@ class ArrayConverter extends \TYPO3\CMS\Extbase\Property\TypeConverter\AbstractT
        protected $priority = 1;
 
        /**
-        * Actually convert from $source to $targetType, in fact a noop here.
+        * We can only convert empty strings to array or array to array.
         *
-        * @param array $source
+        * @param mixed $source
+        * @param string $targetType
+        * @return boolean
+        */
+       public function canConvertFrom($source, $targetType) {
+               return is_string($source) && $source === '' || is_array($source);
+       }
+
+       /**
+        * Convert from $source to $targetType, a noop if the source is an array.
+        * If it is an empty string it will be converted to an empty array.
+        *
+        * @param string|array $source
         * @param string $targetType
         * @param array $convertedChildProperties
         * @param \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration
@@ -53,6 +65,12 @@ class ArrayConverter extends \TYPO3\CMS\Extbase\Property\TypeConverter\AbstractT
         * @api
         */
        public function convertFrom($source, $targetType, array $convertedChildProperties = array(), \TYPO3\CMS\Extbase\Property\PropertyMappingConfigurationInterface $configuration = NULL) {
+               if (is_string($source)) {
+                       if ($source === '') {
+                               $source = array();
+                       }
+               }
+
                return $source;
        }
 }
index 57d5127..91eebdd 100644 (file)
@@ -39,7 +39,7 @@ class ArrayConverterTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
         * @test
         */
        public function checkMetadata() {
-               $this->assertEquals(array('array'), $this->converter->getSupportedSourceTypes(), 'Source types do not match');
+               $this->assertEquals(array('array', 'string'), $this->converter->getSupportedSourceTypes(), 'Source types do not match');
                $this->assertEquals('array', $this->converter->getSupportedTargetType(), 'Target type does not match');
                $this->assertEquals(1, $this->converter->getPriority(), 'Priority does not match');
        }
@@ -51,5 +51,47 @@ class ArrayConverterTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $sourceArray = array('Foo' => 'Bar', 'Baz');
                $this->assertEquals($sourceArray, $this->converter->convertFrom($sourceArray, 'array'));
        }
+
+       /**
+        * @return array
+        */
+       public function stringToArrayDataProvider() {
+               return array(
+                       'Empty string to empty array' => array('', array()),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider stringToArrayDataProvider
+        *
+        * @param string $source
+        * @param array $expectedResult
+        */
+       public function canConvertFromEmptyString($source, $expectedResult) {
+               $this->assertEquals($expectedResult, $this->converter->convertFrom($source, 'array'));
+       }
+
+       /**
+        * @return array
+        */
+       public function canConvertFromDataProvider() {
+               return array(
+                       'Can convert empty string' => array('', TRUE),
+                       'Can not convert not empty string' => array('foo', FALSE),
+                       'Can convert array' => array(array('foo'), TRUE),
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider canConvertFromDataProvider
+        *
+        * @param mixed $source
+        * @param boolean $expectedResult
+        */
+       public function canConvertFromReturnsCorrectBooleans($source, $expectedResult) {
+               $this->assertSame($expectedResult, $this->converter->canConvertFrom($source, 'array'));
+       }
 }
 ?>
\ No newline at end of file