laravel8のhasmanyでgroupbyしたいけど、メソッドが存在しないので、アクセサ(getカラム名or好きな名前Attribute)でgroupbyしてみた。
旧システムから移植する時に、操作ログをhasmanyで持たせたいのだが、ログが大量にあるので
日付毎・種別毎で、一番新しいログだけ表示したい。
laravelのアクセサの説明
モデルのカラムにアクセスしたい時に、何らかの処理を自動化したい時に使う(nameに様をつけるとか)
モデルに、getカラム名Attributeというメソッドを記述すると、取得する時に自動的にコールされる。
User.php
1 2 3 4 5 |
public function getNameAttribute($value) { // 名前に必ず「様」を付けた状態で返される。 return $value . '様'; } |
カラム名以外も独自の項目が追加したり、リレーションも使えたりする
User.php
1 2 3 4 |
public function getAllPostAttribute() { return "{$this->name} さんの投稿一覧: {$this->posts}"; } |
1 2 3 4 5 |
// name様は自動的に付与されるけど $user = User::find(1); // カラム名以外も独自項目は、明示的にコールしないと駄目! return $user->AllPost; |
モデル取得したら自動的に取得して欲しいので
存在しないカラムを、モデルにappendsで追加する
User.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// この更新履歴は、日時別・種類別でgroup byして最新のだけ表示したい protected $appends = ['history_logs']; public function getHistoryLogsAttribute() { // hasmanyは使わずに、ここでgroup byして返す。 return HistoryLog::where('user_id', $this->id) // 指定した期間だけ ->where(DB::raw('DATE(check_date)'), '<=', $this->check_date) // 日時別・種類別 ->groupBy(DB::raw('DATE(created_at)'), 'history_message_kind') // group by しているのでmax()で最新レコードを取得 ->select( DB::raw('max(id) as id'), DB::raw('max(history_message) as history_message'), DB::raw('max(check_date) as check_date'), DB::raw('max(created_at) as created_at'), DB::raw('max(updated_at) as updated_at') ) ->orderBy('updated_at','desc')->get(); } |
これで、普通にeloquentモデルを取得すれば、普通のカラムと同じ感じでhistory_logsで取得できる。
hasmanyとwithは不要!