質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

2回答

619閲覧

まだ1度も解いてない問題が表示されず、これまで表示されていた4択の選択肢も表示されない

t.mat

総合スコア15

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

0クリップ

投稿2019/02/12 02:28

編集2019/02/12 02:41

前提・実現したいこと

お世話になります。
Laravelでクイズアプリを作ってみています。

「1度正解した問題を表示しない」という機能を実装したいです。

テーブルにはそれぞれ以下のようなデータが入っています。
・Questionsテーブル
イメージ説明
idが問題番号、topic_idがカテゴリ、question_textが問題文です。
イメージ説明
・Questions_optionsテーブル
イメージ説明
question_idがQuestionsテーブルのidと関係しています。
correctがその選択肢が正解かどうかを表しています。
イメージ説明
・test_answersテーブル
イメージ説明
user_idが回答者のid、question_idがQuestionsテーブルのidと関係、correctが正解したかどうかを表しています。
イメージ説明

入門書やネットで色々調べて試してみたのですがうまく行かず、初めて質問させていただきます。
SQLやPHPも学び始めたばかりですが、頑張りますのでご教授よろしくお願いします。
どのような関数を使えばいいのかやどういったサイトが参考になるのか等でも良いのでよろしくお願いいたします。

発生している問題・エラーメッセージ

1度解いて不正解になった(correctが0)問題のみ表示される...のはいいのですが、まだ1度も解いてない問題が、test_answersに登録されていないため表示されない。
また、実行してみるとこれまで表示されていた4択の選択肢が表示されなくなってしまいました。

今回の場合、topic_idが1、user_idが3で実行すると、test_answersテーブルのcorrectが0であるquestion_idが5と9の問題(中国の首都は?とスクリーンショットには載っていませんが9のイタリアの首都は?)のみ表示されます。

該当のソースコード

同じカテゴリ(topic_id)の問題からランダムで表示

php

1 /** 2 * 3 * 4 * @param int $id 5 * @return \Illuminate\Http\Response 6 */ 7 public function create($id) 8 { 9 // 元々書いてあったコード 10 // $questions = Question::where('topic_id', $id)->inRandomOrder()->limit(10)->get(); 11 12 // 今回書いているコード 13 $a_id = Auth::id(); 14 $questions = DB::table('questions') 15 ->where('topic_id', $id) 16 ->leftJoin('test_answers', 'questions.id', '=', 'test_answers.question_id') 17 ->where(function ($query) use($a_id){ 18 $query->where('test_answers.user_id', $a_id) 19 ->where('test_answers.correct', '<>', 1); 20 }) 21 ->inRandomOrder()->limit(10)->get(); 22 // 今回書いているコードここまで 23 foreach ($questions as &$question) { 24 $question->options = QuestionsOption::where('question_id', $question->id)->inRandomOrder()->get(); 25 } 26 return view('tests.create', compact('questions')); 27 }

補足情報(FW/ツールのバージョンなど)

・LaravelDailyさんのLaraQuizを元に作成しています。
https://github.com/LaravelDaily/Laraquiz-QuickAdminPanel

・環境構築にはMAMPを使っています。

・Question.php

php

1<?php 2namespace App; 3 4use Illuminate\Database\Eloquent\SoftDeletes; 5use Illuminate\Database\Eloquent\Model; 6 7/** 8 * Class Question 9 * 10 * @package App 11 * @property string $topic 12 * @property text $question_text 13 * @property text $code_snippet 14 * @property text $answer_explanation 15 * @property string $more_info_link 16*/ 17class Question extends Model 18{ 19 use SoftDeletes; 20 21 protected $fillable = ['question_text', 'code_snippet', 'answer_explanation', 'more_info_link', 'topic_id']; 22 23 public static function boot() 24 { 25 parent::boot(); 26 27 Question::observe(new \App\Observers\UserActionsObserver); 28 } 29 30 /** 31 * Set to null if empty 32 * @param $input 33 */ 34 public function setTopicIdAttribute($input) 35 { 36 $this->attributes['topic_id'] = $input ? $input : null; 37 } 38 39 public function topic() 40 { 41 return $this->belongsTo(Topic::class, 'topic_id')->withTrashed(); 42 } 43 44 public function options() 45 { 46 return $this->hasMany(QuestionsOption::class, 'question_id')->withTrashed(); 47 } 48}

・QuestionsOption.php

php

1<?php 2namespace App; 3 4use Illuminate\Database\Eloquent\SoftDeletes; 5use Illuminate\Database\Eloquent\Model; 6 7/** 8 * Class QuestionsOption 9 * 10 * @package App 11 * @property string $question 12 * @property string $option 13 * @property tinyInteger $correct 14*/ 15class QuestionsOption extends Model 16{ 17 use SoftDeletes; 18 19 protected $fillable = ['option', 'correct', 'question_id']; 20 21 public static function boot() 22 { 23 parent::boot(); 24 25 QuestionsOption::observe(new \App\Observers\UserActionsObserver); 26 } 27 28 /** 29 * Set to null if empty 30 * @param $input 31 */ 32 public function setQuestionIdAttribute($input) 33 { 34 $this->attributes['question_id'] = $input ? $input : null; 35 } 36 37 public function question() 38 { 39 return $this->belongsTo(Question::class, 'question_id')->withTrashed(); 40 } 41 42}

・TestController.php

php

1<?php 2 3namespace App\Http\Controllers; 4 5use DB; 6use Auth; 7use App\Test; 8use App\TestAnswer; 9use App\Topic; 10use App\Question; 11use App\QuestionsOption; 12use Illuminate\Http\Request; 13use App\Http\Requests\StoreTestRequest; 14 15class TestsController extends Controller 16{ 17 public function index() 18 { 19 $topics = Topic::all(); 20 21 return view('tests.index', compact('topics')); 22 } 23 24 /** 25 * 26 * 27 * @param int $id 28 * @return \Illuminate\Http\Response 29 */ 30 public function create($id) 31 { 32 // 元々書いてあったコード 33 // $questions = Question::where('topic_id', $id)->inRandomOrder()->limit(10)->get(); 34 35 // 今回書いているコード 36 $a_id = Auth::id(); 37 $questions = DB::table('questions') 38 ->where('topic_id', $id) 39 ->leftJoin('test_answers', 'questions.id', '=', 'test_answers.question_id') 40 ->where(function ($query) use($a_id){ 41 $query->Where('test_answers.user_id', $a_id) 42 ->Where('test_answers.correct', '<>', 1); 43 }) 44 ->orWhere(function ($query) use($a_id){ 45 $query->Where('test_answers.user_id', '<>',$a_id) 46 ->WhereNull('test_answers.question_id'); 47 }) 48 ->inRandomOrder()->limit(10)->get(); 49 // 今回書いているコードここまで 50 foreach ($questions as &$question) { 51 $question->options = QuestionsOption::where('question_id', $question->id)->inRandomOrder()->get(); 52 } 53 return view('tests.create', compact('questions')); 54 } 55 56 /** 57 * Store a newly solved Test in storage with results. 58 * 59 * @param \App\Http\Requests\StoreResultsRequest $request 60 * @return \Illuminate\Http\Response 61 */ 62 public function store(Request $request) 63 { 64 $result = 0; 65 66 $test = Test::create([ 67 'user_id' => Auth::id(), 68 'result' => $result, 69 ]); 70 71 foreach ($request->input('questions', []) as $key => $question) { 72 $status = 0; 73 74 if ($request->input('answers.'.$question) != null 75 && QuestionsOption::find($request->input('answers.'.$question))->correct 76 ) { 77 $status = 1; 78 $result++; 79 } 80 TestAnswer::create([ 81 'user_id' => Auth::id(), 82 'test_id' => $test->id, 83 'question_id' => $question, 84 'option_id' => $request->input('answers.'.$question), 85 'correct' => $status, 86 ]); 87 } 88 89 $test->update(['result' => $result]); 90 91 return redirect()->route('results.show', [$test->id]); 92 } 93 94 /** 95 * Delete all selected Test at once. 96 * 97 * @param Request $request 98 */ 99 public function massDestroy(Request $request) 100 { 101 if ($request->input('ids')) { 102 $entries = Topic::whereIn('id', $request->input('ids'))->get(); 103 104 foreach ($entries as $entry) { 105 $entry->delete(); 106 } 107 } 108 } 109}

・tests>create.blade.php一部抜粋

php

1@section('content') 2 <h3 class="page-title">@lang('quickadmin.laravel-quiz')</h3> 3 {!! Form::open(['method' => 'POST', 'route' => ['tests.store']]) !!} 4 5 <div class="panel panel-default"> 6 <div class="panel-heading"> 7 @lang('quickadmin.quiz') 8 </div> 9 <?php //dd($questions) ?> 10 @if(count($questions) > 0) 11 <div class="panel-body slider"> 12 <?php $i = 1; ?> 13 @foreach($questions as $question) 14 <div class="row"> 15 <div class="col-xs-12 form-group"> 16 <div class="form-group" style="padding-left:100px"> 17 <strong>Question {{ $i }}.<br />{!! nl2br($question->question_text) !!}</strong> 18 19 <input 20 type="hidden" 21 name="questions[{{ $i }}]" 22 value="{{ $question->id }}"> 23 @foreach($question->options as $option) 24 <br> 25 <label class="radio-inline"> 26 <input 27 type="radio" 28 name="answers[{{ $question->id }}]" 29 value="{{ $option->id }}"> 30 {{ $option->option }} 31 </label> 32 @endforeach 33 </div> 34 </div> 35 </div> 36 <?php $i++; ?> 37 @endforeach 38 </div> 39 @endif 40 41 </div> 42 43 {!! Form::submit(trans('quickadmin.submit_quiz'), ['class' => 'btn btn-danger']) !!} 44 {!! Form::close() !!} 45@stop

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/12 02:36

タイトル:1度正解した問題を表示しないようにするには 内容:まだ1度も解いてない問題が表示されない。これまで表示されていた4択の選択肢が表示されない ではタイトルと内容で方向性違いませんか? 内容にそったタイトルにしてください。
t.mat

2019/02/12 02:42

確かにそうですね。 タイトル変更しました。ありがとうございます!
m.ts10806

2019/02/12 02:51

仕様確認ですが、「正解するまで何回でも答えられる」「それまでは不正解のレコードがtest_answersテーブルに蓄積され続ける」ということですよね?
m.ts10806

2019/02/12 02:53

ちなみにview側でdd($questions)されてますが、想定通りの取得したい情報は取れてましたか?
t.mat

2019/02/12 03:09

>仕様確認ですが、「正解するまで何回でも答えられる」「それまでは不正解のレコードがtest_answersテーブルに蓄積され続ける」ということですよね? はい。そのようにしようと思っています。 >ちなみにview側でdd($questions)されてますが、想定通りの取得したい情報は取れてましたか? 問題は取れていたのですが、選択肢が取れていませんでした...。
guest

回答2

0

SQL イメージだけですが、全体的にこんな感じなるように組めばいけるかと

正解が存在しない (NOT EXISTS)

SELECT * FROM questions q WHERE NOT EXISTS ( SELECT 1 FROM test_answers a WHERE q.id = a.question_id AND a.correct = '1' AND a.user_id = ? )

正解が存在しない (NOT IN)

SELECT * FROM questions q WHERE q.id NOT IN ( SELECT a.question_id FROM test_answers a WHERE a.correct = '1' AND a.user_id = ? )

正解が存在しない (LEFT JOIN)

SELECT * FROM questions q LEFT JOIN test_answers a ON q.id = a.question_id AND a.user_id = ? -- NULL か 1以外 WHERE a.correct IS NULL OR NOT a.correct = '1'

投稿2019/02/12 03:27

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t.mat

2019/02/12 03:36

ありがとうございます!早速試してみます。
guest

0

ベストアンサー

問題id、ユーザーid、correct、answer_at
を保持するテーブルがあればよいのでは?
answer_atは未回答のときにはnullもしくは果てしない未来日として
回答した時点で日時を入れれば、answer_atが過去日で
correctが0のモノが間違えた質問になります

訂正

なんか効率悪そうなので考え方を換えます

SQL

1create table question(qid int primary key,qtext varchar(100) 2,a1 varchar(100) 3,a2 varchar(100) 4,a3 varchar(100) 5,a4 varchar(100) 6,correct_a int); 7insert into question values 8( 1,"q01_text","q01_a1","q01_a2","q01_a3","q01_a4",1), 9( 2,"q02_text","q0_a1","q02_a2","q02_a3","q02_a4",2), 10( 3,"q03_text","q03_a1","q03_a2","q03_a3","q03_a4",3), 11( 4,"q04_text","q04_a1","q04_a2","q4_a3","q4_a4",3), 12( 5,"q05_text","q05_a1","q05_a2","q5_a3","q5_a4",4), 13( 6,"q06_text","q06_a1","q06_a2","q6_a3","q6_a4",2), 14( 7,"q07_text","q07_a1","q07_a2","q7_a3","q7_a4",1), 15( 8,"q08_text","q08_a1","q08_a2","q8_a3","q8_a4",3), 16( 9,"q09_text","q09_a1","q09_a2","q9_a3","q9_a4",4), 17(10,"q10_text","q10_a1","q10_a2","q0_a3","q0_a4",4), 18(11,"q11_text","q11_a1","q11_a2","q1_a3","q1_a4",1); 19 20create table user(uid int primary key,uname varchar(20)); 21insert into user values(1,'u1'),(2,'u2'),(3,'u3'); 22 23create table user_question(uqid int primary key auto_increment,uid int not null,qid int not null,correct tinyint default 0,unique(uid,qid)); 24insert into user_question(uid,qid,correct) values 25(1,1,1), 26(1,2,1), 27(1,3,1), 28(1,4,0), 29(1,5,0), 30(1,6,0), 31(2,1,1), 32(2,2,0), 33(2,3,1), 34(2,4,0), 35(2,5,1), 36(2,6,0);

だとします。
上記条件からuid=1の場合qid=1,2,3を除くもの、uid=2の場合qid=1,3,5を除くもの
uid=3の場合すべてが対象になります。

抽出

SQL

1select * from question as t1 2where not exists(select 1 from user_question where qid=t1.qid and uid=1 and correct=1)

uid=xxのxxを指定すれば間違っていたものおよび未回答の物が表示されます。

1問だけ表示したいならorder by とlimitを併用します

SQL

1select * from question as t1 2where not exists(select 1 from user_question where qid=t1.qid and uid=1 and correct=1) 3order by rand() 4limit 1

投稿2019/02/12 02:59

編集2019/02/12 03:50
yambejp

総合スコア114583

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t.mat

2019/02/12 03:14

回答ありがとうございます!参考になります! 新たにテーブルを作成して、あらかじめnullを入れておいて、問題を解いたら更新するという事でしょうか?? その場合、新たに問題を追加した場合は、追加するときにユーザ×問題数のレコードを作成して、nullを入れるという事でしょうか。
yambejp

2019/02/12 03:51 編集

効率が悪そうなので修正しました。追記分で確認してください
t.mat

2019/02/13 03:46

ありがとうございました!いただいた回答を元にやってみようと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問