Laravelでデータベースから検索した値をペジネーションを使って表示させる

Laravelのペジネーションと検索フォームを使った簡単な蔵書検索サイトを作成してみます。
初心者の方に向けて書いた記事ですので色々クールじゃ無いとこもあるかもです。


### 基本事項

Laravel 5.7
PHP7.2
Mysql

defaultデータベースのbookテーブルを以下の内容で作ってます。
id
name …書籍名
author …著者名
day …発行日


今回は以下のファイルを使って蔵書検索を書籍名で行い別ページにて一覧を表示させる仕様にします。


form.blade.php //蔵書検索フォーム
booklist.blade.php //一覧表示
FormController.php //コントローラー
Booksearch.php//モデル


### ルーティング

まずはroutes/web.phpにてルーティングします。
(わかってる人は::resourceを)

```/routes/web.php
Route::get('/form', 'FormController@index');
Route::get('/booklist', 'FormController@booklist');
```

### コントローラーを作ります。

```/Http/Controller/FormController.php

<?php

namespace App\Http\Controllers; //名前空間

use Request; //値の受け渡しをするのでもちろん必要
use App\Booksearch; //Booksearchモデル（Eloquent） あとで作ります。

class FormController extends Controller {

  public function index(){ //formにアクセスされたら単純にform.blade.phpを返します。あとで作ります。
       return view('form');
  }

  public function booklist(Request $request){ //検索フォームから値を受け取って一覧表示をさせる処理とか。

        $title = Request::get('title'); //GET送信された書籍名を受け取ります。

        if ($title) { //書籍名が入力されてたらの処理
            $item = Booksearch::where('name', 'LIKE', "%$title%")->simplePaginate(2);
            //where()でBooksearchモデルを利用してテーブルのnameカラムが入力した書籍名の本を検索
           //simplePaginate(表示数)でさらにペジネーションをするようにしています。前後ページだけを表示するsimplepaginateを今回使ってますが、1.2.3.4…とページ数を一気に表示させたいときはPaginateを使ってください。
        }else { //書籍名が入力されていない時の処理
            $item = Booksearch::select('*')->simplePaginate(2);
            //書籍名がない時は全件表示させることにします。
            $title='全件表示';
        }
        
        return view('booklist',['items' => $item])->with('title',$title);
        //一覧のbooklist.blade.phpを表示させる時に$itemに格納された結果と検索ワードを渡してあげてます。
  }
}

```
### 何回も出てきたBooksearchモデルを。

データベース関連の設定は出来ているものとして進みます！もしデータベース系のエラーが出る時は別で調べてください！

```/app/Booksearch.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model; //忘れずに！

class Booksearch extends Model
{
protected $table = 'default.book'; //defaultデータベースのbookテーブルなので定義しておきます。
}

```

### 実際に表示させるページ

デザインは一切していないので各自行ってください。

まずは検索フォームのページ。
特に難しいことはしてないです。

```/views/form.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>書籍検索</title>

<body>
<h2>蔵書検索</h2>
<form  method="GET" action="/booklist"> //booklistへ本の名前を飛ばしてます 
    <input type="text" name="title">
    <input type="submit" value="検索">
</form>
</body>
</html>
```

一覧を表示させるページ

```/views/booklist.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>書籍検索</title>

<body>
<h2>蔵書検索結果</h2>
<p>検索キーワード：{{$title}}</p> 

@if(!$items->isEmpty()) //検索結果があるか確認してある時の処理（@emptyじゃオブジェクトなので無理です）
<table>
    <tr><th>本の名前</th><th>著者名</th><th>出版日</th></tr>
    @foreach($items as $item) //$itemsでコントローラーから渡された値を＠foreachで表示します。
        <tr>
            <td>{{$item->name}}</td>
            <td>{{$item->author}}</td>
            <td>{{$item->day}}</td>
        </tr>  
    @endforeach
{{ $items->appends(Request::only('title'))->links()}} //ここが肝です。下記で説明します。
</table>
@else　//検索結果があるか確認して無い時の処理
   <p>該当する書籍は存在しません</p>
   <h2>蔵書検索</h2>
   <form  method="GET" action="/booklist">
       <input type="text" name="title">
       <input type="submit" value="検索">
   </form>
@endif

```

###肝の部分

ペジネーションを使う時に
前後のページへのリンクを表示させる際は、

```
{{ $items->links()}}
```

を使いますが、これでは最初のページはしっかり条件にあったものだけ表示されますが、次ページに行ってしまうと
検索のために必要なGETパラメーター(検索ワード)が維持できません。


そこで、リンク自体にパラメーターを持たせてあげます。

```
{{ $items->appends(Request::only('title'))->links()}}
```

これでページ遷移してもちゃんとした検索結果のまま表示してくれます！


Laravel便利ですね！