Laravel表单提交未选选项时如何将题目得分设为0?
Laravel在线测验系统结果存储问题
问题概述
开发Laravel在线测验系统,数据库包含users、questions、results三张表:
questions表存储题目名称、4个选项及正确选项results表以user_id和question_id为外键,通过obtained_marks字段记录用户每题得分
需求:若用户未选择某道题的任何选项,需将该题的obtained_marks设为0。
尝试在存储results数据时使用!isset($options[$i])判断未选情况,但逻辑未生效,且触发**Undefined offset for options[$i]**错误。
原代码
Result Controller 原代码
public function store(Request $request){ DB::beginTransaction(); $questions=Question::all(); if(empty($request->option)){ foreach($questions as $question){ $result = DB::table('results')->insert([ 'user_id' => auth()->user()->id, 'question_id' => $question->id, 'obtained_marks' => 0 ]); } if ($result){ DB::commit(); return redirect()->route('login'); } } $options= array_values($request->option); for($i=0; $i<count($questions); $i++){ $result = DB::table('results')->insert([ 'user_id' => auth()->user()->id, 'question_id' => $questions[$i]->id, 'obtained_marks' => (!isset($options[$i]) || $options[$i] != $questions[$i]->right_answer) ? 0:1 ]); } if ($result){ DB::commit(); return redirect()->route('login'); } }
视图原代码
<div class="container"> <div class="row justify-content-center"> <div class="col-8 mx-auto"> <br> <div class="card"> <div class="card-header"> <h1>Welcome to Quiz</h1> </div> <form class="form" action="{{ route('store') }}" method="POST"> @csrf <div class="card-body"> @foreach ($questions as $question) <p>{{ $loop->iteration }}. {{ $question->question }}</p> <br> <div class="row justify-content-center"> <div class="col-lg-6"> <input type="radio" name="option[{{ $question->id }}]" id="option1" value="a" /> <label for="option1"><button class="options" disabled>a. {{ $question->a }}</button></label> </div> <div class="col-lg-6"> <input type="radio" name="option[{{ $question->id }}]" id="option2" value="b" /> <label for="option2"><button class="options" disabled>b. {{ $question->b }}</button></label> </div> <br> <br> <div class="col-lg-6"> <input type="radio" name="option[{{ $question->id }}]" id="option3" value="c" /> <label for="option3"><button class="options" disabled>c. {{ $question->c }}</button></label> </div> <div class="col-lg-6"> <input type="radio" name="option[{{ $question->id }}]" id="option4" value="d" /> <label for="option4"><button class="options" disabled>d. {{ $question->d }}</button></label> </div> </div> <hr> @endforeach </div> <div class="card-footer"> <button type="submit" class="btn btn-primary flex-item">Submit</button> <button type="reset" class="btn btn-primary flex-item">Reset</button> <br> </div> </form> </div> </div> </div> </div> @endsection
错误原因
- 视图中单选框的
name属性为option[{{ $question->id }}],提交后$request->option是以题目ID为键的数组,仅包含用户选中的题目答案,未选中的题目不会出现在该数组中 - 使用
array_values($request->option)会将数组键重置为连续数字,但题目总数和用户选中的题目数量可能不一致,循环遍历所有题目时,$options[$i]会超出数组长度,触发Undefined offset错误 - 开头的
empty($request->option)判断仅处理完全未选任何题目的场景,无法覆盖部分题目未选的情况
修复方案
直接遍历所有题目,通过题目ID精准匹配用户的答案,无需依赖数组索引,同时统一处理全未选和部分未选的场景:
修复后的Result Controller代码
public function store(Request $request){ DB::beginTransaction(); $questions = Question::all(); // 若用户未选任何题目,默认赋值为空数组 $userAnswers = $request->option ?? []; foreach($questions as $question){ // 判断用户是否选中当前题目,且答案是否正确 $isCorrect = isset($userAnswers[$question->id]) && $userAnswers[$question->id] === $question->right_answer; $obtainedMarks = $isCorrect ? 1 : 0; DB::table('results')->insert([ 'user_id' => auth()->user()->id, 'question_id' => $question->id, 'obtained_marks' => $obtainedMarks ]); } DB::commit(); return redirect()->route('login'); }
修复说明
- 移除冗余的全未选判断逻辑,用
$userAnswers = $request->option ?? []统一处理所有情况 - 遍历每个题目时,通过
$question->id直接访问用户的答案,彻底避免数组索引不匹配的问题 - 逻辑更简洁清晰:用户未选中题目或答案错误时,
obtained_marks设为0;答案正确时设为1
内容的提问来源于stack exchange,提问作者Umar Naeem
相关产品推荐
相关产品推荐

