phpyii2radio-buttonactive-form

How to save values of multiple radios in yii2 activeForm?


I have a survey app with many questions. Each question has options that are presented in form of radiolist. I am using the ActiveForm and RadioList in for loop in order to get all the questions and options from the Database. Everything is ok with printing the questions and options but

When I try to save the answers to the database, it saves only the last option.

In my save action I tried to put a foreach loop in order to save each answer, but it didn't work for me.

I tried to var_dump the $model->save and $request->post('Questions') there is all the selected options, not only the last one.

Model: here is only the rules:

public function rules(){
  return[
    [['id','question_id',  'option_id'], 'required']
  ];

}

View:

<?php $form = ActiveForm::begin([
    'id' => 'my-form-id',
    'action' => ['answers/save'],
]
); 

?> 

<?php $questions = Questions::find()->orderBy('id ASC')->all(); ?>

  <?php for ($i=0; $i<count($questions); $i++): ?>    
     <?= Html::encode("{$questions[$i]->title}") ?>
  <?php $options = Options::find()->where (['question_id'=>$questions[$i]->id])->orderBy('id ASC')->all();
  $options = ArrayHelper::map($options,'id', 'title');
  ?>
  <label class="container" >
    <?= $form->field($model, 'option_title')->radioList(
        $options, 
        ['name'=>'Questions['.$questions[$i]->id.']', 
        'separator' => '<br>',
        ])->label(false) ?>        
  </label>

<?php endfor; ?>

<?= Html::submitButton('Save', ['class' => 'btn btn-primary']) ?>

<?php ActiveForm::end(); ?>

Controller:

public function actionSave(){        
  $model = new Answers();
  $request = \Yii::$app->request;
  foreach($request->post('Questions') as $key=>$value) {
    $model->load($request->post());
    $model->option_id = $value;
    $model->question_id = $key;
    $model->save();
  }
}

Sorry guys if it is obvious question but I really do not understand how to do it. Googling also didn't helped. If you have any ideas please share


Solution

  • You need to move the $model = new Answers(); inside the loop as you need to save all the checkboxes by looping on the post array you should create a new object every time and then it will save all of them. Just change your code to the below

    public function actionSave(){
      $request = \Yii::$app->request;
      foreach($request->post('Questions') as $key=>$value) {
        $model = new Answers();
        $model->load($request->post());
        $model->option_id = $value;
        $model->question_id = $key;
        $model->save();
      }
    }
    

    Also you should use transaction block when working with related or multiple records like in this case you should either save all of them or none in case of any error or exception, currently it isnt the case. If the exception or error occurs on the 4th checkbox you still have the first 3 checkbox values saved. Try wrapping the code like below

    public function actionSave(){
      $request = \Yii::$app->request;
    
      //start transaction
      $transaction=Yii::$app->db->beginTransaction();
    
      try{
    
        foreach ($request->post('Questions') as $key => $value) {
            $model = new Answers();
            $model->load($request->post());
            $model->option_id = $value;
            $model->question_id = $key;
            $model->save();
        }        
    
        //commit the transaction to save the records
        $transaction->commit();
    
      }catch(\Exception $e){
          //rollback the transaction so none of the checkboxes are saved 
          $transaction->rollBack();
          //do your stuff intimate the user by adding the message to a flash and redirecting 
      }
    }