16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

LaravelのpaginationをSQL直接実行で利用する

Last updated at Posted at 2022-08-01

はじめに

Laravelのpaginationを利用するにはクエリビルダまたはEloquentクエリでpaginateメソッドを使用することで簡単にできます。
しかし、何重もサブクエリを定義しているSQLをクエリビルダやEloquentクエリで記述するには困難なので直接SQLを実行したい場合があると思いますが、その場合はpaginateメソッドを使用することができません。

今回は直接SQLを実行した場合でもLaravelのpaginationを利用する方法を紹介します。

※Laravelのpaginationにはいくつか種類がありますが、今回紹介するのはpaginateメソッドで利用できるものにフォーカスしています

paginationを実現するには

paginateメソッドを実行した時の返り値はIlluminate\Pagination\LengthAwarePaginatorです。
このインスタンスがpagination機能で必要なメソッドを持っているので、SQLを直接実行して取得したデータをLengthAwarePaginatorに設定することでpagination機能を実現することができます。

LengthAwarePaginatorのインタスタンスを取得する

LengthAwarePaginatorのコンストラクタには以下の引数を設定する必要があります

item: 表示するアイテム
total: アイテムの総数
perPage: 1ページの表示数
currentPage: 現在のページ番号

上記の各値をまず取得します

// 表示アイテムを取得する為のクエリ(サンプルの為、シンプルなものにしています)
$query = 'SELECT id, name FROM users ORDER BY id';

// 現在のページ番号
$currentPage = \Illuminate\Pagination\Paginator::resolveCurrentPage();
// 1ページの表示数
$perPage = 10;
// 表示するアイテムを取得
$results = \DB::select("{$query} LIMIT :per_page OFFSET :offset", [
    'per_page' => $perPage,
    'offset' => $currentPage * $perPage - $perPage
]);

// アイテムの総数を取得
$total = \DB::selectOne("SELECT count(*) AS cnt FROM ({$query}) AS counter");

// LengthAwarePaginatorのインタスタンスを取得
$pagination = new \Illuminate\Pagination\LengthAwarePaginator(
    $results,
    $total->cnt,
    $perPage,
    $currentPage,
);

paginationのリンクにパラメーターを追加する

LengthAwarePaginatorのインタスタンスで生成されるリンク(次のページや前のページ等)にはページ番号(page)しかパラメーターが設定されていません。
リンクに任意の値を設定したい場合はLengthAwarePaginatorのコンストラクタにオプションを設定する必要があります。
以下はページ番号(page)以外のリクエストパラメーターをリンクに設定します。

$pagination = new LengthAwarePaginator(
    $results,
    $total->cnt,
    $perPage,
    $currentPage,
    [
        'path' => sprintf(
            '%s%s',
            request()->url(),
            request()->except('page')
                ? '?' . http_build_query(request()->except('page'))
                : ''
        )
    ]
);

最後に

今回はSQLを直接実行した場合でもLaravelのpaginationを利用する方法を紹介しました。
paginationはよく利用する機能なので同じインスタンスで利用できるようになれば開発の手間が軽減されます。
公式ドキュメントにも説明はありますが詳しくは書かれていないので、この記事が参考になれば幸いです。
https://readouble.com/laravel/9.x/ja/pagination.html#manually-creating-a-paginator

16
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?