トップページ
Laravel学習サイトLaravelやるばい

目次

ユーザーがクイズの回答をする

今回はユーザーがクイズに回答できるようにします。

クイズに回答すると正解・不正解の表示をさせます。


web.phpの修正

welcome.blade.phpを表示するweb.phpの記述は現在下記です。

Route::get('/', function () {
    return view('welcome');
});

welcome.blade.phpに変数を渡したいのでQuizController.phpにshowアクションを作成してそれで表示する為にweb.phpのコードを下記に変更します。

Route::middleware('auth')->group(function () {
    Route::controller(QuizController::class)->group(function() {
        Route::get('/quiz/create', 'create')->name('quiz.create');

        Route::post('/quiz/store', 'store')->name('quiz.store');

        Route::get('/quiz/admin', 'admin')->name('quiz.admin');

        Route::delete('/quiz/{question}/delete', 'delete')->name('quiz.delete');

        Route::get('/quiz/{question}/edit', 'edit')->name('quiz.edit');

        Route::put('/quiz/{question}/update', 'update')->name('quiz.update');


        //ここから追加
        Route::get('/', 'index')->name('welcome');
        
        Route::get('/quiz/{question}/show', 'show')->name('quiz.show');
        //ここまで追加


    });
});

showアクションもwelcome.blade.phpに必要なので記述しています。

QuizController.phpにindexアクションの記述をします。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Question;

class QuizController extends Controller
{
    public function create()
    {
        return view('quiz.create');
    }

    public function store(Request $request)
    {
        $question_table = new Question();

        $question_table->question = $request->question;

        $question_table->choices = $request->choices;

        $question_table->correct_choice = $request->correct_choice;

        $question_table->save();

        return back()->with('message', 'クイズを作成しました');
    }

    public function admin()
    {
        $quizs = Question::all();

        return view('quiz.admin', compact('quizs'));
    }

    public function delete(Question $question)
    {
        $question->delete();

        return back()->with('message', 'クイズを削除しました');
    }

    public function edit(Question $question)
    {
        return view('quiz.edit', compact('question'));
    }

    public function update(Request $request, Question $question)
    {
        $question->question = $request->question;

        $question->choices = $request->choices;

        $question->correct_choice = $request->correct_choice;

        $question->save();
        
        return back()->with('message', 'クイズを更新しました');
    }


    // ここから追加

    public function index()
    {
        $question = Question::first();

        return view('welcome', compact('question'));
    }

    public function show(Question $question)
    {
        return view('quiz.show', compact('question'));
    }
    // ここまで追加


}

「Question::first()」はquestionsテーブルの最初のレコードのデータを取得するという意味です。

welcome.blade.phpのコードを下記にします。

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Fonts -->
        <link rel="preconnect" href="https://fonts.bunny.net">
        <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet" />

        <!-- Styles -->
       
    </head>
    <body class="antialiased">
        <div class="relative sm:flex sm:justify-center sm:items-center min-h-screen bg-dots-darker bg-center bg-gray-100 dark:bg-dots-lighter dark:bg-gray-900 selection:bg-red-500 selection:text-white">
            @if (Route::has('login'))
                <div class="sm:fixed sm:top-0 sm:right-0 p-6 text-right z-10">
                    @auth
                        <a href="{{ url('/dashboard') }}" class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Dashboard</a>
                    @else
                        <a href="{{ route('login') }}" class="font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Log in</a>

                        @if (Route::has('register'))
                            <a href="{{ route('register') }}" class="ml-4 font-semibold text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-white focus:outline focus:outline-2 focus:rounded-sm focus:outline-red-500">Register</a>
                        @endif
                    @endauth
                </div>
            @endif
            <div class="max-w-7xl mx-auto p-6 lg:p-8">
                <h2 class="font-bold">3択クイズ</h2>
                <a class="answer" href="{{ route('quiz.show', ['question' => $question->id]) }}">クイズに答える</a>       //この行を修正
                @auth
                    @if (auth()->user()->role_type_id == 1)
                        <a class="manage" href="{{ route('quiz.admin') }}">管理人用</a>
                    @endif
                @endauth
            </div>
        </div>
    </body>
</html>

それではクイズのページに入ることができるようにします。


クイズのページ

web.phpとQuizController.phpの記述はしたのでshow.blade.phpの記述をします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>問題</title>
</head>
<body>
    <div class="container">
        <form action="{{ route('quiz.answer', ['question' => $question->id]) }}" method="post">
            @csrf
            <h2>問題 : {{ $question->question }}</h2>
            @foreach($question->choices as $index => $choice)
                <div>
                    <input type="radio" name="choice" value="{{ $index + 1 }}" required>
                    {{ $choice }}
                </div>
            @endforeach

            <input type="hidden" name="question_id" value="{{ $question->id }}">
            <button type="submit">回答する</button>
        </form>
    </div>
</body>
</html>

<style>
    .container{
        width: 70%;
        margin-left:auto;
        margin-right:auto;
        padding-top: 50px;
    }
    .input{
        width: 60%;
        display: inline-block;
        margin-bottom: 20px;
    }
    button{
        margin-top: 20px;
    }
</style>


「@foreach ($question->choices as $index => $choice)」の記述が初めて登場しました。

「$index =>」を記述すると「$choice」に対するインデックス番号を付属することができます。

最初の値は0です。

下記の表示になるはずです。

20241231_155402_quiz13.jpg

次は回答のページを実装します。


解答のページ

web.phpに下記の記述をします。

Route::middleware('auth')->group(function () {
    Route::controller(QuizController::class)->group(function() {
        Route::get('/quiz/create', 'create')->name('quiz.create');

        Route::post('/quiz/store', 'store')->name('quiz.store');

        Route::get('/quiz/admin', 'admin')->name('quiz.admin');

        Route::delete('/quiz/{question}/delete', 'delete')->name('quiz.delete');

        Route::get('/quiz/{question}/edit', 'edit')->name('quiz.edit');

        Route::put('/quiz/{question}/update', 'update')->name('quiz.update');

        Route::get('/', 'index')->name('welcome');
        
        Route::get('/quiz/{question}/show', 'show')->name('quiz.show');

        Route::post('/quiz/{question}/answer', 'answer')->name('quiz.answer');       //この行を追加
    });
});

QuizController.phpに下記の記述をします。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Question;

class QuizController extends Controller
{
    public function create()
    {
        return view('quiz.create');
    }

    public function store(Request $request)
    {
        $question_table = new Question();

        $question_table->question = $request->question;

        $question_table->choices = $request->choices;

        $question_table->correct_choice = $request->correct_choice;

        $question_table->save();

        return back()->with('message', 'クイズを作成しました');
    }

    public function admin()
    {
        $quizs = Question::all();

        return view('quiz.admin', compact('quizs'));
    }

    public function delete(Question $question)
    {
        $question->delete();

        return back()->with('message', 'クイズを削除しました');
    }

    public function edit(Question $question)
    {
        return view('quiz.edit', compact('question'));
    }

    public function update(Request $request, Question $question)
    {
        $question->question = $request->question;

        $question->choices = $request->choices;

        $question->correct_choice = $request->correct_choice;

        $question->save();
        
        return back()->with('message', 'クイズを更新しました');
    }

    public function index()
    {
        $question = Question::first();

        return view('welcome', compact('question'));
    }

    public function show(Question $question)
    {
        return view('quiz.show', compact('question'));
    }


    // ここから追加
    public function answer(Question $question, Request $request)
    {
        $user_answer = $request->input('choice');

        $correct_choice_index = $question->correct_choice;

        $is_correct = false;

        if ($user_answer == $correct_choice_index) {
            $is_correct = true;
        }

        return view('quiz.answer', compact('question', 'user_answer', 'correct_choice_index', 'is_correct'));
    }
    // ここまで追加

}

「$request->input('choice')」は初めて登場したので解説します。

クイズのページに下記の記述がありましたが回答のページで「{{ $choice }}」を使って正解の判定をしないといけません。

<form action="{{ route('quiz.answer', ['question' => $question->id]) }}" method="post">
    @csrf
    <h2>問題 : {{ $question->question }}</h2>
    @foreach($question->choices as $index => $choice)
        <div>
            <input type="radio" name="choice" value="{{ $index + 1 }}" required>
            {{ $choice }}           //←これ
        </div>
    @endforeach

    <input type="hidden" name="question_id" value="{{ $question->id }}">
    <button type="submit">回答する</button>
</form>

クイズのページの「{{ $choice }}」の値を解答のページで受け取る為の記述が「$request->input('choice')」です、$choiceの$は取ります。
if文の記述は正解か不正解かを判定する為の記述です。

次はビューです。

answer.blade.phpに下記の記述をします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>回答</title>
</head>
<body>
    <div class="container">
        <h2>問題{{ $question->id }}の結果</h2>
        <p>あなたは選択肢{{ $user_answer }}を選びました。</p>
        @if ($is_correct)
            <p class="answer">正解です!</p>
        @else
            <p><span class="answer">不正解です。</span>正解は{{ $question->choices[$question->correct_choice - 1]}}です。</p>
        @endif
    </div>
</body>
</html>

<style>
    .container{
        width: 70%;
        margin-left:auto;
        margin-right:auto;
    }
    .input{
        width: 60%;
        display: inline-block;
        margin-bottom: 20px;
    }
    .answer{
        font-weight: bold;
    }
</style>

 下記は不正解の場合ですがこういう感じで正解・不正解が表示されます。

20241231_165437_quiz14.jpg

今のままではクイズを1問答えたら終わりなので次の問題に回答できるようにします。

QuizController.phpのanswerアクションに記述します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Question;

class QuizController extends Controller
{
    public function create()
    {
        return view('quiz.create');
    }

    public function store(Request $request)
    {
        $question_table = new Question();

        $question_table->question = $request->question;

        $question_table->choices = $request->choices;

        $question_table->correct_choice = $request->correct_choice;

        $question_table->save();

        return back()->with('message', 'クイズを作成しました');
    }

    public function admin()
    {
        $quizs = Question::all();

        return view('quiz.admin', compact('quizs'));
    }

    public function delete(Question $question)
    {
        $question->delete();

        return back()->with('message', 'クイズを削除しました');
    }

    public function edit(Question $question)
    {
        return view('quiz.edit', compact('question'));
    }

    public function update(Request $request, Question $question)
    {
        $question->question = $request->question;

        $question->choices = $request->choices;

        $question->correct_choice = $request->correct_choice;

        $question->save();
        
        return back()->with('message', 'クイズを更新しました');
    }

    public function index()
    {
        $question = Question::first();

        return view('welcome', compact('question'));
    }

    public function show(Question $question)
    {
        return view('quiz.show', compact('question'));
    }

    public function answer(Question $question, Request $request)
    {
        $user_answer = $request->input('choice');

        $correct_choice_index = $question->correct_choice;

        $is_correct = false;

        if ($user_answer == $correct_choice_index) {
            $is_correct = true;
        }

        $next_question = Question::where('id', '>', $question->id)->first();       //この行を追加

        return view('quiz.answer', compact('question', 'user_answer', 'correct_choice_index', 'is_correct', 'next_question'));      //この行を修正
    }
}

「Question::where('id', '>', $question->id)->first()」で最初の問題のidの次のidに該当するレコードをquestionsテーブルから探しています。

answer.blade.phpのコードを下記にします。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>回答</title>
</head>
<body>
    <div class="container">
        <h2>問題{{ $question->id }}の結果</h2>
        <p>あなたは選択肢{{ $user_answer }}を選びました。</p>
        @if ($is_correct)
            <p class="answer">正解です!</p>
        @else
            <p><span class="answer">不正解です。</span>正解は{{ $question->choices[$question->correct_choice - 1]}}です。</p>
        @endif


        //ここから追加
        @if ($next_question)
            <a href="{{ route('quiz.show', ['question' => $next_question->id]) }}">次の問題へ。</a>
        @else
            <p>クイズが終了しました。</p>
            <a href="/">トップページに戻る。</a>
        @endif
        //ここまで追加

        
    </div>
</body>
</html>

<style>
    .container{
        width: 70%;
        margin-left:auto;
        margin-right:auto;
    }
    .input{
        width: 60%;
        display: inline-block;
        margin-bottom: 20px;
    }
    .answer{
        font-weight: bold;
    }
</style>

これでquestionsテーブルに次の問題のレコードがある場合は次の問題のリンクが表示されてない場合はクイズが終了になります。

今回はここまでです。

戻る