Browse Source

Fix empty string hiddenField values

While hiddenField is documented it can also be a string. We've had this
behavior (with tests) since 2.1 so we might as well keep it. Expand this
behavior to with ''.

Align both checkbox() and radio() to handle `hiddenField = ''`
consistently as them being different is clunky.

Fixes #16254
Mark Story 4 years ago
parent
commit
8285c18e9e
2 changed files with 55 additions and 6 deletions
  1. 7 6
      src/View/Helper/FormHelper.php
  2. 48 0
      tests/TestCase/View/Helper/FormHelperTest.php

+ 7 - 6
src/View/Helper/FormHelper.php

@@ -1480,8 +1480,8 @@ class FormHelper extends Helper
      *
      * - `value` - the value of the checkbox
      * - `checked` - boolean indicate that this checkbox is checked.
-     * - `hiddenField` - boolean to indicate if you want the results of checkbox() to include
-     *    a hidden input with a value of ''.
+     * - `hiddenField` - boolean|string. Set to false to disable a hidden input from
+     *    being generated. Passing a string will define the hidden input value.
      * - `disabled` - create a disabled input.
      * - `default` - Set the default value for the checkbox. This allows you to start checkboxes
      *    as checked, without having to check the POST data. A matching POST data value, will overwrite
@@ -1503,7 +1503,7 @@ class FormHelper extends Helper
         $options['value'] = $value;
 
         $output = '';
-        if ($options['hiddenField']) {
+        if ($options['hiddenField'] !== false && is_scalar($options['hiddenField'])) {
             $hiddenOptions = [
                 'name' => $options['name'],
                 'value' => $options['hiddenField'] !== true
@@ -1537,8 +1537,9 @@ class FormHelper extends Helper
      * - `label` - Either `false` to disable label around the widget or an array of attributes for
      *    the label tag. `selected` will be added to any classes e.g. `'class' => 'myclass'` where widget
      *    is checked
-     * - `hiddenField` - boolean to indicate if you want the results of radio() to include
-     *    a hidden input with a value of ''. This is useful for creating radio sets that are non-continuous.
+     * - `hiddenField` - boolean|string. Set to false to not include a hidden input with a value of ''. 
+     *    Can also be a string to set the value of the hidden input. This is useful for creating 
+     *    radio sets that are non-continuous.
      * - `disabled` - Set to `true` or `disabled` to disable all the radio buttons. Use an array of
      *   values to disable specific radio buttons.
      * - `empty` - Set to `true` to create an input with the value '' as the first option. When `true`
@@ -1562,7 +1563,7 @@ class FormHelper extends Helper
         $radio = $this->widget('radio', $attributes);
 
         $hidden = '';
-        if ($hiddenField) {
+        if ($hiddenField !== false && is_scalar($hiddenField)) {
             $hidden = $this->hidden($fieldName, [
                 'value' => $hiddenField === true ? '' : $hiddenField,
                 'form' => $attributes['form'] ?? null,

+ 48 - 0
tests/TestCase/View/Helper/FormHelperTest.php

@@ -4590,6 +4590,16 @@ class FormHelperTest extends TestCase
             '/label',
         ];
         $this->assertHtml($expected, $result);
+
+        $result = $this->Form->radio('title', ['option A'], ['hiddenField' => '']);
+        $expected = [
+            ['input' => ['type' => 'hidden', 'name' => 'title', 'value' => '']],
+            'label' => ['for' => 'title-0'],
+            ['input' => ['type' => 'radio', 'name' => 'title', 'value' => '0', 'id' => 'title-0']],
+            'option A',
+            '/label',
+        ];
+        $this->assertHtml($expected, $result);
     }
 
     /**
@@ -5106,6 +5116,28 @@ class FormHelperTest extends TestCase
             '/div',
         ];
         $this->assertHtml($expected, $result);
+
+        $result = $this->Form->control('User.get_spam', [
+            'type' => 'checkbox',
+            'value' => '0',
+            'hiddenField' => '',
+        ]);
+        $expected = [
+            'div' => ['class' => 'input checkbox'],
+            'label' => ['for' => 'user-get-spam'],
+            ['input' => [
+                'type' => 'hidden', 'name' => 'User[get_spam]',
+                'value' => '',
+            ]],
+            ['input' => [
+                'type' => 'checkbox', 'name' => 'User[get_spam]',
+                'value' => '0', 'id' => 'user-get-spam',
+            ]],
+            'Get Spam',
+            '/label',
+            '/div',
+        ];
+        $this->assertHtml($expected, $result);
     }
 
     /**
@@ -5808,6 +5840,22 @@ class FormHelperTest extends TestCase
 
         $result = $this->Form->checkbox('UserForm.something', [
             'value' => 'Y',
+            'hiddenField' => '',
+        ]);
+        $expected = [
+            ['input' => [
+                'type' => 'hidden', 'name' => 'UserForm[something]',
+                'value' => '',
+            ]],
+            ['input' => [
+                'type' => 'checkbox', 'name' => 'UserForm[something]',
+                'value' => 'Y',
+            ]],
+        ];
+        $this->assertHtml($expected, $result);
+
+        $result = $this->Form->checkbox('UserForm.something', [
+            'value' => 'Y',
             'hiddenField' => 'N',
         ]);
         $expected = [