Skip to content
Permalink
Browse files

Handle nested options in multi-checkbox widget

This makes converting from a multiple select box into
a multiple-checkbox widget simple as it works out of the box. This also
makes the behavior match the documentation. While this feature was
documented, it did not have any tests in 2.x and thus wasn't preserved
in the 3.x rewrite.

Refs #8385
  • Loading branch information...
markstory committed Mar 4, 2016
1 parent b2a62ae commit 709b54e9c9b4abdcd5c2379b452127a918d5accb
Showing with 140 additions and 3 deletions.
  1. +20 −3 src/View/Widget/MultiCheckboxWidget.php
  2. +120 −0 tests/TestCase/View/Widget/MultiCheckboxWidgetTest.php
@@ -50,6 +50,8 @@ class MultiCheckboxWidget implements WidgetInterface
* - `checkboxWrapper` Renders the containing div/element for
* a checkbox and its label. Accepts the `input`, and `label`
* variables.
* - `fieldset` Renders the fieldset for grouped inputs.
* - `legend` Renders the legend element for grouped inputs.
*
* @param \Cake\View\StringTemplate $templates Templates list.
* @param \Cake\View\Widget\LabelWidget $label Label widget instance.
@@ -113,10 +115,26 @@ public function render(array $data, ContextInterface $context)
'idPrefix' => null,
'templateVars' => []
];
$out = [];
$this->_idPrefix = $data['idPrefix'];
$this->_clearIds();
return implode('', $this->_renderInputs($data, $context));
}
protected function _renderInputs($data, $context)
{
$out = [];
foreach ($data['options'] as $key => $val) {
// Grouped inputs in a fieldset.
if (is_string($key) && is_array($val) && !isset($val['text'], $val['value'])) {
$inputs = $this->_renderInputs(['options' => $val] + $data, $context);
$legend = $this->_templates->format('legend', ['text' => $key]);
$out[] = $this->_templates->format('fieldset', [
'content' => $legend . implode('', $inputs)
]);
continue;
}
// Standard inputs.
$checkbox = [
'value' => $key,
'text' => $val,
@@ -142,10 +160,9 @@ public function render(array $data, ContextInterface $context)
if (empty($checkbox['id'])) {
$checkbox['id'] = $this->_id($checkbox['name'], $checkbox['value']);
}
$out[] = $this->_renderInput($checkbox, $context);
}
return implode('', $out);
return $out;
}
/**
@@ -37,6 +37,8 @@ public function setUp()
'checkbox' => '<input type="checkbox" name="{{name}}" value="{{value}}"{{attrs}}>',
'label' => '<label{{attrs}}>{{text}}</label>',
'checkboxWrapper' => '<div class="checkbox">{{input}}{{label}}</div>',
'fieldset' => '<fieldset{{attrs}}>{{content}}</fieldset>',
'legend' => '<legend>{{text}}</legend>',
];
$this->templates = new StringTemplate($templates);
$this->context = $this->getMock('Cake\View\Form\ContextInterface');
@@ -366,4 +368,122 @@ public function testRenderTemplateVars()
];
$this->assertHtml($expected, $result);
}
/**
* Test render with groupings.
*
* @return void
*/
public function testRenderGrouped()
{
$label = new LabelWidget($this->templates);
$input = new MultiCheckboxWidget($this->templates, $label);
$data = [
'name' => 'Tags[id]',
'options' => [
'Group 1' => [
1 => 'CakePHP',
],
'Group 2' => [
2 => 'Development',
]
]
];
$result = $input->render($data, $this->context);
$expected = [
'<fieldset',
'<legend', 'Group 1', '/legend',
['div' => ['class' => 'checkbox']],
['input' => [
'type' => 'checkbox',
'name' => 'Tags[id][]',
'value' => 1,
'id' => 'tags-id-1',
]],
['label' => ['for' => 'tags-id-1']],
'CakePHP',
'/label',
'/div',
'/fieldset',
'<fieldset',
'<legend', 'Group 2', '/legend',
['div' => ['class' => 'checkbox']],
['input' => [
'type' => 'checkbox',
'name' => 'Tags[id][]',
'value' => 2,
'id' => 'tags-id-2',
]],
['label' => ['for' => 'tags-id-2']],
'Development',
'/label',
'/div',
'/fieldset',
];
$this->assertHtml($expected, $result);
}
/**
* Test render with partial groupings.
*
* @return void
*/
public function testRenderPartialGrouped()
{
$label = new LabelWidget($this->templates);
$input = new MultiCheckboxWidget($this->templates, $label);
$data = [
'name' => 'Tags[id]',
'options' => [
1 => 'PHP',
'Group 1' => [
2 => 'CakePHP',
],
3 => 'Development',
]
];
$result = $input->render($data, $this->context);
$expected = [
['div' => ['class' => 'checkbox']],
['input' => [
'type' => 'checkbox',
'name' => 'Tags[id][]',
'value' => 1,
'id' => 'tags-id-1',
]],
['label' => ['for' => 'tags-id-1']],
'PHP',
'/label',
'/div',
'<fieldset',
'<legend', 'Group 1', '/legend',
['div' => ['class' => 'checkbox']],
['input' => [
'type' => 'checkbox',
'name' => 'Tags[id][]',
'value' => 2,
'id' => 'tags-id-2',
]],
['label' => ['for' => 'tags-id-2']],
'CakePHP',
'/label',
'/div',
'/fieldset',
['div' => ['class' => 'checkbox']],
['input' => [
'type' => 'checkbox',
'name' => 'Tags[id][]',
'value' => 3,
'id' => 'tags-id-3',
]],
['label' => ['for' => 'tags-id-3']],
'Development',
'/label',
'/div',
];
$this->assertHtml($expected, $result);
}
}

0 comments on commit 709b54e

Please sign in to comment.
You can’t perform that action at this time.