Now that user can take quizzes we need to save results in the DB which we will do in this tutorial.
For this we will need two Eloquent Models:
-
Test
where we will save information about user, which test (another word for "quiz" but it's broader) he took, how much time it took him. -
TestAnswer
where we will store the information about which answers user chose during the quiz.
php artisan make:model Test -m
database/migrations/xxxx_create_tests_table.php:
return new class extends Migration{ public function up(): void { Schema::create('tests', function (Blueprint $table) { $table->id(); $table->integer('result')->nullable(); $table->string('ip_address')->nullable(); $table->integer('time_spent')->nullable(); $table->foreignId('user_id')->nullable()->constrained(); $table->foreignId('quiz_id')->nullable()->constrained(); $table->timestamps(); $table->softDeletes(); }); } // ...};
app/Models/Test.php:
class Test extends Model{ use HasFactory; use SoftDeletes; protected $fillable = [ 'user_id', 'quiz_id', 'result', 'ip_address', 'time_spent', ]; public function user(): BelongsTo { return $this->belongsTo(User::class); } public function quiz(): BelongsTo { return $this->belongsTo(Quiz::class); } public function questions(): BelongsToMany { return $this->belongsToMany(Question::class, 'test_answers', 'test_id', 'question_id'); }}
database/migrations/xxxx_create_test_answers_table.php:
return new class extends Migration{ public function up(): void { Schema::create('test_answers', function (Blueprint $table) { $table->id(); $table->boolean('correct')->default(0)->nullable(); $table->foreignId('user_id')->nullable()->constrained(); $table->foreignId('test_id')->nullable()->constrained(); $table->foreignId('question_id')->nullable()->constrained(); $table->foreignId('option_id')->nullable()->references('id')->on('question_options'); $table->timestamps(); $table->softDeletes(); }); } // ...};
app/Models/TestAnswer.php:
class TestAnswer extends Model{ use HasFactory; use SoftDeletes; protected $fillable = [ 'user_id', 'test_id', 'question_id', 'option_id', 'correct', ]; public function user(): BelongsTo { return $this->belongsTo(User::class); } public function test(): BelongsTo { return $this->belongsTo(Test::class); } public function question(): BelongsTo { return $this->belongsTo(Question::class); } public function option(): BelongsTo { return $this->belongsTo(QuestionOption::class); }}
Now after submitting quiz we can save test results.
In the submit
method first we set a $result
to 0. We will increase it if users answer will be correct. And then we first create a new test.
app/Livewire/Front/Quizzes/Show.php:
class Show extends Component{ // ... public function submit() { $result = 0; $test = Test::create([ 'user_id' => auth()->id(), 'quiz_id' => $this->quiz->id, 'result' => 0, 'ip_address' => request()->ip(), 'time_spent' => now()->timestamp - $this->startTimeSeconds ]); } // ...}
Then we need to go through every answered question. In this foreach first we set $status
to 0 which means answer isn't correct. Then we need to find that question option and if it is correct we $status
to 1 (or true) and increase $result
. And create a new TestAnswer.
app/Livewire/front/quizzes/Show.php:
class Show extends Component{ // ... public function submit(): Redirector { $result = 0; $test = Test::create([ 'user_id' => auth()->id(), 'quiz_id' => $this->quiz->id, 'result' => 0, 'ip_address' => request()->ip(), 'time_spent' => now()->timestamp - $this->startTimeSeconds ]); foreach ($this->questionsAnswers as $key => $option) { $status = 0; if (! empty($option) && QuestionOption::find($option)->correct) { $status = 1; $result++; } TestAnswer::create([ 'user_id' => auth()->id(), 'test_id' => $test->id, 'question_id' => $this->questions[$key]->id, 'option_id' => $option ?? null, 'correct' => $status, ]); } } // ..}
After creating Test with the Answers all that is left to update test with the result and redirect. For now we will redirect to homepage.
app/Livewire/Front/Quizzes/Show.php:
class Show extends Component{ // ... public function submit(): Redirector|RedirectResponse { $result = 0; $test = Test::create([ 'user_id' => auth()->id(), 'quiz_id' => $this->quiz->id, 'result' => 0, 'ip_address' => request()->ip(), 'time_spent' => now()->timestamp - $this->startTimeSeconds ]); foreach ($this->questionsAnswers as $key => $option) { $status = 0; if (! empty($option) && QuestionOption::find($option)->correct) { $status = 1; $result++; } TestAnswer::create([ 'user_id' => auth()->id(), 'test_id' => $test->id, 'question_id' => $this->questions[$key]->id, 'option_id' => $option ?? null, 'correct' => $status, ]); } $test->update([ 'result' => $result, ]); return to_route('home'); } // ...}
No comments yet…