0

I am building something which uses a form element with '#type' => 'checkboxes'.

I want this to be reusable, so it should accept anything as option values that works as a PHP array key (integers and non-integer strings).

$form['checkboxes'] = [
  '#type' => 'checkboxes',
  '#options' => [
    0 => 'zero',
    '' => 'empty string',
    ' ' => 'space',
    'other' => 'Other',
  ],
];

However there seems to be a problem with values 0 (zero) and '' (empty string).

Even when the checkboxes for '' or 0 are checked, the values are gone in the $element['#value'] array, e.g. when checking with a custom '#element_validate' callback.

$element['#value'] === [
  # '' and 0 are gone, even if they were checked.
  ' ' => ' ',
  'other' => 'other',
];

Interestingly, the $_POST still contains the values, with an interesting twist, where space and empty string behave like array insertion via []. I suppose this is due to the way POST data is sent.

$_POST['checkboxes'] === [
  0 => '0',
  1 => '',
  2 => ' ',
  'other' => 'other',
];

I can imagine why all of this happens, but is there a workaround or solution?

EDIT: The previous version of the code snippet was misleading, sorry. I had mixed up $_POST and the original '#options' array.

10
  • Why would you put an empty string in the first place? Try putting zero without quotes 0 => 0,
    – No Sssweat
    Feb 22, 2019 at 1:31
  • Sorry, my code snippet was misleading. I fixed it.
    – donquixote
    Feb 22, 2019 at 9:22
  • "Why would you put an empty string in the first place?" - I want this component to be usable by others, and I assume that empty string would be a valid option value.
    – donquixote
    Feb 22, 2019 at 9:24
  • 1
    Ah, after Drupal gets its dirty mitts on it you mean. Yeah that makes sense. Have a look at api.drupal.org/api/drupal/includes%21form.inc/function/… and api.drupal.org/api/drupal/includes%21form.inc/function/…, I don't have time to look at the moment but the comments specifically talk about '0' and '' as return values for checkboxes, so you might be able to get a start point to debug in there
    – Clive
    Feb 22, 2019 at 11:37
  • 1
    You could always 'preprocess' your options by concatenating a prefix (e.g., '_') to it when creating the form elements and remove that prefix in the submit handler. Thus, a key like 0 would become '_0', '' becomes '_', ' ' becomes '_ ', and so on. Feb 25, 2019 at 12:51

1 Answer 1

0

I managed to prevent this problem by adding an '#element_validate' handler on the checkboxes element.

The code below is a simplified version of what I did, up to you to fine-tune.

$element['#element_validate'][] = '_MYMODULE_checkboxes_validate';

function _MYMODULE_checkboxes_validate(array &$element, array &$form_state) {

  // The form value already has the format $[$id] = $id, mostly.
  // However, if trim($id) === '', the array key will be an integer increment.
  $value = $element['#value'];

  // Make sure it has the expected format.
  if (!is_array($value) || [] === $value) {
    $ids = [];
  }
  else {
    // Get rid of integer keys for empty-ish string ids.
    $ids = array_combine($value, $value);
  }

  // Remove dangling * => 0 entries.
  form_set_value($element, $ids, $form_state);
}

Note: If you have the value_is module installed, empty-ish values will always be unset, thanks to _value_is_disabled_options_value_callback().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.