LoginSignup
1
0

More than 1 year has passed since last update.

laravel8で複合検索

Last updated at Posted at 2022-01-23

はじめに

複合検索のメソッドを忘備録としてメモしておきます。

View

Viewファイルに
・検索フォーム
・ソートリンク付きテーブルヘッダー
・一覧表示テーブル
を用意する。

blade.php

{!! Form::open(array('url' => '/user/list', 'method' => 'get', 'id'=>'form')) !!}

{{ Form::label('section_id','部署名') }}
{{ Form::select('section_id', config('const.section_name'), old('section_id'), ['class' => 'form-control', 'placeholder' => '選択してください']) }}

{{ Form::label('name','名前') }}
{{ Form::text('name', '', ['class' => 'form-control', 'placeholder' => '氏名']) }}

{{ Form::label('login_id','ログインID') }}
{{ Form::text('login_id', '', ['class' => 'form-control', 'placeholder' => 'ログインID(メールアドレス)']) }}

{{ Form::submit('送信', ['class'=>'btn btn-primary btn-block']) }}

{!! Form::close() !!}

----------------------------------------------------------------------

    <div class="card-body p-0 table-responsive">
        <table id="user-master" class="table table-bordered table-striped">
            <thead>
                <tr>
                    <th class="sorting"><a href="{{ Request::getSortLink('section_id') }}">部署名</a></th>
                    <th class="sorting"><a href="{{ Request::getSortLink('name') }}">氏名</a></th>
                    <th class="sorting"><a href="{{ Request::getSortLink('login_id') }}">ログインID(メールアドレス)</a></th>
                </tr>
            </thead>
            <tbody>
                @foreach($userList as $user)
                    <tr>
                        <td>{{ config('const.section_name')[$user->section_id] }}</td>
                        <td>{{ $user->name }}</td>
                        <td>{{ $user->login_id }}</td>
                    </tr>
                @endforeach
            </tbody>
        </table>
    </div>
    <div class="card-footer clearfix text-right">
        {{ $userList->appends($conditions)->links('vendor.pagination.default') }}
    </div>

↑レイアウトは適当です。

ソートボタンのリンク(URL)生成

まずはソートのリンクを生成する処理を作ります。

src/app/Http/Request.php
<?php

namespace App\Http;

use Illuminate\Http\Request as BaseRequest;

class Request extends BaseRequest
{

    public function getSortLink($key)
    {
        $orderBy = $this->orderby;
        $sort    = $orderBy == $key && $this->sort == 'desc' ? 'asc' : 'desc';
        $tmp     = $this->fullUrlWithQuery(['orderby' => $key, 'sort' => $sort]);

        return $outputUrl;
    }
}

リンクをクリックするとasc⇄descの切り替えをするようにしています。

Controller

UserController.php
    /**
     * ユーザー一覧
     * @return type
     */
    public function index(Request $request)
    {
        // ログインユーザーを取得する。
        $userSet = Auth::user();

        $conditions = $request->all(); //ここで検索したGETパラメータを配列で受け取る
        $orderby    = $request->orderby ?: 'section_id'; //ソートするカラムを取得デフォは部署
        $sort       = $request->sort ?: 'asc'; //昇順・降順をセットする
        $users      = User::searchByConditions($conditions);
        $userList   = $this->setOrderBy($users, $orderby, $sort)->paginate(config('const.paginate.user'))->setPath('/user');

        $requestData = compact(
            'userSet',
            'conditions',
            'users',
            'userList'
        );
        return view('user.index', $requestData);
    }

    /**
     * orderByをセット
     * (ソート機能の内部処理をここに実装)
     * @param query $query
     * @param type $orderby
     * @param type $sort
     * @return query
     */
    public static function setOrderBy($query, $orderby, $sort)
    {
        switch ($orderby) {
            default:
                $query = $query->orderBy($orderby, $sort);
                break;
        }
        return $query;
    }

このsetOrderByですが、もし、カラム名がinputのname要素と一致しない場合や他テーブルを参照する必要がある場合はcase文をしてやる必要があります。
たとえばこんな感じに。

        switch ($orderby) {

            //inputのnameは'login_id'だが、DBのカラム名は'mail'の場合
            case 'login_id':
                $query = $query->orderBy('mail', $sort);
                break;

            //articlesテーブルのtitleで検索する場合(Viewは割愛してます)
            case 'title':
                $query = $query->leftJoin('articles', 'users.id', '=', 'articles.user_id')
                    ->orderby('articles.title', $sort);
                break;

            default:
                $query = $query->orderBy($orderby, $sort);
                break;

        }

Model

User.php

    /**
     * 検索項目定義
     * @var varchar
     */
    public static $searchableFields = [
        'section_id', //部署名
        'name', //氏名
        'login_id', //ログインID
    ];

    /**
     * 検索処理
     * @param array $conditions 検索条件
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function searchByConditions($conditions)
    {
        //withにリレーション追記
        $query = self::select('users.*');

        foreach ($conditions as $key => $value) {

            if (!in_array($key, self::$searchableFields) || !isset($value)) {
                continue;
            }
            switch ($key) {
                case 'name':
                case 'login_id':
                    $query = $query->where($key, 'LIKE', '%' . $value . '%');
                    break;
                default:
                    $query = $query->where($key, '=', $value);
                    break;
            }
        }
        return $query;
    }

ここで出てくるsearchByConditions($conditions)でController側の$conditionsに入れたGETパラメータの配列をforeachで回します。
そして、keyであるinputのname要素を基準にusersテーブル内をwhereで検索していき、最終的に$queryに検索にひっかかったデータ群のみが残るようになります。

ここでもし、inputのnameと実際のカラム名が異なる場合、また、users以外のテーブルから検索する場合の処理を例として記載しておくと、

User.php

    /**
     * 検索項目定義
     * @var varchar
     */
    public static $searchableFields = [
        'section_id', //部署名
        'name', //氏名
        'login_id', //ログインID
        'title' //投稿記事タイトル(追加)
    ];

    /**
     * 検索処理
     * @param array $conditions 検索条件
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function searchByConditions($conditions)
    {
        $query = self::select('users.*')->with('articles');

        foreach ($conditions as $key => $value) {

            if (!in_array($key, self::$searchableFields) || !isset($value)) {
                continue;
            }
            switch ($key) {
                case 'name':
                   $query = $query->where($key, 'LIKE', '%' . $value . '%');
                    break;

                //inputのnameは'login_id'だが、DBのカラム名は'mail'の場合
                case 'login_id':
                    $query = $query->where('mail', 'LIKE', '%' . $value . '%');
                    break;

                //articlesテーブルのtitleで検索する場合(Viewは割愛してます)
                case 'title':
                    $query->whereHas('articles', function ($query) use ($key, $value) {
                        $query->whereIn($key, $value);
                    });
                    break;

                default:
                    $query = $query->where($key, '=', $value);
                    break;
            }
        }
        return $query;
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0