yiisoft / yii2

Yii 2: The Fast, Secure and Professional PHP Framework
http://www.yiiframework.com
BSD 3-Clause "New" or "Revised" License
14.24k stars 6.91k forks source link

`Html::activeListInput()` failed loading data to model attribute have array type #19446

Open WinterSilence opened 2 years ago

WinterSilence commented 2 years ago

What steps will reproduce the problem?

Model:

class Form extends \yii\base\Model
{
    public array $values = [];

    public function rules()
    {
       return [
        [['values'], 'safe']
      ];
    }
}

View:

use \yii\widgets\ActiveForm;
$form = ActiveForm::begin();
echo $form->field($model, 'values[]')->checkboxList([1 => 'foo', 2 => 'bar']);
echo \yii\widgets\Html::submitButton();
ActiveForm::end();

Controller:

class TestController extends \yii\web\Controller
{
   public function actionForm()
   {
       $model = new Form();
        if ($this->request->isPost && $model->load($this->request->post()) && $model->save()) {
            return $this->redirect(['index']);
        }

        return $this->render('form', ['model' => $model]);
   }
}

What is the expected result?

No errors on load form data into model when i don't check values

What do you get instead?

Error: can't set string to array property $values because https://github.com/yiisoft/yii2/blob/f72310c398759841a0f8b52e1aba7990086c0d9c/framework/helpers/BaseHtml.php#L1845

Additional info

Q A
Yii version 2.0.45
PHP version -
Operating system -
MarkoNV commented 1 year ago

Framework works exactly as documentation says and it allows developer to override default behavior if needed in cases like this. Documentation for BaseHtml::activeCheckboxList() and BaseHtml::activeRadioList() clearly says:

@param array $options options (name => config) for the checkbox list / radio button container tag. The following options are specially handled: ...

  • unselect: string, the value that should be submitted when none of the checkboxes / radio buttons is selected. You may set this option to be null to prevent default value submission. If this option is not set, an empty string will be submitted.

Per documentation: If Form::$values isn't intended to allow unselect, 'unselect' should be set to null and that works without issue as designed:

echo $form->field($model, 'values[]')->checkboxList([1 => 'foo', 2 => 'bar'], ['unselect' => null]);

Also, if Form::$values expect any other value for unselect, custom value can be set and that works without issue as designed:

echo $form->field($model, 'values[]')->checkboxList([1 => 'foo', 2 => 'bar'], ['unselect' => 0]);

IMHO, this isn't bug and should be closed.

Also, as both @rob006 and I stated in PR #19447 discussion, if Model::load() throws exception, issue is in concrete Model implementation, not in helper for printing forms. If invalid data is submitted (which doesn't need to be submitted exclusively via form printed using this helper), that should trigger validation error, not exception.