ZF-7006: setValue on Select fields does not correctly handle UUIDs which are ~16 digits long

Description

Because we need to synchronise offline with online DB´s, we are using a sort of UUIDs for our primary keys. The UUIDs are generated with MySQL´s UUID_SHORT() function. This function returns UUIDs which consist only of digits and have a length around 16 digits. Because these UUIDs are longer than the maximum allowed Integer length in PHP (11 digits), these UUID´s must be handled as strings. When handled as Integers all digits after digit 11 are cut off.

The problem is when using these UUID´s with Select form fields. When setting the default value with setValue a lot of options are marked selected=selected and not only the one which should. Therefore if existing data is loaded in the form for editing, the last option with selected=selected is selected and not the one which should be. When saving the form even if the user has not modified the data, the wrong option is saved. This is very very bad.

I guess this results because somewhere in the Zend Framework, values with digits are handled as Integer and not as string. Probably values with more than 11 digits should always be handled as string.

This is a very ugly bug because existing data is randomly modified when loaded for editing. The User does not even recognize this.

Comments

For everyone affected by this bug:

PHP's function in_array has a third parameter called 'strict' used to force the type checking of the needle and the haystack.

Just taking a look at the FormSelect class file you will see that it uses this function to check which option should be selected. Change the original function: protected function _build($value, $label, $selected, $disable) { if (is_bool($disable)) { $disable = array(); }

    $opt = '<option'
         . ' value="' . $this->view->escape($value) . '"'
         . ' label="' . $this->view->escape($label) . '"';

    // selected?
    if (in_array((string) $value, $selected)) {
        $opt .= ' selected="selected"';
    }

    // disabled?
    if (in_array($value, $disable)) {
        $opt .= ' disabled="disabled"';
    }

    $opt .= '>' . $this->view->escape($label) . "</option>";

    return $opt;
}

for this other:

protected function _build($value, $label, $selected, $disable) { if (is_bool($disable)) { $disable = array(); }

    $opt = '<option'
         . ' value="' . $this->view->escape($value) . '"'
         . ' label="' . $this->view->escape($label) . '"';

    // selected?
    if (in_array((string) $value, $selected, true)) {
        $opt .= ' selected="selected"';
    }

    // disabled?
    if (in_array($value, $disable)) {
        $opt .= ' disabled="disabled"';
    }

    $opt .= '>' . $this->view->escape($label) . "</option>";

    return $opt;
}

And all will go fine :)