はじめに
複合検索のメソッドを忘備録としてメモしておきます。
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;