ページネーション

記事の内容

概要

ページネーションは、データを自動的に分割し、シンプルなページリンクを生成するために使用されます。

【コントローラー】

$items = Item::paginate(件数); 

【view】Tailwind CSS

{{ $items->links() }}

【view】Bootstrap 4

{{ $items->links('pagination::bootstrap-4') }}

【view】Bootstrap 5

{{ $items->links('pagination::bootstrap-5') }}

Tailwind CSSかBootstrapをインストールした方を使用

ソース例

【コマンド】Migration・Model・Factory・Seederファイル作成

php artisan make:model Item -mfs

【ファイル先】database/migrations/2024_01_01_065715_create_items_table.php

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration {
    public function up(): void
    {
        Schema::create('items', function (Blueprint $table) {
            $table->id();
            $table->string('name'); // 追加
            $table->text('description')->nullable(); // 追加
            $table->timestamps();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('items');
    }
};

【ファイル先】app/Models/Item.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Item extends Model
{
    use HasFactory;

    /**
     * 複数代入を許可するカラム
     *
     * @var array<int, string>
     */
    protected $fillable = ['name', 'description'];
}

【ファイル先】database/factories/ItemFactory.php

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

class ItemFactory extends Factory
{
    /**
     * モデルに関連するデフォルトの状態を定義
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'name' => $this->faker->word(), // 商品名としてランダムな単語を生成
            'description' => $this->faker->sentence(), // 商品説明としてランダムな文章を生成
        ];
    }
}

【ファイル先】database/seeders/ItemSeeder.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\Item;

class ItemSeeder extends Seeder
{
    /**
     * データベースにダミーデータを挿入
     *
     * @return void
     */
    public function run(): void
    {
        // 50件のダミーデータを生成
        Item::factory()->count(50)->create();
    }
}

【ファイル先】routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ItemController;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/items', [ItemController::class, 'index'])->name('items.index');

【ファイル先】resources/views/items/index.blade.php

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Items List</title>
</head>

<body>
    <h1>Items List</h1>

    @foreach ($items as $item)
        <div>
            <h2>{{ $item->name }}</h2>
            <p>{{ $item->description }}</p>
        </div>
    @endforeach

    <!-- ページネーションリンク(Tailwind CSS) -->
    {{ $items->links() }}
</body>
</html>

【コマンド】

// テーブル作成
php artisan migrate
// 仮データ50件投入
php artisan db:seed --class=ItemSeeder

http://localhost/itemsで確認してみましょう。

色々なページネーション

シンプル

シンプルな「前へ」「次へ」リンクのみを提供するページネーションを行います。

【コントローラー】

$items = Item::simplePaginate(件数);

カスタムページ

カスタムビューで表示する場合、links メソッドにカスタムビューを指定します。

【コマンド】

php artisan vendor:publish --tag=laravel-pagination

resources/views/vendor/pagination配下にファイルが作成される
※BootstrapやTailwind CSSを少しアレンジしたい場合にも有効

【view】

{{ $items->links('vendor.pagination.custom') }}

【ページネーションのデザイン】

.pagination {
    display: flex;
    list-style: none;
    padding: 0;
}

.pagination li {
    margin: 0 5px;
}

.pagination li a {
    padding: 8px 12px;
    border: 1px solid #ddd;
    text-decoration: none;
    color: #007bff;
}

.pagination li a:hover {
    background-color: #007bff;
    color: white;
}

.pagination .active span {
    background-color: #007bff;
    color: white;
    padding: 8px 12px;
    border: 1px solid #007bff;
}

URLにクエリパラメータを追加

追加のクエリパラメータを付加したい場合、appends メソッドを使用します。
※検索条件やソート順を保持

【view】

{{ $items->appends(request()->query())->links() }}

ページリンクに ?key1=value1&key2=value2&page=2 のようなURLが生成

【ファイル先】app/Http/Controllers/ItemController.php

<?php

namespace App\Http\Controllers;

use App\Models\Item;
use Illuminate\Http\Request;

class ItemController extends Controller
{
    /**
     * 商品一覧を表示する
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\View\View
     */
    public function index(Request $request)
    {
        // クエリビルダーを利用して、Itemモデルのデータを取得するための準備
        $query = Item::query();

        // 検索条件が入力されている場合、その条件でデータを絞り込む
        if ($request->filled('search')) {
            $search = $request->search;
            // 検索条件を指定して、name か description にキーワードが含まれるデータを取得
            $query->where(function ($query) use ($search) {
                $query->where('name', 'like', '%' . $search . '%')
                      ->orWhere('description', 'like', '%' . $search . '%');
            });
        }

        // ソートの順番(昇順か降順か)を指定。デフォルトでは昇順(asc)
        $sortOrder = $request->get('sort', 'asc');
        // name列に基づいて指定された順序でデータを並べ替える
        $query->orderBy('name', $sortOrder);

        // ページネーションを適用して、1ページあたり10件のデータを取得
        $items = $query->paginate(10);

        // 取得したデータをビュー(items/index.blade.php)に渡して表示
        return view('items.index', compact('items'));
    }
}

【ファイル先】resources/views/items/index.blade.php

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Items List</title>
</head>

<body>
    <h1>Items List</h1>

    <!-- 検索フォーム -->
    <form action="{{ route('items.index') }}" method="GET">
        <input type="text" name="search" value="{{ request('search') }}" placeholder="検索キーワード">

        <!-- ソートの選択 (昇順・降順) -->
        <select name="sort" onchange="this.form.submit()">
            <option value="" disabled selected>ソート順を選択</option>
            <option value="asc" {{ request('sort') == 'asc' ? 'selected' : '' }}>昇順</option>
            <option value="desc" {{ request('sort') == 'desc' ? 'selected' : '' }}>降順</option>
        </select>

        <button type="submit">検索</button>
    </form>

    <!-- アイテムリスト -->
    @foreach ($items as $item)
        <div>
            <h2>{{ $item->name }}</h2>
            <p>{{ $item->description }}</p>
        </div>
    @endforeach

    <!-- ページネーションリンク -->
    {{ $items->appends(request()->query())->links() }}

</body>

</html>

ページ番号の周辺リンク数調整

中央時のページリンクの前後リンクをonEachSide メソッドで調整できます。
※デフォルトでは前後に3つずつのリンク

【view】

{{ $items->onEachSide(数値)->links() }}

【onEachSide(2)の場合】
1 … 6 7 [8] 9 10 … 15

【onEachSide(4)の場合】
1 … 4 5 6 7 [8] 9 10 11 12 … 15

データを配列取得

ページネーション結果を配列として取得するには、toArray メソッドを使用します。
※カスタムビューやAPIレスポンスに使用

【コントローラー】

$paginationData = $items->paginate(10)->toArray();

名前付きページネーション

複数のページネーションを同じ画面で使う際、それぞれ独立したクエリパラメータ名を付ける方法です。
withQueryString は、現在のクエリパラメータをページネーションリンクに引き継ぐ

【コントローラー】

// 商品一覧のページネーション
$items = Item::paginate(10, ['*'], 'items_page');

// ユーザー一覧のページネーション
$users = User::paginate(5, ['*'], 'users_page');

第一引数 : 1ページあたりに表示するアイテム数
第二引数 : 取得するカラムを指定
第三引数 : ページネーションのクエリパラメータ名を指定

【view】

@foreach ($items as $item)
    <div>
        <h2>{{ $item->name }}</h2>
        <p>{{ $item->description }}</p>
    </div>
@endforeach

<!-- 商品一覧のページネーション -->
{{ $items->withQueryString()->links() }}

@foreach ($users as $user)
    <div>
        <h2>{{ $user->name }}</h2>
        <p>{{ $user->email }}</p>
    </div>
@endforeach

<!-- ユーザー一覧のページネーション -->
{{ $users->withQueryString()->links() }}

ページリンクに ?users_page=5&items_page=4のようなURLが生成

記事の内容
閉じる