はじめに
この記事はプログラミング初学者による備忘録用の記事であり、また、少しでも他の初学者のお役に立てればと思い書いています。
今回は、Eloquentで取得したテーブルのデータに対してページネーションの設定を試みた際に発生したエラー解決策を共有したいと思います(Qiitaで似たような記事がありそうですが、、、)。
間違いなどがございましたら、ご指摘のほどよろしくお願い致します。
結論(解決策)
/Providers/AppServiceProvider.phpでLengthAwarePaginatorのインスタンスを作成する
下記のように記述すれば、Method Illuminate\Support\Collection::paginate does not exist.を解決できます。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Collection; //追記
use Illuminate\Pagination\LengthAwarePaginator; //追記
class AppServiceProvider extends ServiceProvider
{
//略
public function boot() //下記内容を追記
{
/**
* Paginate a standard Laravel Collection.
*
* @param int $perPage
* @param int $total
* @param int $page
* @param string $pageName
* @return array
*/
Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page') {
$page = $page ?: LengthAwarePaginator::resolveCurrentPage($pageName);
return new LengthAwarePaginator(
$this->forPage($page, $perPage)->values(),
$total ?: $this->count(),
$perPage,
$page,
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
);
});
}
}
エラー原因
[Error]Method Illuminate\Database\Eloquent\Collection::paginate does not exist.
下記のように、Eloquentで取得したUserテーブルのデータに対してページネーションの設定を試みた際にエラーが発生
class UserController extends Controller
{
public function show(string $name)
{
$user = User::where('name', $name)->first()->load(['articles.user', 'articles.likes', 'articles.tags']);
$articles = $user->articles->sortByDesc('created_at')->paginate(10);
return view('users.show', compact('user', 'articles'));
}
調べてみて分かったこと
どうやらLaravelはEloquentコレクションにページネーションを提供していますが、デフォルトでは使用できないらしい。
ちなみに、コレクションにはforPage()メソッド
がありますが、ページネーションリンクは生成されず、私が求めていた機能とは異なるので使用していません。
このような場合、AppServiceProvider.phpでLengthAwarePaginatorのインスタンスを作成する
必要があることがわかりました。
Eloquentのコレクションと同じ動作をさせたい場合,結論で述べたコードを記述することで可能になるとのこと。
構文と出力がEloquent Collectionのpaginate()メソッドとほぼ同じなので、テストの際に(比較的)簡単にEloquent Collectionと入れ替えることができるそうです。便利そうですね。
補足1
URLに追加するクエリパラメータを渡す必要がある場合は、下記のようにパラメータの配列を追加することで可能になります。
before
Collection::macro('paginate', function($perPage, $total = null, $page = null, $pageName = 'page') {
//略
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
]
after
Collection::macro('paginate', function ($perPage, $total = null, $page = null, $pageName = 'page', $queryParams = []//追記) {
//略
[
'path' => LengthAwarePaginator::resolveCurrentPath(),
'pageName' => $pageName,
'query' => $queryParams //追記
]
補足2
今回記述したコードは、基本的に好きな場所に置くことができます。ここでは、AppServiceProvider.phpに入れてエラーを解決していますが、理由としてはほとんどのLaravelアプリケーションがデフォルトでAppServiceProvider.phpが存在しているからです。
参考文献