Search code examples
jsonsql-serverlaraveldynamic-arrayssurvey

How to store selected checkbox IDs to my database on Laravel 8


I have created a dynamic survey builder application, where the survey creator can choose what question type the question that will be made (either radio, checkbox, text and textarea). The storing of user's responses are saving correctly EXCEPT on my checkboxes. If the user selected 3 or 2 checkboxes then it will only save 1 to the database. Please help I am new to laravel. Thank you

This is my store function in controller

  public function surveystore(Questionnaire $questionnaire, Request $request){

  
            $data = request()->validate([
            'responses.*.answer_id' => 'required_if:responses.*.questiontype,radio,|required_if:responses.*.questiontype,checkbox',
            'responses.*.answer_text' => 'required_if:responses.*.questiontype,text,|required_if:responses.*.questiontype,textarea',
            'responses.*.question_id' => 'required',
            'survey.name' => 'required',    //present ang ilagay kung need na confidential
            'survey.email' => 'required',   //present ang ilagay kung need na confidential
                ]);

          
             $survey= $questionnaire->surveys()->create($data['survey']);
             $survey->responses()->createMany($data['responses']);

             return redirect()->back()->with('message', 'Thank You! :)');

             
        }

This is my route

Route::get('dsb/creator/surveys/{questionnaire}-{slug}', [dsbCreatorController::class, 'surveyshow'])->name('dsb/creator/surveyshow/{questionnaire}-{slug}');
Route::post('dsb/creator/surveys/{questionnaire}-{slug}', [dsbCreatorController::class, 'surveystore'])->name('dsb/creator/surveystore/{questionnaire}-{slug}');

This is my surveyshow.blade.php (the survey form that the users will take to answer)

<div class="container">
            
            @if(session()->has('message'))
                    <div class="alert alert-success">
                        {{ session()->get('message') }}
                    </div>
                @endif

            <div class="card mt-4">
                <div class="card-body">
                    <div class="header text-center ml-auto mr-auto">
                        <h3 class= "font-bold">Survey Title: {{ $questionnaire->title }}</h3>
                        <h4>Purpose: {{ $questionnaire->purpose }}</h4>
                    </div>
                </div>
            </div>


                <form action="/dsb/creator/surveys/{{ $questionnaire->id}}-{{ Str::slug($questionnaire->title) }}" method="post">
                    @csrf

                    @foreach ($questionnaire->questions as $key => $question)
                    <div class="card mt-4">
                        <div class="card-header"><strong>{{ $key + 1}}</strong> {{ $question->question }}</div>

                        @if($question->questiontype === 'radio')

                        <div class="card-body">
                            @error('responses.'. $key . '.answer_id')
                                <small class="text-danger">{{ $message }}</small>
                                
                            @enderror

                            <ul class="list-group">
                                @foreach($question->answers as $answer)
                                <label for="answer{{ $answer->id }}">
                                    <li class="list-group-item">
                                        <input type="radio" name="responses[{{ $key }}][answer_id]" id="answer{{ $answer->id }}" 
                                        {{ (old('responses.' . $key . '.answer_id')== $answer->id) ? 'checked' : ''}}
                                        class="mr-2" value="{{ $answer->id }}">
                                        {{ $answer->answer }}

                                        <input type="hidden" name="responses[{{ $key }}][question_id]" value="{{ $question->id }}">
                                        <input type="hidden" name="responses[{{ $key }}][questiontype]" value="{{ $question->questiontype }}">
                                        <input type="hidden" name="responses[{{ $key }}][required]" value="{{ $question->required }}">
                                    </li>
                                </label>
                                    @endforeach
                            </ul>

                        </div>

                            @elseif($question->questiontype === 'text')
                                    <div class="card-body">
                                        @error('responses.'. $key . '.answer_text')
                                         <small class="text-danger">{{ $message }}</small>
                                             @enderror
                                        <div class="input-field col s12">
                                            <input type="text" name="responses[{{ $key }}][answer_text]">
                                            <input type="hidden" name="responses[{{ $key }}][question_id]" value="{{ $question->id }}">
                                            <input type="hidden" name="responses[{{ $key }}][questiontype]" value="{{ $question->questiontype }}">
                                            <input type="hidden" name="responses[{{ $key }}][required]" value="{{ $question->required }}">
                                        <label for="responses[{{ $key }}][answer_text]">Provide answer</label>
                                        </div>
                                    </div>

                            @elseif($question->questiontype === 'textarea')
                              <div class="card-body">
                                @error('responses.'. $key . '.answer_text')
                                <small class="text-danger">{{ $message }}</small>
                                 @enderror
                                    <div class="input-field col s12">
                                        <textarea name="responses[{{ $key }}][answer_text]"></textarea>
                                        <input type="hidden" name="responses[{{ $key }}][question_id]" value="{{ $question->id }}">
                                        <input type="hidden" name="responses[{{ $key }}][questiontype]" value="{{ $question->questiontype }}">
                                        <input type="hidden" name="responses[{{ $key }}][required]" value="{{ $question->required }}">
                                       <label for="responses[{{ $key }}][answer_text]">Provide answer</label>
                                    </div>
                              </div>

                            @elseif($question->questiontype === 'checkbox')
                             <div class="card-body">
                                @error('responses.'. $key . '.answer_id')
                                <small class="text-danger">{{ $message }}</small>
                                 @enderror
                                     <ul class="list-group">
                                  @foreach($question->answers as $answer)
                                     <label for="answer{{ $answer->id }}">
                                        <li class="list-group-item">
                                        <input type="checkbox" name="responses[{{ $key }}][answer_id][]" id="answer{{ $answer->id }}" 
                                        {{ (old('responses.' . $key . '.answer_id')== $answer->id) ? 'checked' : ''}}
                                        class="mr-2" value="{{ $answer->id }}">
                                        {{ $answer->answer }}

                                        <input type="hidden" name="responses[{{ $key }}][question_id]" value="{{ $question->id }}">
                                        <input type="hidden" name="responses[{{ $key }}][questiontype]" value="{{ $question->questiontype }}">
                                        <input type="hidden" name="responses[{{ $key }}][required]" value="{{ $question->required }}">
                                    </li>
                                </label>
                                    @endforeach
                            </ul>

                        </div>

                            @endif        
                    </div>
                    
                @endforeach
                      
              <br><br>
                <div class="card">
                     <div class="card-header">Your Information:
                        <small id="info" class="form-text text-muted">(NOT REQUIRED)</small>
                    </div> <br>
                    
                     <div class="card-body">

                            <div class="form-group">
                                <label for="name">Name</label>
                                <input name="survey[name]" type="text" class="form-control" id="name" aria-describedby="nameHelp" placeholder="Enter Name">
                     
                              @error('name')
                                    <small class="text-danger">{{$message}}</small>
                                    @enderror
                            </div>  <br>

                              <div class="form-group">
                                <label for="email">Email</label>
                                <input name="survey[email]" type="text" class="form-control" id="email" aria-describedby="emailHelp" placeholder="Enter email">
                        
                                @error('email')
                                <small class="text-danger">{{$message}}</small>
                                @enderror
                            </div>

                                <div>
                                   <br>
                                   <br>
                                    <button type="submit" class="btn btn-primary">Complete survey</button>
                                </div>

                    
                     </div>
                    </form>
                </div>

This is my SurveyResponse Model's function

use HasFactory;
protected $guarded = [];

public function survey()
{
    return $this->belongsTo(Survey::class);
}
public function questionnaire()
{
    return $this->belongsTo(Questionnaire::class);
}
  }

Solution

  • array:4 [▼ 
    0 => array:2 [▼ "answer_id" => "89" "question_id" => "103" ] 
    1 => array:2 [▼ "answer_id" => array:2 [▼ 0 => "90" 1 => "91" ] "question_id" => "104" ]
    2 => array:2 [▼ "answer_text" => "answer to text" "question_id" => "105" ] 
    3 => array:2 [▼ "answer_text" => "answer to textarea" "question_id" => "106" ] ]
    

    in the second index answer_id is an array. createMany() method can't handle this properly.I think that causes the problem.You can change your code with a foreach loop for storing $data['responses'] and check if value is an array.If it is then iterate over again to save.For example;

    foreach ($data['responses'] as $response) {
        if (isset($response['answer_id']) && is_array($response['answer_id'])) {
            foreach ($response['answer_id'] as $value) {
                $survey->responses()->createOne(
                    [
                        "answer_id" => $value,
                        "question_id" => $response['question_id']
                    ]
                );
            }
        } else {
            $survey->responses()->createOne($response);
        }
    }