いやはや、今までフルスクラッチもしくは、巷で言われるオレオレフレームワークでしか構築したことがなかったのでLaravelの簡単便利さには驚いてばかりです。
はじめてのLaravelなので、調べるのに時間がかかっているけど、これ、極めたらフルスクラッチで何かを作るってことがばかげたことに思えるようになるんだろうな。いやもうすでになってるか。
フルスクラッチだと無駄に工数がかかってお客様にも予算的な無駄を強いることになることになるわけで、ああ、ああ、なんか妙なプライドからフルスクラッチにこだわってきた自分に早く教えてあげたかった。
まだ使い始めなのでデメリット的なことはあんまりわからないけど、デメリットさえもカバーできるようなLaravel使いになりたいものです。
さて、表題の並び替え。
これあっという間にできてしまって驚きを隠せません。
よくある顧客一覧や商品一覧テーブル(html的な)のthなんかにリンクを設置して並び替えるアレです。
ちまちまとコーディングする必要も、sqlいじることも、getデータをバリデートして加工して、リンク生成してってしなくてもいいんです。
プラグイン?パッケージ?をインストールして少しコードを追加するだけ。
ああ、神様。
作業工数で言うと、20分の1、いやもっとかもしれない。
ということで、備忘録として残しておきます。
column-sortableパッケージをコンポーザーからインストール
composer require kyslik/column-sortable
これで待つだけ。
エラーは出なかった。
config.app.phpにサービスプロバイダ、エイリアスを追加する
//config/app.php
'providers' => [
....
Kyslik\ColumnSortable\ColumnSortableServiceProvider::class,
]
.....
ソートをしたいDBモデルに必要な追記をする
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Kyslik\ColumnSortable\Sortable;//追記
class Modelname extends Model
{
use Sortable;//追記
protected $fillable = [ 'companyname_kana','email','status' ];
public $sortable = ['id','companyname_kana','email','status'];//追記(ソートに使うカラムを指定
bladeにリンクを設置
<th>@sortablelink('companyname_kana', '会社名')</th>
<th>@sortablelink('pref', '都道府県')</th>
こんな感じで設置
アイコンの設定なんかもしましょう。
ページャーを設置している場合は、ページャーにも並び替えクエリを追加しておきます
{{!! $list->links() !!}}
{{ $list->appends(request()->query())->links() }}
なんとこれだけでソート機能が簡単につけられてしまう!!!!!!!
fontawesomeのアイコンが出ません!
もともとの設定ファイルでは、
fa fa-sort-numericというclass名に
‘asc_suffix’ => ‘-asc’,
‘desc_suffix’ => ‘-desc’,
というsuffixが付与されてそれぞれ降順・昇順のアイコンが出るようになっている。
だけど、fontawesome5から、-asc、-descではなく、-up、-downになっていて廃止されているためアイコンがでない。
ならば、この設定を変えようか。。。ともっても設定ファイルはプロジェクトにはなくて・・・どうするねんと思ったら、
php artisan vendor:publish --provider="Kyslik\ColumnSortable\ColumnSortableServiceProvider" --tag="config"
というコマンドで、config/以下に設定用ファイル(columnSortable.php)がコピーされる。
これで、columnSortable.phpの上記部分を
‘asc_suffix’ => ‘-up’,
‘desc_suffix’ => ‘-down’,
に変更すれば、アイコンがちゃんとでてくる。
利用するclassはカラムごとに指定できる
あれ?思ったようにアイコンがでないけど?
と思ったら、columnSortable.phpの一番最初にあるcolumnsに、利用するclassが指定できる。
alphaはa-z、amountは量、numericは数値のアイコンで、
各rowsには、カラム名を記入していく。
複雑になればなるほどデータベース設計とか命名規則とかしっかりせねばなと思う。
'columns' => [
'alpha' => [
'rows' => ['description', 'email', 'name', 'slug'],
'class' => 'fa fa-sort-alpha',
],
'amount' => [
'rows' => ['amount', 'price'],
'class' => 'fa fa-sort-amount',
],
'numeric' => [
'rows' => ['created_at', 'updated_at', 'level', 'id', 'phone_number'],
'class' => 'fa fa-sort-numeric',
],
],
日本語とかの場合は適切なアイコンがないからデフォルトのfa-sort-up、fa-sort-down、つまりは上記のcolumnsには何も指定しない感じで使おう。
カラムを結合して並び替える方法
例えば、姓・名に分かれたカラムをガッチャンコして並び替えたりといったときに使える方法。
モデルにメソッドを追加することでマルチカラムソートが可能
メソッド名がxxxSortableとなるように作る。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Kyslik\ColumnSortable\Sortable;//追記
class Modelname extends Model
{
use Sortable;//追記
protected $fillable = [ 'companyname_kana','email','status' ];
public $sortable = ['id','companyname_kana','email','status'];//追記(ソートに使うカラムを指定
//姓(セイ)・名(メイ)で分かれているカラムをつなげてマルチソートに
public function unionNameSortable($query, $direction){
return $query->orderBy('lastname_kana', $direction)->orderBy('firstname_kana', $direction);
}
blade側では、Sortableを除いたメソッド名で指定する。
<th>@sortablelink('unionName', '氏名')</th>
ソートその2リレーション先の情報でソート「witchCountでとった数値でソート」
リレーション先に登録されている件数をwithCountで取得して、その値をもとにSortableでソートしたい。
具体的には動画リストがあって、気に入った動画を各ユーザーがお気に入りに入れるといった場合。
お気に入りは動画テーブルとユーザーテーブルの中間テーブルとして存在している。
中間テーブルの登録件数でソートしたい。
$list = Movie::sortable()->withCount('user')->paginate(30);
一覧用のデータ自体はこのようにして取得できる。
withCountはカラム名がuser_countといった風に、後ろに_countが付く形になる。
フロント側(blade)で
<tr>
<th>@sortablelink('id', 'ID')</th>
<th>お気に入り</th>
@foreach($list as $val)
<tr>
<td>{{ $val->id }}</td>
<td>{{ $val->user_count }}</td>
</tr>
@endforeach
こんな風にして表示できる。
で、肝心のお気に入り数での並び替えは、
<tr>
<th>@sortablelink('id', 'ID')</th>
<th>@sortablelink('user_count', 'お気に入り')</th>
@foreach($list as $val)
<tr>
<td>{{ $val->id }}</td>
<td>{{ $val->user_count }}</td>
</tr>
@endforeach
でよさそうだけど、これだと並び替えを行ったときにエラーになる。
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'movies.user_count' in 'order clause' (SQL: select `movies`.*, (select count(*) from `users` inner join `movie_user` on `users`.`id` = `movie_user`.`user_id` where `movies`.`id` = `movie_user`.`movie_id`) as `user_count` from `movies` order by `movies`.`user_count` desc limit 30 offset 0)
movies.user_countというカラムはありませんよと。ないカラムでの並び替えはできませんよ。と。
Column Sortableではカラム名の前にmovies.とテーブル名がついてしまうため、サブクエリの結果としてuser_countという別名でmovies.user_countはないよ、ってことですね。
blade側で調整できないものかとやってみましたがマルチソートの時と同じく、model側にクエリを加えることで解決することに。
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Kyslik\ColumnSortable\Sortable;
class Movie extends Model
{
//
use Sortable; //ソートクラス
public $sortable = ['id','title','material','category_id','creator_id','duration','public','user_count']; //ソート対象指定
//このメソッドを追加
public function userCountSortable($query, $direction)
{
return $query->orderBy('user_count', $direction);
}
...
この追加したメソッドuserCountSortableをblade側から指定すればOK
<tr>
<th>@sortablelink('id', 'ID')</th>
<th>@sortablelink('userCount', 'お気に入り')</th>
@foreach($list as $val)
<tr>
<td>{{ $val->id }}</td>
<td>{{ $val->user_count }}</td>
</tr>
@endforeach
参考サイト
設置方法
https://www.nicesnippets.com/blog/laravel-6-column-sorting-with-pagination-example
マルチソート
https://qiita.com/haserror/items/3d88bdb6fc5d08019fe8
めちゃくちゃ助かりました!
ありがとうございます!!
コメントを残す