【Laravel】検索機能の実装


#laravelで検索機能の実装

#要件定義

今回はユーザー一覧から検索機能を実装する。
ユーザーの管理対象項目は名前、年齢、性別

#データベース設計

プロジェクト名:serch
モデル名：User
テーブル名：users



#プロジェクトファイルの作成

```
$ composer create-project --prefer-dist laravel/laravel='5.8' serch
```

#.envファイルにデータベースの設定


#database.sqliteファイルの作成


#Userモデルとマイグレーションファイルを作成

```
$ php artisan make:model User -m
Model created successfully.
Created Migration: 2019_12_21_043638_create_users_table
```

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

```php:
public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('sex');
            $table->integer('age');
            $table->timestamps();
        });
```

#マイグレーションの実行

```
$ php artisan migrate
Migration table created successfully.
Migrating: 2019_12_21_043638_create_users_table
Migrated:  2019_12_21_043638_create_users_table (0.01 seconds)
```

#UsersControllerの作成

```
$ php artisan make:controller UsersController
Controller created successfully.
```

#usersテーブルにデータを挿入するseederファイルを作成

```
$ php artisan make:seeder UsersTableSeeder
Seeder created successfully.
```

#seederファイルに書き込むデータを記載する。

```php:database/seeds/UsersTableSeeder.php
      DB::table('users')->insert([
        [
        'name' => '岩崎蓮',
        'age' => 34,
        'sex' => '男',
        'created_at' => new Datetime(),
        'updated_at' => new Datetime()
      ],
        [
        'name' => '町田里奈',
        'age' => 20,
        'sex' => '女',
        'created_at' => new Datetime(),
        'updated_at' => new Datetime()
      ],
        [
        'name' => '横田拓也',
        'age' => 25,
        'sex' => '男',
        'created_at' => new Datetime(),
        'updated_at' => new Datetime()
      ],
        [
        'name' => '矢野萌',
        'age' => 25,
        'sex' => '女',
        'created_at' => new Datetime(),
        'updated_at' => new Datetime()
      ],
        [
        'name' => '沼田舞',
        'age' => 31,
        'sex' => '女',
        'created_at' => new Datetime(),
        'updated_at' => new Datetime()
      ],

    ]);
    }
```

#DatabaseSeederに実行できるように編集

```
    public function run()
    {
        // $this->call(UsersTableSeeder::class);
        $this->call(UsersTableSeeder::class);
    }
```

#seederの実行

```
$ php artisan db:seed
Seeding: UsersTableSeeder
Database seeding completed successfully.
```

#ルーティングの設定

```php:route/web.php

//検索結果を表示する
Route::get('/serch','UsersController@serch');

//ユーザー一覧と検索画面
Route::get('/','UsersController@index');
```

#Userモデルに書き込み可能な権限を加える

```php:app/User.php
class User extends Model
{
    //
        protected $fillable = ['name','age','sex'];
}
```

#コントローラーの編集

とりあえず、ユーザー一覧を取得するindexメソッドを作成

```php:app/Http/controllers/UsersController.php
  public function index() {
      $users = User::all();
      return view('index')->with('users', $users);
    }
```

#全体ビューを作成

共通化するビューのフォルダとファイルを作成

```
$ cd resources/views
$ mkdir layouts
$ cd layouts
$ vi defalt.blade.php
```

defalt.blade.phpの編集

```html:resources/views/layouts/defalt.blade.php
<!doctype html>
<html lang="ja">
  <head>
    <title>ユーザー管理</title>
  <!-- 必要なメタタグ -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  </head>
  <body>
    <div class="container" style="margin-top:50px;">
      <ul class="nav justify-content-end">
    <li class="nav-item">
      <a class="nav-link active" href="{{ url('/')}}">検索と一覧</a>
    </li>
  </ul>
      @yield('content')
    </div>
    ...

  <!-- オプションのJavaScript -->
  <!-- 最初にjQuery、次にPopper.js、次にBootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  </body>
</html>

```

#indexビューを作成

```html:resources/views/index.blade.php
@extends('layouts.defalt')

@section('content')
<h1>検索条件を入力してください</h1>
<form action="{{ url('/serch')}}" method="post">
  {{ csrf_field()}}
  {{method_field('get')}}
  <div class="form-group">
    <label>名前</label>
    <input type="text" class="form-control col-md-5" placeholder="検索したい名前を入力してください" name="name">
  </div>
  <div class="form-group">
    <label>年齢</label>
    <input type="text" class="form-control col-md-5" placeholder="年齢を入力してください" name="age" value="{{ old("name")}}">
  </div>

  <div class="form-group">
     <label>年齢の条件</label>
     <select class="form-control col-md-5" name="age_condition">
       <option selected value="0">選択...</option>
       <option value="1">以上</option>
       <option value="2">以下</option>
     </select>
   </div>

  <div class="form-group">
     <label>性別</label>
     <select class="form-control col-md-5" name="sex">
       <option selected value="0">選択...</option>
       <option value="1">男</option>
       <option value="2">女</option>
     </select>
   </div>

  <button type="submit" class="btn btn-primary col-md-5">検索</button>
</form>
@if(session('flash_message'))
<div class="alert alert-primary" role="alert" style="margin-top:50px;">{{ session('flash_message')}}</div>
@endif
<div style="margin-top:50px;">
<h1>ユーザー一覧</h1>
<table class="table">
  <tr>
    <th>ユーザー名</th><th>年齢</th><th>性別</th>
  </tr>
@foreach($users as $user)
  <tr>
    <td>{{$user->name}}</td><td>{{$user->age}}</td><td>{{$user->sex}}</td>
  </tr>
@endforeach
</table>
</div>
@endsection

```

#laravelサーバーを立ち上げて確認

```
$ php artisan serve --host ***.****.**.** --port 8000
```

こんな感じでできていれば、okです。

![スクリーンショット 2019-12-22 10.16.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420746/8ce385b3-4298-ed1a-cd06-7030ce6aa45a.png)

#検索機能を実装していきます。

##検索画面を作成

```php:resources/views/serch.blade.php
@extends('layouts.defalt')

@section('content')
<div style="margin-top:50px;">
<h1>検索結果</h1>
@if(isset($users))
<table class="table">
  <tr>
    <th>ユーザー名</th><th>年齢</th><th>性別</th>
  </tr>
  @foreach($users as $user)
    <tr>
      <td>{{$user->name}}</td><td>{{$user->age}}</td><td>{{$user->sex}}</td>
    </tr>
  @endforeach
</table>
@endif
@if(!empty($message))
<div class="alert alert-primary" role="alert">{{ $message}}</div>
@endif
</div>
@endsection
```

##検索メソッドを作成。コントローラーの編集

```php:app/Http/Controllers/USersController.php
public function serch(Request $request) {
      $keyword_name = $request->name;
      $keyword_age = $request->age;
      $keyword_sex = $request->sex;
      $keyword_age_condition = $request->age_condition;

      if(!empty($keyword_name) && empty($keyword_age) && empty($keyword_age_condition)) {
      $query = User::query();
      $users = $query->where('name','like', '%' .$keyword_name. '%')->get();
      $message = "「". $keyword_name."」を含む名前の検索が完了しました。";
      return view('/serch')->with([
        'users' => $users,
        'message' => $message,
      ]);
    }

    elseif(empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 0){
          $message = "年齢の条件を選択してください";
          return view('/serch')->with([
            'message' => $message,
          ]);
    }
    elseif(empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 1){
      $query = User::query();
      $users = $query->where('age','>=', $keyword_age)->get();
      $message = $keyword_age. "歳以上の検索が完了しました";
      return view('/serch')->with([
        'users' => $users,
        'message' => $message,
      ]);
    }
    elseif(empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 2){
      $query = User::query();
      $users = $query->where('age','<=', $keyword_age)->get();
      $message = $keyword_age. "歳以下の検索が完了しました";
      return view('/serch')->with([
        'users' => $users,
        'message' => $message,
      ]);
    }
    elseif(!empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 1){
      $query = User::query();
      $users = $query->where('name','like', '%' .$keyword_name. '%')->where('age','>=', $keyword_age)->get();
      $message = "「".$keyword_name . "」を含む名前と". $keyword_age. "歳以上の検索が完了しました";
      return view('/serch')->with([
        'users' => $users,
        'message' => $message,
      ]);
    }
    elseif(!empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 2){
      $query = User::query();
      $users = $query->where('name','like', '%' .$keyword_name. '%')->where('age','<=', $keyword_age)->get();
      $message = "「".$keyword_name . "」を含む名前と". $keyword_age. "歳以下の検索が完了しました";
      return view('/serch')->with([
        'users' => $users,
        'message' => $message,
      ]);
    }
    elseif(empty($keyword_name) && empty($keyword_age) && $keyword_sex == 1){
      $query = User::query();
      $users = $query->where('sex','男')->get();
      $message = "男性の検索が完了しました";
            return view('/serch')->with([
              'users' => $users,
              'message' => $message,
            ]);
    }
    elseif(empty($keyword_name) && empty($keyword_age) && $keyword_sex == 2){
      $query = User::query();
      $users = $query->where('sex','女')->get();
      $message = "女性の検索が完了しました";
            return view('/serch')->with([
              'users' => $users,
              'message' => $message,
            ]);
    }
    else {
      $message = "検索結果はありません。";
      return view('/serch')->with('message',$message);
      }
}
```

#おまけ


#目的
laravelで検索機能を実装してみたが、検索時のコントローラーに書いたメソッドが長すぎるので、すっきりさせる。その際にファザードという機能を使う。

#全体的な流れ

"serch"という名称のサービスプロバイダーを作成

#プロバイダーの設定

##SerchServiceProviderを作成

```
$ php artisan make:provider SerchServiceProvider
Provider created successfully.
```

##serchクラスの登録

```php:app/Http/Providers/SerchServiceProvider.php
    public function register()
    {
        $this->app->bind(
          'serch',
          'App\Http\Compornents\Serch'
        );
    }
```

#ファザードの設定

##ファザードクラスの作成

laravel/app 配下にFacadesディレクトリを作成し、その中にSerch.phpを作成

コンポーネントの登録名を取得する為のアクセサーgetFacadeAccessor()メソッドを以下のように定義します。

```php:app/Fadades/Serch.php
<?php

namespace App\Facades;

use Illumnate\Support\Facades\Facade;

class Serch extends Facade
{
  protected static function getfacadeAccessor() {
    retrun 'serch';
  }
}
```

##検索メソッドをSerchクラスにまとめる

laravel/app/Http 配下に Components ディレクトリを作成し、その中にSerch.phpを作成

```php:app/Http/Compornents
<?php

namespace App\Http\Components;

use App\User;

class Serch
{
  public static function serch($keyword_name,$keyword_age,$keyword_sex,$keyword_age_condition)
  {
          $query = User::query();

          if(!empty($keyword_name) && empty($keyword_age) && empty($keyword_age_condition)) {
          $users = $query->where('name','like', '%' .$keyword_name. '%')->get();
          $message = "「". $keyword_name."」を含む名前の検索が完了しました。";
        }

        elseif(empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 0){
              $message = "年齢の条件を選択してください";
        }
        elseif(empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 1){
          $users = $query->where('age','>=', $keyword_age)->get();
          $message = $keyword_age. "歳以上の検索が完了しました";
        }
        elseif(empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 2){
          $users = $query->where('age','<=', $keyword_age)->get();
          $message = $keyword_age. "歳以下の検索が完了しました";
        }
        elseif(!empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 1){
          $users = $query->where('name','like', '%' .$keyword_name. '%')->where('age','>=', $keyword_age)->get();
          $message = "「".$keyword_name . "」を含む名前と". $keyword_age. "歳以上の検索が完了しました";
        }
        elseif(!empty($keyword_name) && !empty($keyword_age) && $keyword_age_condition == 2){
          $users = $query->where('name','like', '%' .$keyword_name. '%')->where('age','<=', $keyword_age)->get();
          $message = "「".$keyword_name . "」を含む名前と". $keyword_age. "歳以下の検索が完了しました";
        }
        elseif(empty($keyword_name) && empty($keyword_age) && $keyword_sex == 1){
          $users = $query->where('sex','男')->get();
          $message = "男性の検索が完了しました";
        }
        elseif(empty($keyword_name) && empty($keyword_age) && $keyword_sex == 2){
          $users = $query->where('sex','女')->get();
          $message = "女性の検索が完了しました";
        }
        else {
          $users = null;
          $message = "検索結果はありません。";
        }

        return  [$users,$message];
}

}

```

#コントローラーを編集

```php:app/Http/Controllers/UsersController.php
class UsersController extends Controller
{
    //
    public function index() {
      $users = User::all();
      return view('index')->with('users', $users);
    }

    public function serch(Request $request) {
      $keyword_name = $request->name;
      $keyword_age = $request->age;
      $keyword_sex = $request->sex;
      $keyword_age_condition = $request->age_condition;

      list($users,$message) = Serch::serch($keyword_name,$keyword_age,$keyword_sex,$keyword_age_condition);

      return view('/serch')->with([
        'users' => $users,
        'message' => $message,
      ]);

}
}
```

#サービスプロパイダーとエイリアスの登録

```php:config/app.php
'providers' => [
    App\Providers\SerchServiceProvider::class,



    'aliases' => [
        'Serch' => App\Facades\Serch::class,

.
.


```





#終了です。