Browse Source

Merge pull request #13357 from advitum/ticket-13342

Fix for issue 13342 - RadioWidget and MultiCheckboxWidget now use passed "id"
Mark Story 6 years ago
parent
commit
8cd0b0bc54

+ 15 - 1
src/View/Helper/IdGeneratorTrait.php

@@ -59,7 +59,21 @@ trait IdGeneratorTrait
     protected function _id($name, $val)
     {
         $name = $this->_domId($name);
+        $suffix = $this->_idSuffix($val);
 
+        return trim($name . '-' . $suffix, '-');
+    }
+
+    /**
+     * Generate an ID suffix.
+     *
+     * Ensures that id's for a given set of fields are unique.
+     *
+     * @param string $val The ID attribute value.
+     * @return string Generated id suffix.
+     */
+    protected function _idSuffix($val)
+    {
         $idSuffix = mb_strtolower(str_replace(['/', '@', '<', '>', ' ', '"', '\''], '-', $val));
         $count = 1;
         $check = $idSuffix;
@@ -68,7 +82,7 @@ trait IdGeneratorTrait
         }
         $this->_idSuffixes[] = $check;
 
-        return trim($name . '-' . $check, '-');
+        return $check;
     }
 
     /**

+ 8 - 1
src/View/Widget/MultiCheckboxWidget.php

@@ -164,7 +164,14 @@ class MultiCheckboxWidget implements WidgetInterface
             $checkbox['checked'] = $this->_isSelected($checkbox['value'], $data['val']);
             $checkbox['disabled'] = $this->_isDisabled($checkbox['value'], $data['disabled']);
             if (empty($checkbox['id'])) {
-                $checkbox['id'] = $this->_id($checkbox['name'], $checkbox['value']);
+                if (isset($data['id'])) {
+                    $checkbox['id'] = $data['id'] . '-' . trim(
+                        $this->_idSuffix($checkbox['value']),
+                        '-'
+                    );
+                } else {
+                    $checkbox['id'] = $this->_id($checkbox['name'], $checkbox['value']);
+                }
             }
             $out[] = $this->_renderInput($checkbox + $data, $context);
         }

+ 8 - 1
src/View/Widget/RadioWidget.php

@@ -165,7 +165,14 @@ class RadioWidget implements WidgetInterface
         }
 
         if (empty($radio['id'])) {
-            $radio['id'] = $this->_id($radio['name'], $radio['value']);
+            if (isset($data['id'])) {
+                $radio['id'] = $data['id'] . '-' . trim(
+                    $this->_idSuffix($radio['value']),
+                    '-'
+                );
+            } else {
+                $radio['id'] = $this->_id($radio['name'], $radio['value']);
+            }
         }
         if (isset($data['val']) && is_bool($data['val'])) {
             $data['val'] = $data['val'] ? 1 : 0;

+ 66 - 0
tests/TestCase/View/Widget/MultiCheckboxWidgetTest.php

@@ -648,4 +648,70 @@ class MultiCheckboxWidgetTest extends TestCase
         ];
         $this->assertHtml($expected, $result);
     }
+
+    /**
+     * testRenderExplicitId method
+     *
+     * Test that the id passed is actually used
+     * Issue: https://github.com/cakephp/cakephp/issues/13342
+     *
+     * @return void
+     */
+    public function testRenderExplicitId()
+    {
+        $label = new LabelWidget($this->templates);
+        $input = new MultiCheckboxWidget($this->templates, $label);
+        $data = [
+            'name' => 'field',
+            'options' => ['value1', 'value2'],
+            'id' => 'alternative-id',
+            'idPrefix' => 'willBeIgnored',
+        ];
+        $result = $input->render($data, $this->context);
+        $expected = [
+            [
+                'div' => ['class' => 'checkbox'],
+                'input' => ['type' => 'checkbox', 'name' => 'field[]', 'value' => '0', 'id' => 'alternative-id-0'],
+                'label' => ['for' => 'alternative-id-0'],
+            ],
+            'value1',
+            '/label',
+            '/div',
+            [
+                'div' => ['class' => 'checkbox'],
+                'input' => ['type' => 'checkbox', 'name' => 'field[]', 'value' => '1', 'id' => 'alternative-id-1'],
+                'label' => ['for' => 'alternative-id-1'],
+            ],
+            'value2',
+            '/label',
+            '/div',
+        ];
+        $this->assertHtml($expected, $result);
+
+        $data = [
+            'name' => 'field',
+            'options' => ['value1', 'value2'],
+            'idPrefix' => 'formprefix',
+        ];
+        $result = $input->render($data, $this->context);
+        $expected = [
+            [
+                'div' => ['class' => 'checkbox'],
+                'input' => ['type' => 'checkbox', 'name' => 'field[]', 'value' => '0', 'id' => 'formprefix-field-0'],
+                'label' => ['for' => 'formprefix-field-0'],
+            ],
+            'value1',
+            '/label',
+            '/div',
+            [
+                'div' => ['class' => 'checkbox'],
+                'input' => ['type' => 'checkbox', 'name' => 'field[]', 'value' => '1', 'id' => 'formprefix-field-1'],
+                'label' => ['for' => 'formprefix-field-1'],
+            ],
+            'value2',
+            '/label',
+            '/div',
+        ];
+        $this->assertHtml($expected, $result);
+    }
 }

+ 58 - 0
tests/TestCase/View/Widget/RadioWidgetTest.php

@@ -820,4 +820,62 @@ class RadioWidgetTest extends TestCase
         ];
         $this->assertHtml($expected, $result);
     }
+
+    /**
+     * testRenderExplicitId method
+     *
+     * Test that the id passed is actually used
+     * Issue: https://github.com/cakephp/cakephp/issues/13342
+     *
+     * @return void
+     */
+    public function testRenderExplicitId()
+    {
+        $label = new NestingLabelWidget($this->templates);
+        $input = new RadioWidget($this->templates, $label);
+        $data = [
+            'name' => 'field',
+            'options' => ['value1', 'value2'],
+            'id' => 'alternative-id',
+            'idPrefix' => 'willBeIgnored',
+        ];
+        $result = $input->render($data, $this->context);
+        $expected = [
+            [
+                'label' => ['for' => 'alternative-id-0'],
+                'input' => ['type' => 'radio', 'name' => 'field', 'value' => '0', 'id' => 'alternative-id-0'],
+            ],
+            'value1',
+            '/label',
+            [
+                'label' => ['for' => 'alternative-id-1'],
+                'input' => ['type' => 'radio', 'name' => 'field', 'value' => '1', 'id' => 'alternative-id-1'],
+            ],
+            'value2',
+            '/label',
+        ];
+        $this->assertHtml($expected, $result);
+
+        $data = [
+            'name' => 'field',
+            'options' => ['value1', 'value2'],
+            'idPrefix' => 'formprefix',
+        ];
+        $result = $input->render($data, $this->context);
+        $expected = [
+            [
+                'label' => ['for' => 'formprefix-field-0'],
+                'input' => ['type' => 'radio', 'name' => 'field', 'value' => '0', 'id' => 'formprefix-field-0'],
+            ],
+            'value1',
+            '/label',
+            [
+                'label' => ['for' => 'formprefix-field-1'],
+                'input' => ['type' => 'radio', 'name' => 'field', 'value' => '1', 'id' => 'formprefix-field-1'],
+            ],
+            'value2',
+            '/label',
+        ];
+        $this->assertHtml($expected, $result);
+    }
 }