3 namespace Drupal\Core\Render\Element;
5 use Drupal\Core\Form\FormStateInterface;
8 * Provides a form element for a set of checkboxes.
11 * - #options: An associative array whose keys are the values returned for each
12 * checkbox, and whose values are the labels next to each checkbox. The
13 * #options array cannot have a 0 key, as it would not be possible to discern
14 * checked and unchecked states.
18 * $form['high_school']['tests_taken'] = array(
19 * '#type' => 'checkboxes',
20 * '#options' => array('SAT' => $this->t('SAT'), 'ACT' => $this->t('ACT')),
21 * '#title' => $this->t('What standardized tests did you take?'),
26 * @see \Drupal\Core\Render\Element\Radios
27 * @see \Drupal\Core\Render\Element\Checkbox
29 * @FormElement("checkboxes")
31 class Checkboxes extends FormElement {
33 use CompositeFormElementTrait;
38 public function getInfo() {
39 $class = get_class($this);
43 [$class, 'processCheckboxes'],
46 [$class, 'preRenderCompositeFormElement'],
48 '#theme_wrappers' => ['checkboxes'],
53 * Processes a checkboxes form element.
55 public static function processCheckboxes(&$element, FormStateInterface $form_state, &$complete_form) {
56 $value = is_array($element['#value']) ? $element['#value'] : [];
57 $element['#tree'] = TRUE;
58 if (count($element['#options']) > 0) {
59 if (!isset($element['#default_value']) || $element['#default_value'] == 0) {
60 $element['#default_value'] = [];
63 foreach ($element['#options'] as $key => $choice) {
64 // Integer 0 is not a valid #return_value, so use '0' instead.
65 // @see \Drupal\Core\Render\Element\Checkbox::valueCallback().
66 // @todo For Drupal 8, cast all integer keys to strings for consistency
67 // with \Drupal\Core\Render\Element\Radios::processRadios().
71 // Maintain order of options as defined in #options, in case the element
72 // defines custom option sub-elements, but does not define all option
76 $element += [$key => []];
78 '#type' => 'checkbox',
80 '#return_value' => $key,
81 '#default_value' => isset($value[$key]) ? $key : NULL,
82 '#attributes' => $element['#attributes'],
83 '#ajax' => isset($element['#ajax']) ? $element['#ajax'] : NULL,
84 // Errors should only be shown on the parent checkboxes element.
85 '#error_no_message' => TRUE,
96 public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
97 if ($input === FALSE) {
99 $element += ['#default_value' => []];
100 foreach ($element['#default_value'] as $key) {
105 elseif (is_array($input)) {
106 // Programmatic form submissions use NULL to indicate that a checkbox
107 // should be unchecked. We therefore remove all NULL elements from the
108 // array before constructing the return value, to simulate the behavior
109 // of web browsers (which do not send unchecked checkboxes to the server
110 // at all). This will not affect non-programmatic form submissions, since
111 // all values in \Drupal::request()->request are strings.
112 // @see \Drupal\Core\Form\FormBuilderInterface::submitForm()
113 foreach ($input as $key => $value) {
114 if (!isset($value)) {
118 return array_combine($input, $input);
126 * Determines which checkboxes were checked when a form is submitted.
128 * @param array $input
129 * An array returned by the FormAPI for a set of checkboxes.
132 * An array of keys that were checked.
134 public static function getCheckedCheckboxes(array $input) {
135 // Browsers do not include unchecked options in a form submission. The
136 // FormAPI tries to normalize this to keep checkboxes consistent with other
137 // form elements. Checkboxes show up as an array in the form of option_id =>
138 // option_id|0, where integer 0 is an unchecked option.
140 // @see \Drupal\Core\Render\Element\Checkboxes::valueCallback()
141 // @see https://www.w3.org/TR/html401/interact/forms.html#checkbox
142 $checked = array_filter($input, function($value) {
145 return array_keys($checked);
149 * Determines if all checkboxes in a set are unchecked.
151 * @param array $input
152 * An array returned by the FormAPI for a set of checkboxes.
155 * TRUE if all options are unchecked. FALSE otherwise.
157 public static function detectEmptyCheckboxes(array $input) {
158 return empty(static::getCheckedCheckboxes($input));