LoginSignup
0
0

More than 5 years have passed since last update.

Laravelでpagination用Link headerに対応する

Last updated at Posted at 2018-12-07
  • 初版:2018.12.7
  • laravel-5.7, php-7.2

APIなどでページングデータを返却jsonに含めずヘッダに載せる場合はLinkを使うことが多い。その対応。

Responseマクロを書いて返却データを修正する

app/Providers/AppServiceProvider.php
<?php

use Illuminate\Support\ServiceProvider;

use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Response;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Response::macro('jsonpage', function ($coll) {
            $linkUrls = [];
            // Laravelに沿った開発をしている場合
            if ($coll instanceof ResourceCollection && $paginated = $coll->toArray()) {
                // Illuminate\Http\Resources\Json\ResourceCollectionを継承したコレクション(*1)に
                // paginateなコレクション(*2)を渡してる場合
                // *1 https://readouble.com/laravel/5.7/ja/eloquent-resources.html#pagination
                // *2 https://readouble.com/laravel/5.7/ja/pagination.html
                if (isset($paginated['first_page_url'])) {
                    $linkUrls = [
                        'first' => $paginated['first_page_url'] ?? null,
                        'last' => $paginated['last_page_url'] ?? null,
                        'prev' => $paginated['prev_page_url'] ?? null,
                        'next' => $paginated['next_page_url'] ?? null,
                    ];
                    // Linkヘッダ使うんだしwrappingははずしたい
                    $coll->withoutWrapping();
                }
            }

            // custom実装(案)
            if (empty($linkUrls)) {
                switch ($this->pattern) {
                    // Laravelパジネーションを使う場合こんな感じ
                    // https://github.com/laravel/framework/blob/9f313ce9bb5ad49a06ae78d33fbdd1c92a0e21f6/src/Illuminate/Pagination/LengthAwarePaginator.php#L41
                    case 'laravel':
                        $total = 1000;
                        $perPage = 10;
                        $currentPage = 2;
                        $options = [];
                        $pagination = new LengthAwarePaginator($coll, $total, $perPage, $currentPage, $options);
                        $paginated = $pagination->toArray();
                        if (isset($paginated['first_page_url'])) {
                            $linkUrls = [
                                'first' => $paginated['first_page_url'] ?? null,
                                'last' => $paginated['last_page_url'] ?? null,
                                'prev' => $paginated['prev_page_url'] ?? null,
                                'next' => $paginated['next_page_url'] ?? null,
                            ];
                        }
                        break;

                    // コレクションクラスで実装しとくとか
                    case 'original':
                        $linkUrls = $coll->getPaginatedLinks();
                        break;

                    // URLクエリだけ取得してここで組み立てるとか
                    case 'original2':
                        $url = request()->url(); // queryなし
                        $queries = $coll->getPaginationQuery();
                        // ...
                        break;
                }
            }

            // 追加レスポンスヘッダ
            $headers = [];

            // linksをレスポンスヘッダ用フォーマット
            $linkFormat = '<%s>; rel="%s"';
            $links = [];
            foreach ($linkUrls as $rel => $url) {
                if (!empty($url)) {
                    $links[] = sprintf($linkFormat, $url, $rel);
                }
            }
            if (!empty($links)) {
                $headers['Link'] = join(',', $links);
            }

            // total件数を追加する必要があれば、コレクションに件数取得するメソッド作って対応したり
            $headers['MyApp-Total-Count'] = $coll->getCustomTotal();

            return Response::json($coll, 200, $headers);
        });
    }
}

AppServiceProviderが肥大するので、専用のServiceProviderを作っても良さそう。

使うときは

app/Controllers/SomeController.php
<?php
namespace App\Http\Controllers;

class SomeController extends Controller
{
    public function index()
    {
        $list = NankanoCollection::list();
        response()->jsonpage($list);
    }
}

の様にマクロ登録した名前をメソッドにして呼び出す。

要調整、動作未確認。

0
0
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
0
0