やりたいこと
Laravelで自分で作る英単語帳アプリを作っており、
保存されたレコードの指定範囲からクイズを出題する機能を追加しようとしています。
考えているやり方
・テスト形式選択画面のViewで、テスト範囲を「自分が保存した単語」or「他人が保存した単語のうち、良いねしたもの」から選んでFormでコントローラに送信
・コントローラで、
①Formデータに基づき、Viewに渡すレコードを取得
②(1ページ目の場合)レコードをランダム順にし、1ページ1レコードのページネーションをつけてViewに渡す
(2ページ目以降の場合)1ページ目のViewから渡された順番の通りとし、1ページ1レコードのページネーションをつけてViewに渡す
・Viewでは入力欄だけつくる(答えをForm送信はしない)。ボタンを押すと答えが表示されるように。
コントローラから受け取った順序をページネーションリンクにappendsメソッドで追加して渡す
問題点
あるユーザの「他人が保存した単語のうち、良いねしたもの」が①②③④の4つあるとします。
テスト範囲を「他人が保存した単語のうち、良いねしたもの」にすると、
①②②③のような4ページになることが度々あります。(一つの組み合わせに同じカードが2つ存在。含まれないカードが1つある)
※毎回ではありません。正しく①②③④の4ページになることもあります。
解決方法についてアドバイスをいただきたく、よろしくお願いいたします。
現在のコード
TestController.php
php
1 public function test(Request $request, $id) { 2 $user = User::find($id); 3 $scope = $request->input('scope'); //テスト範囲:2択 4 $order = $request->input('order');//1ページ目から渡された順序を$orderとする 5 6 if ($scope == 'my_cards') { 7 $cards = $user->cards(); 8 } else { 9 $cards = $user->good_cards(); 10 } 11 12 /*$orderが空なら(=1ページ目なら)ランダムが並び順。 13 $orderの中身があれば(=2ページ目以降なら)$orderが並び順。*/ 14 if ($order == null) { 15 $count = $cards->count(); 16 $numbers = range(1, $count); 17 shuffle($numbers); 18 $pages = null; 19 foreach ($numbers as $number) { 20 $pages .= $number; 21 }; 22 } else { 23 $pages = $order; 24 }; 25 26 $cards = $cards->inRandomOrder($pages)->paginate(1); 27 28 return view('test.test', [ 29 'cards' => $cards, 30 'order' => $pages, 31 'scope' => $scope, 32 ]); 33 }
test.blade.php
PHP
1@extends('commons.app') 2@section('content') 3<div class="container"> 4 <ul class="list-unstyled"> 5 @foreach ($cards as $card) 6 <li> 7 <div class="row"> 8 <div class="col-6"> 9 <div class="card"> 10 <div class="card-body"> 11 <p class="card-title">英語:</p> 12 <p class="card-text">{{ $card->english }}</p> 13 </div> 14 </div> 15 </div> 16 <div class="col-6"> 17 <div class="card"> 18 <div class="card-body"> 19 <p class="card-title">日本語:</p> 20 <textarea rows="4" class="form-control"></textarea> 21 </div> 22 </div> 23 <div class="hidden_box"> 24 <label for="answer" class="btn btn-dark btn-block">答えを見る</label> 25 <input type="checkbox" id="answer"> 26 <div class="hidden_show"> 27 <div class="card"> 28 <div class="card-body"> 29 <p class="card-title">答え:</p> 30 <p class="card-text">{{ $card->japanese }}</p> 31 </div> 32 </div> 33 </div> 34 </div> 35 </div> 36 </div> 37 </li> 38 @endforeach 39 </ul> 40 {{ $cards->appends(['scope' => $scope, 'order' => $order])->render('pagination::bootstrap-4') }} 41</div> 42@endsection
web.php
php
1Route::group(['middleware' => 'auth'], function () { 2 Route::group(['prefix' => 'users/{id}'], function (){ 3 Route::get('test', 'TestController@test')->name('users.test'); 4 }); 5});
User.php
php
1 public function cards() 2 { 3 return $this->hasMany(Card::class); 4 } 5 6 public function good_cards() 7 { 8 return $this->belongsToMany(Card::class, 'good', 'good_user_id', 'card_id')->withTimestamps(); 9 }
確認したこと
・テスト範囲$scope
を「自分が保存した単語」にすると毎回問題なく全カードが1ページずつ表示されます。
・Viewに渡された良いねしたカード$user->good_cards()
の中身は毎回正しく①②③④全カードの並び替えになっています。ダブっていません。
($cards->inRandomOrder($pages)->paginate(4);
に変えてみて確認)
・$pages
の中身は正しく1~4をランダムに並び替えたものになっています。(Viewに渡して確認)
補足
別の問題かもしれませんが、当初は$cards = $cards->inRandomOrder($pages)->paginate(1);
の$pages
の中身を1234と固定にしていました。すると順番が毎回同じになりました。なので1ページ目の場合はシャッフルしたものを$pages
に入れるようにしています。
環境
Laravel 5.5
よろしくお願いいたします。