[BUGFIX] Enable CheckboxViewHelper binding to ArrayObject and Null 84/21184/2
authorAlexander Schnitzler <alex.schnitzler@typovision.de>
Sat, 1 Jun 2013 09:56:21 +0000 (11:56 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Tue, 4 Jun 2013 19:00:14 +0000 (21:00 +0200)
Currently the checkbox view helper relies on a present
form object which is not necessary any longer since 6.1
as the new property mapper is active by default.

Therefore the viewhelper must be adjusted to be able to
be bound to ArrayObject objects or Null which throws an
exception till now.

Releases: 6.2, 6.1
Resolves: #48628
Change-Id: I35b70fb0a09ddd72da1c64ec5c7c5456e9af9471
Reviewed-on: https://review.typo3.org/21184
Tested-by: Adrian Dymorz
Reviewed-by: Wouter Wolters
Tested-by: Wouter Wolters
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
typo3/sysext/fluid/Classes/ViewHelpers/Form/CheckboxViewHelper.php
typo3/sysext/fluid/Tests/Unit/ViewHelpers/Form/CheckboxViewHelperTest.php

index b8508d4..025563b 100644 (file)
@@ -71,17 +71,29 @@ class CheckboxViewHelper extends \TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormF
         */
        public function render($checked = NULL) {
                $this->tag->addAttribute('type', 'checkbox');
+
                $nameAttribute = $this->getName();
                $valueAttribute = $this->getValue();
-               if ($checked === NULL && $this->isObjectAccessorMode()) {
-                       $propertyValue = $this->getPropertyValue();
-                       if (is_bool($propertyValue)) {
-                               $checked = $propertyValue === (boolean) $valueAttribute;
-                       } elseif (is_array($propertyValue)) {
-                               $checked = in_array($valueAttribute, $propertyValue);
-                               $nameAttribute .= '[]';
+               if ($this->isObjectAccessorMode()) {
+                       if ($this->hasMappingErrorOccured()) {
+                               $propertyValue = $this->getLastSubmittedFormData();
                        } else {
-                               throw new \TYPO3\CMS\Fluid\Core\ViewHelper\Exception('Checkbox viewhelpers can only be bound to properties of type boolean or array. Property "' . $this->arguments['property'] . '" is of type "' . (is_object($propertyValue) ? get_class($propertyValue) : gettype($propertyValue)) . '".', 1248261038);
+                               $propertyValue = $this->getPropertyValue();
+                       }
+
+                       if ($propertyValue instanceof \Traversable) {
+                               $propertyValue = iterator_to_array($propertyValue);
+                       }
+                       if (is_array($propertyValue)) {
+                               if ($checked === NULL) {
+                                       $checked = in_array($valueAttribute, $propertyValue);
+                               }
+                               $nameAttribute .= '[]';
+                       } elseif (($multiple = FALSE) === TRUE) {
+                               // @todo: implement correct as in Flow.Fluid
+                               $nameAttribute .= '[]';
+                       } elseif ($checked === NULL && $propertyValue !== NULL) {
+                               $checked = (boolean) $propertyValue === (boolean) $valueAttribute;
                        }
                }
                $this->registerFieldNameForFormTokenGeneration($nameAttribute);
index d23931e..31a95ba 100644 (file)
@@ -150,13 +150,40 @@ class CheckboxViewHelperTest extends \TYPO3\CMS\Fluid\Tests\Unit\ViewHelpers\For
 
        /**
         * @test
-        * @expectedException \TYPO3\CMS\Fluid\Core\ViewHelper\Exception
         */
-       public function bindingObjectsToACheckboxThatAreNotOfTypeBooleanOrArrayThrowsException() {
-               $mockTagBuilder = $this->getMock('TYPO3\\CMS\\Fluid\\Core\\ViewHelper\\TagBuilder', array('setTagName', 'addAttribute'));
+       public function renderCorrectlySetsCheckedAttributeIfCheckboxIsBoundToAPropertyOfTypeArrayObject() {
+               $mockTagBuilder = $this->getMock('TYPO3\CMS\Fluid\Core\ViewHelper\TagBuilder', array('setTagName', 'addAttribute'));
+               $mockTagBuilder->expects($this->at(1))->method('addAttribute')->with('type', 'checkbox');
+               $mockTagBuilder->expects($this->at(2))->method('addAttribute')->with('name', 'foo[]');
+               $mockTagBuilder->expects($this->at(3))->method('addAttribute')->with('value', 'bar');
+               $mockTagBuilder->expects($this->at(4))->method('addAttribute')->with('checked', 'checked');
+
+               $this->viewHelper->expects($this->any())->method('getName')->will($this->returnValue('foo'));
+               $this->viewHelper->expects($this->any())->method('getValue')->will($this->returnValue('bar'));
+               $this->viewHelper->expects($this->any())->method('isObjectAccessorMode')->will($this->returnValue(TRUE));
+               $this->viewHelper->expects($this->any())->method('getPropertyValue')->will($this->returnValue(new \ArrayObject(array('foo', 'bar', 'baz'))));
+               $this->viewHelper->injectTagBuilder($mockTagBuilder);
+
+               $this->viewHelper->initialize();
+               $this->viewHelper->render();
+       }
+
+       /**
+        * @test
+        */
+       public function renderSetsCheckedAttributeIfBoundPropertyIsNotNull() {
+               $mockTagBuilder = $this->getMock('TYPO3\CMS\Fluid\Core\ViewHelper\TagBuilder', array('setTagName', 'addAttribute'));
+               $mockTagBuilder->expects($this->at(1))->method('addAttribute')->with('type', 'checkbox');
+               $mockTagBuilder->expects($this->at(2))->method('addAttribute')->with('name', 'foo');
+               $mockTagBuilder->expects($this->at(3))->method('addAttribute')->with('value', 'bar');
+               $mockTagBuilder->expects($this->at(4))->method('addAttribute')->with('checked', 'checked');
+
+               $this->viewHelper->expects($this->any())->method('getName')->will($this->returnValue('foo'));
+               $this->viewHelper->expects($this->any())->method('getValue')->will($this->returnValue('bar'));
                $this->viewHelper->expects($this->any())->method('isObjectAccessorMode')->will($this->returnValue(TRUE));
                $this->viewHelper->expects($this->any())->method('getPropertyValue')->will($this->returnValue(new \stdClass()));
                $this->viewHelper->injectTagBuilder($mockTagBuilder);
+
                $this->viewHelper->initialize();
                $this->viewHelper->render();
        }