Laravelで都道府県やカテゴリなどのプルダウンと文字入力から検索機能を実装する

## 業務でプルダウンと文字入力から検索機能を実装する機会があり調べながら実装したので備忘録として。

ここではユーザーが都道府県やカテゴリを選択してニュースを投稿するという前提で進める。

###都道府県とカテゴリデータの準備

config下にファイルを作成することで、定数的な使い方ができる。定義した値はconfig('ファイル名.キー名')でアプリのどこからでも取得できる。

```php:pref.php
<?php 
return array(
  '1' => '北海道', 
  '2' => '青森県', 
  '3' => '岩手県', 
  '4' => '宮城県',
  '5' => '秋田県', 
  '6' => '山形県', 
  '7' => '福島県', 
  '8' => '茨城県',
  '9' => '栃木県', 
  '10' => '群馬県', 
  '11' => '埼玉県', 
  '12' => '千葉県',
  '13' => '東京都', 
  '14' => '神奈川県', 
  '15' => '新潟県', 
  '16' => '富山県',
  '17' => '石川県', 
  '18' => '福井県', 
  '19' => '山梨県', 
  '20' => '長野県', 
  '21' => '岐阜県', 
  '22' => '静岡県', 
  '23' => '愛知県', 
  '24' => '三重県',
  '25' => '滋賀県', 
  '26' => '京都府', 
  '27' => '大阪府', 
  '28' => '兵庫県',
  '29' => '奈良県', 
  '30' => '和歌山県', 
  '31' => '鳥取県', 
  '32' => '島根県',
  '33' => '岡山県', 
  '34' => '広島県', 
  '35' => '山口県', 
  '36' => '徳島県',
  '37' => '香川県',
  '38' => '愛媛県',
  '39' => '高知県', 
  '40' => '福岡県',
  '41' => '佐賀県', 
  '42' => '長崎県', 
  '43' => '熊本県', 
  '44' => '大分県',
  '45' => '宮崎県', 
  '46' => '鹿児島県', 
  '47' => '沖縄県'
);
?>

```

### カテゴリ一覧
```php:category.php
<?php 
return array(
  '1' => 'エンタメ', 
  '2' => '経済', 
  '3' => 'IT', 
  '4' => 'スポーツ',
  '5' => 'イベント', 
  '6' => 'その他'
);
?>

```
### ルーティング
```php:web.php
//新規作成
Route::get('news/new', 'App\Http\Controllers\News\PostController@new')->name('newsNew');
//保存
Route::post('news/store', 'App\Http\Controllers\News\PostController@store')->name('newsStore');
//検索
Route::get('news/search','App\Http\Controllers\News\PostController@search')->name('newsSearch');
```

### マイグレーションファイル

```php:XXXXXXXXXXX_create_posts_table
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id');
            $table->integer('category_id'); 
            $table->integer('pref_id');
            $table->string('title');
            $table->timestamps();
        });
    }
```

###モデルでpref_idとcategory_idの数字から実際の名前へと変換する関数を定義

```php:Post.php
      public function getPrefNameAttribute()
      {
          return config('pref.'.$this->pref_id);
      }

      public function getCategoryNameAttribute()
      {
          return config('category.'.$this->category_id);
      }
```

### コントローラーで新規作成

```php:PostController.php
public function new()
    {
        $prefs = config('pref');
        $categories = config('category');
        return view('news.new')->with(['prefs' => $prefs],['categories' => $categories])->with(['categories' => $categories]);
    }
```

### コントローラーで値を保存

```php:PostController.php
public function store(Request $request, User $user)
    {
        $user = Auth::user();

        $post = new Post();
        $post->title                  = $request->input('title');
        $post->body                   = $request->input('body');
        $post->category_id            = $request->category;
        $post->pref_id                = $request->pref;
        $post->user_id                = Auth::id();

        $post->save();

        return redirect()->to('/news/search');
    }
```

### コントローラーで検索機能

```php:PostController.php
    public function search(Request $request)
{
        $prefs = config('pref');
        $categories = config('category');
        $query = Post::query();

        //$request->input()で検索時に入力した項目を取得します。
        $search1 = $request->input('title');
        $search2 = $request->input('pref');
        $search3 = $request->input('category');

         // タイトル入力フォームで入力した文字列を含むカラムを取得します
        if ($search1!=null) {
            $query->where('title', 'like', '%'.$search1.'%')->get();
        }

         // プルダウンメニューで指定なし以外を選択した場合、$query->whereで選択した都道府県と一致するカラムを取得します
        if ($search2!=null) {
            $query->where('pref_id', $search2)->get();
        }

         // プルダウンメニューで指定なし以外を選択した場合、$query->whereで選択した好きなカテゴリと一致するカラムを取得します
        // if ($request->has('category'))
        if ($search3!=null) {
            $query->where('category_id', $search3)->get();
        }

        //ニュースを1ページにつき5件ずつ表示させます
        $data = $query->paginate(5);

        return view('posts.search',[
            'prefs' => $prefs,'categories' => $categories,'data' => $data
        ]);
    }
```

### ニュース新規作成ページ

```php:new.blade.php
        <section id="dash-news">
            <form method="POST" action="{{ route('newsStore') }}" class="p-5" enctype="multipart/form-data">
                    @csrf
                <div class="col-8 offset-2">
                    @if (session('status'))
                        <div class="alert alert-success" role="alert">
                            {{ session('status') }}
                        </div>
                    @endif
                </div>
                    {{-- タイトル --}}
                    <div class="dn-title">
                        <label for="name">タイトル</label>
                        <input id="title" type="text" class="@error('title') @enderror" placeholder="タイトル" name="title" value="{{ old('title') }}" required autocomplete="title" autofocus>
                        @error('title')
                        <span class="invalid-feedback" role="alert">
                            <strong>{{ $message }}</strong>
                        </span>
                        @enderror
                    </div>

                    <div class="select-tag">
                            <div class="prefecture">
                                <select class="form-control" id="pref" name="pref" required>
                                    @foreach($prefs as $index => $name)
                                        <option value="" hidden>都道府県▼</option>
                                        <option value="{{ $index }}">{{ $name }}</option>
                                    @endforeach
                                </select>
                            </div>
                            <div class="category">
                                <select class="form-control" id="category" name="category" required>
                                    @foreach($categories as $index => $name)
                                        <option value="" hidden>カテゴリー▼</option>
                                        <option value="{{ $index }}">{{ $name }}</option>
                                    @endforeach
                                </select>
                            </div>
                        </div>
                    </div>

                    <div id="btn-block" class="form-group">
                        <button type="submit" id="btn" class="btn">
                            投稿する
                        </button>
                    </div>
                </form>
            </section>
```


### ニュース検索表示ページ

```php:search.blade.php
@section('content')
<div class="row">
        <div class="col-sm-4">
            <div class="text-center my-4">
                <h3 class="brown border p-2">投稿検索</h3>
            </div>
        <form method="GET" action="{{ route('search') }}" class="p-5" enctype="multipart/form-data">
                    @csrf
            <div class="select-tag">
                <div class="dn-title">
                    <input id="title" type="text" placeholder="タイトル" name="title" >
                <div class="st-area">
                    <p>タグを選択してください</p>
                    <div class="st-flex">
                        
                            <select class="form-control" id="pref" name="pref" >
                                @foreach($prefs as $index => $name)
                                    <option value="" hidden>都道府県▼</option>
                                    <option value="{{ $index }}">{{ $name }}</option>
                                @endforeach
                            </select>
                        </div>
                        <div class="category">
                            <select class="form-control" id="category" name="category" >
                                @foreach($categories as $index => $name)
                                    <option value="" hidden>カテゴリー▼</option>
                                    <option value="{{ $index }}">{{ $name }}</option>
                                @endforeach
                            </select>
                        </div>
                    </div>
                </div>
             </div>
        <div class="col-sm-8">
            <div class="text-center my-4">
                <h3 class="brown p-2">投稿一覧</h3>
            </div>

            <div class="container">
                <!--検索ボタンが押された時に表示されます-->
                @if(!empty($data))
                    <div class="my-2 p-0">
                        <div class="row  border-bottom text-center">
                            <div class="col-sm-4">
                                <p>タイトル</p>
                            </div>
                            <div class="col-sm-4">
                                <p>カテゴリ</p>
                            </div>
                            <div class="col-sm-4">
                                <p>都道府県</p>
                            </div>
                        </div>
                        <!-- 検索条件に一致したユーザを表示します -->
                        @foreach($data as $post)
                                <div class="row py-2 border-bottom text-center">
                                    <div class="col-sm-4">
                                        <a href="">{{ $post->title }}</a>
                                    </div>
                                    <div class="col-sm-4">
                                        {{ $post->CategoryName }}
                                    </div>
                                    <div class="col-sm-4">
                                        {{ $post->prefName }}
                                    </div>
                                </div>
                        @endforeach
                    </div>
                    {{ $data->appends(request()->input())->render('pagination::bootstrap-4') }}
                @endif
            </div>
                <div id="ulb-frame" class="form-group mb-0 mt-3">
                    <button type="submit" id="uploadBtn" class="btn btn-block btn-secondary">
                        検索する
                    </button>
                </div>
        </form>
        </div>
    </div>
@endsection
```

参考記事

https://qiita.com/sakuraya/items/42fffe0f171d49ee74a0

https://qiita.com/banku/items/4ac99f9a48d2fc862255

参考になれば幸いです。