yii2: ActiveForm dropDownList does not set the selected option properly if the underlying model's attribute is of boolean type

What steps will reproduce the problem?

We have a model

class MyModel extends Model
{
    public ?bool $value = false;
}

and in some view, we render an an ActiveForm

<div>
    <?php $form = ActiveForm::begin([
        'action' => '/some/path',
        'method' => 'GET'
     ]) ?>

    <?php $form->field($model, 'value')->textInput()->label(
        'text')->dropDownList([true => 'Yes', false => 'No'], ['prompt' => 'Please select']) ?>
</div>

What is the expected result?

I expect the rendered dropDownList to have a selection of 'Yes' when $value is true and 'No' when $value is false.

What do you get instead?

The dropDownList always shows the prompt instead.

Additional info

Q A
Yii version 2.0.45
PHP version 8.1.2
Operating system Debian

The problem is to be found in https://github.com/yiisoft/yii2/blob/2874e070f3ad88c727b1335ba4f4515855bf5f64/framework/helpers/BaseHtml.php#L1916-L1918 and the fact that arrays with boolean keys are indexed with 0 and 1 in php. When getting to this point

gettype($key) // integer
$key // 0
gettype($selection) // boolean
$selection // false

and

!strcmp($key, $selection)

does not give back that they are equal.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 22 (22 by maintainers)

Commits related to this issue

Most upvoted comments

@WinterSilence Thank you for the suggestion, but, you see, these getter and setter functions do not solve the problem in the renderSelectOptions function.

The setting of the value works perfectly fine (although your code for doing so is shorter than what I wrote above when there is only one boolean variable in the model). It is when the value is read inside of renderSelectOptions and the boolean false is compared to the integer 0 inside of strcmp that the comparison fails. Have you looked at the function in a debugger?

And will my pull request #19331 be considered as a fix? Currently, it is not clear to me whether this issue has been recognized/accepted as a bug.

['No', 'Yes'] converts to [['value' => '0', 'text' => 'No'], ['value' => '1', 'text' => 'Yes']], prepend prompt: [['value' => '', 'text' => 'Please select'], ['value' => '0', 'text' => 'No'], ['value' => '1', 'text' => 'Yes']]

(string)false is '' i.e. prompt value

An array keys can be int or string. Your boolean keys converted to strings.