Larabelのcolumn-sortable使い方Tip
お疲れ様です。新人エンジニアのtelluruです。技術記事第一弾はLarabelの実装でお世話になったcolumn-sortableの使い方のメモを記します。
導入
まずはcomposerからcolumn-sortableをインストール。
composer require kyslik/column-sortable
次にコンフィグファイルを追加。
php artisan vendor:publish --provider="Kyslik\ColumnSortable\ColumnSortableServiceProvider" --tag="config"
実装
基本的な使い方。
Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Kyslik\ColumnSortable\Sortable; //追加
class Staff extends Authenticatable
{
use Sortable; //追加
public $sortable = ['staff_name']; //ソート対象指定
}
Controller
class JobListController extends Controller
{
public function index(Request $request)
{
$joblist = Staff::select([
'staff.staff_id'
'staff.staff_name'])
->sortable() //これを挟むだけ
->orderBy('staff.staff_id', 'desc')
->paginate(20);
}
}
この時sortableを挟む位置はjoinの後、条件式(where)やソート(orderBy)の前に入れる。場所を間違えるとうまく動作してくれない。ソートのSQLを見るとsortableの位置にorderBy句を入れて再検索するようだ。
View
<th class="back" scope="col" style="white-space:nowrap;">
@sortablelink('staff_name', '登録者') //追加
</th>
@sortablelink('取得カラム名','表示する名前')でソートリンクを作ってくれる。
//HTMLのすがた
<th class="back1" scope="col" style="white-space:nowrap;">
<a href="http://localhost:3306/hoge/jobList?sort=staff_name&direction=desc">登録者</a>
<i class="fa fa-sort-asc"></i>
</th>
別名を付けたカラムでSorting
As句で名前を付けると基本の使い方ではカラムを認識してくれない。joinで別名を付けたテーブルを使用する場合も同様。なので別名をモデルに宣言する必要がある。宣言にはsortableの代わりにsortableAsを使う。
public $sortableAs = ['sm_name']; //staff_name as sm_name
joinしたテーブルのカラムでSorting
上記の別名カラムソートを使うとjoinした先のカラムにソートを付けることができる。
Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Kyslik\ColumnSortable\Sortable;
class Job extends Model
{
use Sortable;
public $sortable = ['job_id', 'job_name', 'job_kind', 'in_id', 'in_date'];
public $sortableAs = ['sm_name'];
public function staffNameSortable($query, $direction)
{
return $query->leftjoin('staff', 'job.in_id', 'staff.staff_id')
->orderBy('sm_name', $direction);
}
}
結合される側のモデルに結合するjoin句とorderBy句、カラムの別名を記述する。例の場合JobテーブルにStaffテーブルを左結合するのでJob側のモデルにjoin句を記述することになる。join句とorderBy句は’(任意の英数字)Sortable’という名前でメソッドを作ればsortableをオーバーライドできるので、その中に記述。
Controller
$joblist = JobMaster::select([
'job_id',
'job_name',
'job_kind',
'in_id',
'job.in_date',
'sm.staff_name as sm_name'])
->leftjoin('staff as sm', 'job.in_id', 'sm.staff_id')
->sortable('sm_name')
->orderBy('job.job_id', 'desc')
->paginate(20);
sortableの中に配列で名前を変えたカラムを列挙する。複数ある場合は配列にする。
【2020/01/31追記】
上記をしなくてもソーティング機能は実装できる。上記をした場合初期表示でソートがかかる。
View
<th class="back1 " scope="col" style="white-space:nowrap;">
@sortablelink('job_id', 'ID')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('job_name', 'ジョブ名')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('job_kind', '種別')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
メモ
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('sm_name', '登録者')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('in_date', '登録日時')
</th>
変えた名前でカラム指定する。
複雑なクエリのカラムをSorting
上記の応用を使用すると複雑なクエリを発行したときもソート機能を付けられる。
Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Kyslik\ColumnSortable\Sortable;
class OutList extends Model
{
use Sortable;
public $sortableAs = ['co_id', 'w_cnt', 'output_cnt', 'co_name','jm_id','jm_name'];
public function companySortable($query, $direction)
{
return $query->orderBy('co_id', $direction);
}
public function wSortable($query, $direction)
{
return $query->orderBy('w_cnt', $direction);
}
public function companyNameSortable($query, $direction)
{
return $query->leftjoin('company as cm', 'out_list.company_id', 'cm.company_id')
->orderBy('co_name', $direction);
}
public function jobIdSortable($query, $direction)
{
return $query->leftjoin('job as jm', 'out_list.job_id', 'jm.job_id')
->orderBy('jm_id', $direction);
}
public function jobNameSortable($query, $direction)
{
return $query->leftjoin('job as jm', 'out_list.job_id', 'jm.job_id')
->orderBy('jm_name', $direction);
}
}
Controller
$child_jobs = OutList::select(
'otl.company_id as co_id',
'cm.company_name as co_name',
'jm.job_id as jm_id',
'jm.job_name as jm_name',
)
->selectSub(OutList::selectRaw('count(*)')
->fromSub(OutList::select('member_id', 'company_id', 'job_id')
->where('parent_job_id', $parent_job_id)
->where('output_flg', 1)
->groupBy('member_id', 'company_id', 'job_id'), 'otl_s2')
->whereColumn('otl.company_id', 'otl_s2.company_id'), 'w_cnt')
->fromSub(OutList::select('member_id', 'company_id', 'job_id')
->where('parent_job_id', $parent_job_id), 'otl')
->leftjoin('job_master as jm', 'otl.job_id', 'jm.job_id')
->leftjoin('company as cm', 'otl.company_id', 'cm.company_id')
->sortable(['co_id', 'w_cnt', 'co_name', 'jm_id', 'jm_name'])
->groupby('jm.job_id')
->paginate(20);
※distinctはLarabelのpagenationと相性が悪いらしく、totalが重複排除されずカウントされてしまうので代わりにgroupByを使用している。
View
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('co_id', '企業ID')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('co_name', '企業名')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('w_cnt', '件数')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('jm_id', 'ジョブID')
</th>
<th class="back1" scope="col" style="white-space:nowrap;">
@sortablelink('jm_name', 'ジョブ名')
</th>
こんな感じでCountしたカラムにソートを付けることもできる。