概要
モデルをget()後に加工しなければならないのためのメモ。
eagerロードの制約を加えた値は動的プロパティを使わないと受け取れないので、コレクションを活用して加工など行う必要がある。
備忘録。
laravel 6.X
リレーション先の先の条件
fillter()を使う
ビューでクエリを行わずに、制約をかけた後のデータを渡すとスマートで安心する。
// ある記事に紐づく、公開中の評価がついた公開中のコメントが欲しい
// 制約をかける
$article->load([
'comments' => function ($query) {
$query->where('is_public', 1);
},
'comments.ratings' => function ($query) {
$query->where('is_public', 1);
}
]);
$commnts = $article->comments->filter(function ($comment, $key) {
// 動的プロパティでアクセス
return $comment->ratings->count() > 0;
});
reject()
除去する条件を入れる
$commnts = $article->comments->reject(function ($comment, $key) {
return $comment->ratings->count() === 0;
});
コレクションを合成する
concat()で他のモデルから取得したget()と合成する
ちなみに中身はコレクションをforeachで回して、push()しているだけのようです。
なので
$articles = collect(\App\Models\Article::public()->take(3)->get());
$concat = $articles->concat(
\App\Models\Service::query()->take(5)->get()
);
slice()を使ってページング
Illuminate\Pagination\LengthAwarePaginato
はページング対象引数をコレクションで取ることが出来るので、合成後のコレクションで独自にページネーション出来る。
$offset = ($page * $limit) - $limit;
$slice = $concat->slice($offset, $limit);
$paginate = new LengthAwarePaginator($slice, count($concat), $limit, $page);
(仕様に従ってみましたが、これはsliceせずにどうにかならないんでしょうか....)
追記
@nunulk さんにコメント頂き追記
forPage()を使ってスマートになりました。
$paginate = new LengthAwarePaginator($concat->forPage($page, $limit), count($concat), $limit, $page);