複数の値を一度に同じテーブルに入れる【Laravel】
複数の値を一度に同じテーブルに入れる【Laravel】
アンケートなどを作成するとき、一つの質問に対して、答えを複数用意したい。 そんな時のためのメモ。
環境:Laravel 8.50.0
まずはQuestionモデルとテーブル、Answerモデルとテーブルを作成。
Questionモデル
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Question extends Model
{
use HasFactory;
protected $guarded = [];
public function answers()
{
return $this->hasMany(Answer::class);
}
}
questionsテーブル
public function up() { Schema::create('questions', function (Blueprint $table) { $table->id(); $table->string('question'); $table->timestamps(); }); }
Answer モデル
<?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Answer extends Model { use HasFactory; protected $guarded = []; public function question() { return $this->belongsTo(Question::class); } }
answersテーブル
public function up() { Schema::create('answers', function (Blueprint $table) { $table->id(); $table->foreignId('question_id')->constrained()->cascadeOnDelete(); $table->string('answer'); $table->timestamps(); }); }
web.php
Route::get('/questionnaires/{questionnaire}/question/create', [QuestionController::class, 'create'])->name('question.create'); Route::post('/questionnaires/{questionnaire}/questions', [QuestionController::class, 'store'])->name('question.store'); Route::get('/questionnaires/{questionnaire}', [QuestionnaireController::class, 'show'])->name('questionnaire.show');
question/create.blade
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">Create New Question</div> <div class="card-body"> <form action="{{ route('question.store', $questionnaire->id) }}" method="post"> @csrf <div class="form-group"> <label for="question">Question</label> <input name="question[question]" type="text" class="form-control" value="{{ old('question.question') }}" id="question" aria-describedby="questionHelp" placeholder="Enter Question"> <small id="questionHelp" class="form-text text-muted">Ask simple and to-the-point questions for best results.</small> @error('question.question') <small class="text-danger">{{ $message }}</small> @enderror </div> <div class="form-group"> <fieldset> <legend>Choices</legend> <small id="choicesHelp" class="form-text text-muted">Give choices that give you the most insight into your question.</small> <div> <div class="form-group"> <label for="answer1">Choice 1</label> <input name="answers[][answer]" type="text" value="{{ old('answers.0.answer') }}" class="form-control" id="answer1" aria-describedby="choicesHelp" placeholder="Enter Choice 1"> @error('answers.0.answer') <small class="text-danger">{{ $message }}</small> @enderror </div> </div> <div> <div class="form-group"> <label for="answer2">Choice 2</label> <input name="answers[][answer]" type="text" value="{{ old('answers.1.answer') }}" class="form-control" id="answer2" aria-describedby="choicesHelp" placeholder="Enter Choice 2"> @error('answers.1.answer') <small class="text-danger">{{ $message }}</small> @enderror </div> </div> <div> <div class="form-group"> <label for="answer3">Choice 3</label> <input name="answers[][answer]" type="text" value="{{ old('answers.2.answer') }}" class="form-control" id="answer3" aria-describedby="choicesHelp" placeholder="Enter Choice 3"> @error('answers.2.answer') <small class="text-danger">{{ $message }}</small> @enderror </div> </div> <div> <div class="form-group"> <label for="answer4">Choice 4</label> <input name="answers[][answer]" type="text" value="{{ old('answers.3.answer') }}" class="form-control" id="answer4" aria-describedby="choicesHelp" placeholder="Enter Choice 4"> @error('answers.3.answer') <small class="text-danger">{{ $message }}</small> @enderror </div> </div> </fieldset> </div> <button type="submit" class="btn btn-primary">Add Question</button> </form> </div> </div> </div> </div> </div> @endsection
細かく見てみます。
question
<div class="form-group"> <label for="question">Question</label> //'question.question'で受け取る <input name="question[question]" type="text" class="form-control" value="{{ old('question.question') }}" id="question" aria-describedby="questionHelp" placeholder="Enter Question"> <small id="questionHelp" class="form-text text-muted">Ask simple and to-the-point questions for best results.</small> @error('question.question') <small class="text-danger">{{ $message }}</small> @enderror </div>
answer1
<div> <div class="form-group"> <label for="answer1">Choice 1</label> //answeresを配列で渡した1番目のanswer。answerがkey。 <input name="answers[][answer]" type="text" //1番目なので0を指定 value="{{ old('answers.0.answer') }}" class="form-control" id="answer1" aria-describedby="choicesHelp" placeholder="Enter Choice 1"> @error('answers.0.answer') <small class="text-danger">{{ $message }}</small> @enderror </div> </div>
answer2,3,4も同じ。
QuestionController
class QuestionController extends Controller { public function create(Questionnaire $questionnaire) { return view('question.create',compact('questionnaire')); } public function store(Questionnaire $questionnaire) { //Validationして$dataに入れる。 $data = request()->validate([ //question['question'] 'question.question' =>' required', //arrayを入力するのでワイルドカード 'answers.*.answer' =>' required', ]); //$data['question']を作成 $question = $questionnaire->questions()->create($data['question']); //$data['answers']を作成 answersは複数あるのでcreateMany $question->answers()->createMany($data['answers']); return redirect()->route('questionnaire.show',[$questionnaire->id]); } }
QuestionnaireController
public function show(Questionnaire $questionnaire) { //lazy loading.questionsと一緒にquestionsとリレーションを貼ったanswersを呼び出す。取得できる結果はwith(Eager)と同じ $questionnaire->load('questions.answers'); return view('questionnaire.show',compact('questionnaire')); }
questionnaire/show.blade
//受け取った変数を$questionとしてループ @foreach ($questionnaire->questions as $question) <div class="card mt-4"> <div class="card-header">{{ $question->question }}</div> <div class="card-body"> <ul class="list-group"> //$questionとのリレーション$answersを$answerとしてループ @foreach ($question->answers as $answer) <li class="list-group-item">{{ $answer->answer }}</li> @endforeach </ul> </div> </div> @endforeach
Question Answer1 Answer2 Answer3 Answer4
と出力されます。