Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Checkboxes fixes and tests #1268

Merged
merged 7 commits into from

2 participants

@elinw

This fixes a few issues in the checkboxes field and adds detailed tests.
1. Formerly the field was not checking for stored data when rendering, so it was always using the information from the field definition. Going to the field definition is now conditioned on there not being an existing value.
2. Formerly selecting more than one item to be checked (preset) was not working because the array of checked values was not being created correctly.
Checkboxes continues to have the limitation that it cannot distinguish between a field that is deliberately saved as empty and one that has never been saved, so if the checked element is used it will always render with the checked items when the form is reopened. This is inherent to the structure of the checkboxes field type so developers should be aware of that and use the checked attribute with caution or consider using a "none of the above" option to force a value to be saved.

@ianmacl ianmacl merged commit 89942f3 into joomla:staging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
12 libraries/joomla/form/fields/checkboxes.php
@@ -51,6 +51,7 @@ protected function getInput()
// Initialize some field attributes.
$class = $this->element['class'] ? ' class="checkboxes ' . (string) $this->element['class'] . '"' : ' class="checkboxes"';
+ $checkedOptions = explode(',', (string) $this->element['checked']);
// Start the checkbox field output.
$html[] = '<fieldset id="' . $this->id . '"' . $class . '>';
@@ -62,9 +63,16 @@ protected function getInput()
$html[] = '<ul>';
foreach ($options as $i => $option)
{
-
// Initialize some option attributes.
- $checked = (in_array((string) $option->value, (array) $this->value) ? ' checked="checked"' : '');
+ if (!isset($this->value) || empty($this->value))
+ {
+ $checked = (in_array((string) $option->value, (array) $checkedOptions) ? ' checked="checked"' : '');
+ }
+ else
+ {
+ $value = !is_array($this->value) ? explode(',', $this->value) : $this->value;
+ $checked = (in_array((string) $option->value, $value) ? ' checked="checked"' : '');
+ }
$class = !empty($option->class) ? ' class="' . $option->class . '"' : '';
$disabled = !empty($option->disable) ? ' disabled="disabled"' : '';
View
319 tests/suites/unit/joomla/form/fields/JFormFieldCheckboxesTest.php
@@ -24,28 +24,323 @@ class JFormFieldCheckboxesTest extends TestCase
protected function setUp()
{
require_once JPATH_PLATFORM.'/joomla/form/fields/checkboxes.php';
- include_once dirname(__DIR__).'/inspectors.php';
}
/**
- * Test the getInput method.
+ * Test the getInput method with no value and no checked attribute.
*
- * @since 11.3
+ * @since 12.2
+ */
+ public function testGetInputNoValueNoChecked()
+ {
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
+
+ // Test with no value, no checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with no value and no checked values did not produce the right html'
+ );
+ }
+
+ /**
+ * Test the getInput method with one value selected and no checked attribute.
+ *
+ * @since 12.2
+ */
+ public function testGetInputValueNoChecked()
+ {
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
+
+ // Test with one value checked, no checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'value', 'red');
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red" checked="checked"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with one value did not produce the right html'
+ );
+ }
+
+ /**
+ * Test the getInput method with one value that is an array and no checked attribute.
+ *
+ * @since 12.2
+ */
+ public function testGetInputValueArrayNoChecked()
+ {
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
+
+ // Test with one value checked, no checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ $valuearray = array ('red');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'value', $valuearray);
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red" checked="checked"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with one value did not produce the right html'
+ );
+ }
+
+ /**
+ * Test the getInput method with no value and one value in checked.
+ *
+ * @since 12.2
+ */
+ public function testGetInputNoValueOneChecked()
+ {
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
+
+ // Test with nothing checked, one value in checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes" checked="blue">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue" checked="checked"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with no values and one value in the checked element did not produce the right html'
+ );
+ }
+
+ /**
+ * Test the getInput method with no value and two values in the checked element.
+ *
+ * @since 12.2
+ */
+ public function testGetInputNoValueTwoChecked()
+ {
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
+
+ // Test with nothing checked, two values in checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes" checked="red,blue">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+ TestReflection::setValue($formFieldCheckboxes, 'value', '""');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with no values and two items in the checked element did not produce the right html'
+ );
+ }
+
+ /**
+ * Test the getInput method with one value and a different checked value.
+ *
+ * @since 12.2
+ */
+ public function testGetInputValueChecked()
+ {
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
+
+ // Test with one item checked, a different value in checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes" checked="blue">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'value', 'red');
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red" checked="checked"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with one value and a different value in the checked element did not produce the right html'
+ );
+ }
+
+ /**
+ * Test the getInput method with multiple values, no checked.
+ *
+ * @since 12.2
*/
- public function testGetInput()
+ public function testGetInputValuesNoChecked()
{
- $form = new JFormInspector('form1');
+ $formFieldCheckboxes = $this->getMock('JFormFieldCheckboxes', array('getOptions'));
+
+ $option1 = new JObject;
+ $option1->set('value','red');
+ $option1->set('text','red');
+
+ $option2 = new JObject;
+ $option2->set('value','blue');
+ $option2->set('text','blue');
+
+ $optionsReturn = array($option1,$option2);
+ $formFieldCheckboxes->expects($this->any())
+ ->method('getOptions')
+ ->will($this->returnValue($optionsReturn));
- $this->assertThat(
- $form->load('<form><field name="checkboxes" type="checkboxes" /></form>'),
- $this->isTrue(),
- 'Line:'.__LINE__.' XML string should load successfully.'
+ // Test with two values checked, no checked element
+ $element = simplexml_load_string(
+ '<field name="color" type="checkboxes">
+ <option value="red">red</option>
+ <option value="blue">blue</option>
+ </field>');
+ TestReflection::setValue($formFieldCheckboxes, 'element', $element);
+ TestReflection::setValue($formFieldCheckboxes, 'id', 'myTestId');
+ TestReflection::setValue($formFieldCheckboxes, 'value', 'yellow,green');
+ TestReflection::setValue($formFieldCheckboxes, 'name', 'myTestName');
+
+ $this->assertEquals(
+ '<fieldset id="myTestId" class="checkboxes"><ul><li><input type="checkbox" id="myTestId0" name="myTestName" value="red"/><label for="myTestId0">red</label></li><li><input type="checkbox" id="myTestId1" name="myTestName" value="blue"/><label for="myTestId1">blue</label></li></ul></fieldset>',
+ TestReflection::invoke($formFieldCheckboxes, 'getInput'),
+ 'The field with two values did not produce the right html'
);
+ }
+
+ /**
+ * Test the getOptions method.
+ *
+ * @since 12.2
+ */
+ public function testGetOptions()
+ {
+ $formFieldCheckboxes = new JFormFieldCheckboxes;
+
+ $option1 = new JObject;
+ $option1->set('value','yellow');
+ $option1->set('text','yellow');
+ $option1->set('disable',false);
+ $option1->set('class','');
+ $option1->set('onclick','');
- $field = new JFormFieldCheckboxes($form);
+ $option2 = new JObject;
+ $option2->set('value','green');
+ $option2->set('text','green');
+ $option2->set('disable',false);
+ $option2->set('class','');
+ $option2->set('onclick','');
- $this->markTestIncomplete();
+ $optionsExpected = array($option1,$option2);
- // TODO: Should check all the attributes have come in properly.
+ // Test with two values checked, no checked element
+ TestReflection::setValue($formFieldCheckboxes, 'element', simplexml_load_string(
+ '<field name="color" type="checkboxes">
+ <option value="yellow">yellow</option>
+ <option value="green">green</option>
+ </field>'));
+
+ $this->assertEquals(
+ $optionsExpected,
+ TestReflection::invoke($formFieldCheckboxes, 'getOptions'),
+ 'The field with two values did not produce the right options'
+ );
}
}
Something went wrong with that request. Please try again.