Fippiyのプログラム学習内容アウトプットBlog

日々の学習内容をアウトプットして振り返りを実施する。

Laravel開発、ページネーション機能をつける【2】検索ページのリスト表示にページネーションを実装する

indexページに表示される書籍情報一覧表示に対してのページネーション機能を設定しました。

コンポーネントによるリスト表示に対してページネーション化していますので、同じコンポーネントを利用している検索ページにもページネーション機能を追加することにしました。

今回の目的

リスト表示コンポーネントを利用している検索ページにてページネーションを適用させる

なぜやるか

検索結果が大量にあった場合に、全結果を表示するのではなくページ遷移による個別表示を行うことでユーザーに対して扱いやすい結果表示とするため

やりたいこと

  • ページネーション機能を検索結果に対応させる

やったこと

  • 検索処理にページネーションを導入する
  • 検索時のデータ処理をpostからgetに修正する
  • ページネーションリンクを場合分けする
  • 検索結果の件数表示をする

実施内容 

検索ページを確認する

検索結果が表示されない

検索ページはワード入力+検索によって、結果がリストとして表示されるページです。

f:id:Fippiy:20190528115240p:plain

検索ページ

検索結果は、この画面の下に一覧表示されます。

ページネーション化コンポーネントと同じ物を使用しているので、ページリンクが付与されて表示されます。

そのため、ページネーション対応したデータを準備する必要が有ります。このまま検索してもエラー画面となり正しく表示はできません。

 

テストによる確認

書籍情報ページに関連するテストによっても、検索結果を表示できずにエラーとなりました。

[テスト結果]

# ~/tests/Feature/BookdataTest.php

$ vendor/bin/phpunit tests/Feature/BookdataTest.php

PHPUnit 7.5.7 by Sebastian Bergmann and contributors.

.......FF.......................                                  32 / 32 (100%)

Time: 8.71 seconds, Memory: 32.00 MB

 

There were 2 failures:

1) Tests\Feature\BookdataTest::test_findTitle_ok_yesMatchFindTitle

Expected status code 200 but received 500.

Failed asserting that false is true.

 

~/book-property-management/vendor/laravel/framework/src/Illuminate/

 Foundation/Testing/TestResponse.php:133

~/book-property-management/tests/Feature/BookdataTest.php:282

 

2) Tests\Feature\BookdataTest::test_findTitle_ok_noMatchFindTitle

Expected status code 200 but received 500.

Failed asserting that false is true.

 

~/book-property-management/vendor/laravel/framework/src/Illuminate/

 Foundation/Testing/TestResponse.php:133

~/book-property-management/tests/Feature/BookdataTest.php:307

 

FAILURES!

Tests: 32, Assertions: 321, Failures: 2.

 [テストコード]

// 検索書籍有り
public function test_findTitle_ok_yesMatchFindTitle(){
 //// ユーザー生成
 $user = factory(User::class)->create(); // ユーザーを作成
 $this->actingAs($user); // ログイン済み
 $this->assertTrue(Auth::check()); // Auth認証済であることを確認
 // faker book自動生成
 $bookdata = factory(Bookdata::class)->create();
 //// 検索
 // 検索の実施(findページ)
 $find_post = 'book/find'; // 検索パス
 $savebook = Bookdata::all()->first(); // 保存されたデータを取得
 $response = $this->get($find_post); // 検索ページへアクセス
 $response->assertStatus(200); // 200ステータスであること
 $response->assertViewIs('book.find'); // book.findビューであること
 $response = $this->from($find_post)->post($find_post,
  ['find' => $bookdata->title]); // 検索実施
 $response->assertSessionHasNoErrors(); // エラーメッセージがないこと
 $response->assertStatus(200); // 200ステータスであること 282行目
 $response->assertSeeText($bookdata->title); // bookdataタイトルが表示されていること
}

テスト結果によると282行目と307行目に問題があるように見えます。

実際に282行目を確認すると、検索結果表示に対してのステータスが200であることを確認していますが、先の問題を解決していないため500ステータスとなってしまっている為、不一致となっています。307行目に関しても検索結果表示に関する物です。

 

ページネーション対応を実施する

検索結果をpagination対応にする

indexページ同様に、paginationを付与して対応させます。

[変更前]

# ~/app/Http/Controllers/BookController.php

public function search(Request $request)
{
// バリデーションチェック
$this->validate($request, Bookdata::$searchRules);
$title = $request->find;
$books = Bookdata::where('title', 'like', "%{$title}%")->get();
$count = count($books);
if ($count==0) {
$msg = '書籍がみつかりませんでした。';
} else {
$msg = $count.'件の書籍がみつかりました。';
}
$param = ['input' => $title, 'books' => $books, 'msg' => $msg];
return view('book.find', $param);
}

検索結果に対してpaginateを付与します。

$books = Bookdata::where('title', 'like', "%{$title}%")->paginate(2);

結果表示に対して2件の上限を設定しました。

この状態で実際に検索を行います。

f:id:Fippiy:20190528121207p:plain

検索結果

2件の検索結果が表示されました。

しかし、次のページを表示しようとすると消えてしまいます

f:id:Fippiy:20190528115240p:plain

検索結果が消える

確認の為、ページネーションの表示件数を増やして検索結果を全て表示してみます。

$books = Bookdata::where('title', 'like', "%{$title}%")->paginate(10);

f:id:Fippiy:20190528121450p:plain

検索結果

実際には4件のデータがあり正常出力されている状態です。

先程は2件のページネーション指定をしており、ページネーション表示自体はできていたが、検索結果も2件となっていました。こちらも修正がいりそうです。

 

検索結果ページのページネーション問題を解決する

どう作成するか?

検索ページでのページネーション対応について調べてみました。こちらを参考にさせて頂きました、ありがとうございます。

manablog.org

こちらの情報によると検索結果に対応するURLがページネーションのリンクに設定されていない為にリンクをクリックするとURLが異なる為に表示がきえるようです。

検索ページのURLはこちらです。

~/book/find

検索後は検索ワードを含むURLとなります。

~/book/search?find=検索ワード

 

URLが対応できていない

ところが、自分のサイトを確認してみたのですが、URLは変わりません。

検索しても"~/book/find"のままです。

 

検索ページのフォームはこうなっています。

# ~/resources/views/book/find.blade.php

<form class="book-find" action="{{ route('book.find') }}" method="post">

postで作成していました。これではURLに検索結果を反映した状態にはなりません。

getメソッドでないと対応できません。

検索に関してはそもそもDBへデータ保存するわけでもないのでpostにする必要なかったですね…。

というわけで、postからgetに修正する必要がでてきました。

 

検索メソッドを修正する

まずはフォームを修正します。

# ~/resources/views/book/find.blade.php

<form class="book-find" action="{{ route('book.search') }}" method="get">

メソッドをgetに修正と、アクション名を変更しました。

今までは、getのbook/findに対してpostのbook/findとしてデータ送信していました。

今回、同じgetを利用することとなり名前が重複するので変更しています。

 

アクション名変更に伴って、ルーティングについても記述を変更しています。

# ~/routes/web.php

Route::get('/book/search', 'BookController@search')->name('book.search');

これで検索することでURLに検索結果が付与された状態になりました。

しかし、これだけでは次のページへ移動してもデータは消えてしまいます

 

ページネーションリンク対応する

ここで改めて表示させるページのURLを確認します。

index一覧表示ページ

  • ~/book/index

indexページネーション(2ページ目)

  • ~/book?page=2

検索ページトップ

  • ~/book/find

検索結果ページ

  • ~/book/search?find=検索ワード

検索ページ表示リンク(2ページ目)←問題点

  • ~/book/search?page=2

このようになっています、最後の検索後のページに関しては検索ワードが消えてしまっており、これが原因で次のページに移動するとデータが消えてしまいます。

希望するリンクURLはこちらです。

検索結果ページ(2ページ目)

 ~/book/search?find=検索ワード&page=2

検索したワード結果に対しての2ページ目と標記できれば対応できそうです。

そこでページネーションのリンクにappendsを使用して文字列を付け加えます。

{{ $books->appends(Request::only('find'))->links() }}

findは検索フォームに使用している名前です。これによって"find=検索ワード"を付与したリンクとして生成できます。 

 

これで検索ページでのURL対応は完了しました、2ページ目、3ページ目と進むと、続きのデータが表示されるようになりました。

  

結果表示に検索件数を表示させる

ページネーション実装時の確認で上限2件に対して、実際の検索結果は4件となっていました。

f:id:Fippiy:20190528121207p:plain

検索結果表示

ページネーションとしてはこれで問題ないのですが、やはり数値は検索数が表示されるべきです。
しかし、検索数だけの為に検索をもう一度するには非効率です。そこで処理方法を調べてみました。こちらを参考にさせて頂きました、ありがとうございます。

blog.capilano-fw.com

totalを使えば簡単に検索総数がだせそうです。

# ~/app/Http/Controllers/BookController.php

public function search(Request $request){
 // バリデーションチェック
 $this->validate($request, Bookdata::$searchRules);
 $title = $request->find;
 $books = Bookdata::where('title', 'like', "%{$title}%")->paginate(2);
 $count = count($books);
 if ($count==0) {
  $msg = '書籍がみつかりませんでした。';
 } else {
  $msg = $books->total().'件の書籍がみつかりました。';
 }
 $param = ['input' => $title, 'books' => $books, 'msg' => $msg];
 return view('book.find', $param);
}

検索件数表示箇所で$books->total()として結果数を参照することで1ページ表示数ではなく、検索結果数を表示させることができました。

 

以上で書籍情報を扱うページでのリスト表示に対してページネーションによる複数ページを表現することができました。

 

残るは所有書籍ページへの対応と、ページネーション化に伴うテストの実装をおこなっていきます。