diff --git a/src/View/Input/MultiCheckbox.php b/src/View/Input/MultiCheckbox.php new file mode 100644 index 00000000000..ecc6b8ff1a1 --- /dev/null +++ b/src/View/Input/MultiCheckbox.php @@ -0,0 +1,138 @@ +_templates = $templates; + } + +/** + * Render multi-checkbox widget. + * + * @param array $data + * @return string + */ + public function render($data) { + $data += [ + 'name' => '', + 'escape' => true, + 'options' => [], + 'disabled' => null, + 'val' => null, + ]; + $out= []; + foreach ($data['options'] as $key => $val) { + $checkbox = [ + 'value' => $key, + 'text' => $val, + ]; + if (is_array($val) && isset($val['text'], $val['value'])) { + $checkbox = $val; + } + $checkbox['name'] = $data['name']; + $checkbox['escape'] = $data['escape']; + + if ($this->_isSelected($key, $data['val'])) { + $checkbox['selected'] = true; + } + if ($this->_isDisabled($key, $data['disabled'])) { + $checkbox['disabled'] = true; + } + if (empty($checkbox['id'])) { + $checkbox['id'] = mb_strtolower(Inflector::slug($checkbox['name'] . $checkbox['value'], '-')); + } + + $out[] = $this->_renderInput($checkbox); + } + return implode('', $out); + } + +/** + * Render a single checkbox & wrapper. + * + * @return string + */ + protected function _renderInput($checkbox) { + $input = $this->_templates->format('checkbox', [ + 'name' => $checkbox['name'] . '[]', + 'value' => $checkbox['value'], + 'attrs' => $this->_templates->formatAttributes( + $checkbox, + ['name', 'value', 'text'] + ) + ]); + + $labelAttrs = [ + 'for' => $checkbox['id'], + 'escape' => $checkbox['escape'] + ]; + $label = $this->_templates->format('label', [ + 'text' => $checkbox['escape'] ? h($checkbox['text']) : $checkbox['text'], + 'input' => $input, + 'attrs' => $this->_templates->formatAttributes($labelAttrs) + ]); + + return $this->_templates->format('checkboxContainer', [ + 'label' => $label, + 'input' => $input + ]); + } + +/** + * Helper method for deciding what options are selected. + * + * @param string $key The key to test. + * @param array|string|null The selected values. + * @return boolean + */ + protected function _isSelected($key, $selected) { + if ($selected === null) { + return false; + } + $isArray = is_array($selected); + if (!$isArray) { + return (string)$key === (string)$selected; + } + $strict = !is_numeric($key); + return in_array((string)$key, $selected, $strict); + } + +/** + * Helper method for deciding what options are disabled. + * + * @param string $key The key to test. + * @param array|null The disabled values. + * @return boolean + */ + protected function _isDisabled($key, $disabled) { + if ($disabled === null) { + return false; + } + $strict = !is_numeric($key); + return in_array((string)$key, $disabled, $strict); + } + +} diff --git a/tests/TestCase/View/Input/MultiCheckboxTest.php b/tests/TestCase/View/Input/MultiCheckboxTest.php new file mode 100644 index 00000000000..000ad259800 --- /dev/null +++ b/tests/TestCase/View/Input/MultiCheckboxTest.php @@ -0,0 +1,115 @@ + '', + 'label' => '{{text}}', + 'checkboxContainer' => '
{{input}}{{label}}
', + ]; + $this->templates = new StringTemplate(); + $this->templates->add($templates); + } + +/** + * Test render simple option sets. + * + * @return void + */ + public function testRenderSimple() { + $input = new MultiCheckbox($this->templates); + $data = [ + 'name' => 'Tags[id]', + 'options' => [ + 1 => 'CakePHP', + 2 => 'Development', + ] + ]; + $result = $input->render($data); + $expected = [ + ['div' => ['class' => 'checkbox']], + ['input' => [ + 'type' => 'checkbox', + 'name' => 'Tags[id][]', + 'value' => 1, + 'id' => 'tags-id-1', + ]], + ['label' => ['for' => 'tags-id-1']], + 'CakePHP', + '/label', + '/div', + ['div' => ['class' => 'checkbox']], + ['input' => [ + 'type' => 'checkbox', + 'name' => 'Tags[id][]', + 'value' => 2, + 'id' => 'tags-id-2', + ]], + ['label' => ['for' => 'tags-id-2']], + 'Development', + '/label', + '/div', + ]; + $this->assertTags($result, $expected); + } + +/** + * Test render escpaing options. + * + * @return void + */ + public function testRenderEscaping() { + $this->markTestIncomplete(); + } + +/** + * Test render complex options. + * + * @return void + */ + public function testRenderComplex() { + $this->markTestIncomplete(); + } + +/** + * Test render selected checkboxes. + * + * @return void + */ + public function testRenderSelected() { + $this->markTestIncomplete(); + } + +/** + * Test render disabled checkboxes. + * + * @return void + */ + public function testRenderDisabled() { + $this->markTestIncomplete(); + } + +}