【Laravel】ページネーション機能を実装する|簡単な掲示板アプリの作成

Laravelのページネーション機能を使って、掲示板の投稿一覧やコメントを複数ページに分割して表示する方法を学びます。`paginate()`メソッドでのデータ取得から、Bootstrapでデザインを整えたページリンクの表示方法までを、初心者にもわかりやすく解説します。

作成日: 更新日:

開発環境

  • OS: Windows10
  • Visual Studio Code: 1.73.0
  • PHP: 8.3.11
  • Laravel: 11.29.0
  • laravel/breeze: 2.2

サンプルコード

/app/Http/Controllers/PostController.php

/app/Http/Controllers/PostController.php
1                 break;
2         }
3 
4-        $posts = $query->get();
5+        $posts = $query->paginate(5);
6 
7         return view('posts.index', compact('posts'));
8     }
9     public function show(string $id)
10     {
11         $post = Post::with('comments.user')->findOrFail($id);
12-        return view('posts.show', compact('post'));
13+        $comments = $post->comments()->with('user')->paginate(5);
14+        return view('posts.show', compact('post', 'comments'));
15     }
16 
17     /**
18

/app/Providers/AppServiceProvider.php

/app/Providers/AppServiceProvider.php
1 namespace App\Providers;
2 
3 use Illuminate\Support\ServiceProvider;
4+use Illuminate\Pagination\Paginator;
5 
6 class AppServiceProvider extends ServiceProvider
7 {
8      */
9     public function boot(): void
10     {
11-        //
12+        Paginator::useBootstrapFive();
13     }
14 }
15

/resources/views/posts/index.blade.php

/resources/views/posts/index.blade.php
1         </div>
2     </form>
3 
4+    <!-- 投稿のリスト表示 -->
5     @foreach ($posts as $post)
6         <div class="card mb-3">
7             <div class="card-body">
8             </div>
9         </div>
10     @endforeach
11+
12+    <!-- ページネーションリンク -->
13+    <div class="d-flex justify-content-center mt-4">
14+        {{ $posts->links() }}
15+    </div>
16 @endsection
17

/resources/views/posts/show.blade.php

/resources/views/posts/show.blade.php
1 
2     {{-- コメント一覧 --}}
3     <h3>コメント一覧</h3>
4-    @if ($post->comments->isEmpty())
5+    @if ($comments->isEmpty())
6        <p>コメントはまだありません。</p>
7     @else
8-        @foreach ($post->comments as $comment)
9+        @foreach ($comments as $comment)
10             <div class="card mb-2">
11                 <div class="card-body">
12                     <p class="card-text">{{ $comment->content }}</p>
13     @else
14         <p>コメントを投稿するにはログインしてください。</p>
15     @endauth
16+
17+    {{-- コメントのページネーションリンク --}}
18+    <div class="d-flex justify-content-center mt-4">
19+        {{ $comments->links() }}
20+    </div>
21+
22 @endsection
23

コード解説

変更点: 投稿一覧をページネーションで取得

/app/Http/Controllers/PostController.php
1-        $posts = $query->get();
2+        $posts = $query->paginate(5);
3 
4         return view('posts.index', compact('posts'));
5     }

これまでデータベースから全ての投稿を取得するために使っていた get() メソッドを paginate(5) メソッドに変更しました。get() は条件に合う全てのデータを一度に取得しますが、paginate() は指定した数(この場合は5件)ごとにデータを区切って取得します。これにより、大量の投稿があってもページごとに分割して表示できるようになります。

変更点: コメント一覧をページネーションで取得

/app/Http/Controllers/PostController.php
1     public function show(string $id)
2     {
3         $post = Post::with('comments.user')->findOrFail($id);
4-        return view('posts.show', compact('post'));
5+        $comments = $post->comments()->with('user')->paginate(5);
6+        return view('posts.show', compact('post', 'comments'));
7     }

投稿詳細ページで表示するコメントの取得方法を変更しました。以前は $post->comments ですべてのコメントを取得していましたが、これだとコメントが増えた際にページの表示が遅くなる可能性があります。そこで、特定の投稿に紐づくコメントを $post->comments() という形でクエリとして取得し、それに対して paginate(5) を適用しています。これにより、コメントも1ページあたり5件ずつ表示されるようになります。取得したコメントデータは新しく $comments という変数に入れ、compact() を使ってビューに渡しています。

変更点: Paginatorクラスのインポート

/app/Providers/AppServiceProvider.php
1 namespace App\Providers;
2 
3 use Illuminate\Support\ServiceProvider;
4+use Illuminate\Pagination\Paginator;
5 
6 class AppServiceProvider extends ServiceProvider
7 {

この変更では、Laravelのページネーション機能をカスタマイズするために必要な Paginator クラスを use を使って読み込んでいます。ファイル内で外部のクラスを使用する際には、このようにファイルの先頭で「このクラスを使います」と宣言する必要があります。

変更点: ページネーションのデザインをBootstrap 5に設定

/app/Providers/AppServiceProvider.php
1      */
2     public function boot(): void
3     {
4-        //
5+        Paginator::useBootstrapFive();
6     }
7 }

Laravelが生成するページネーションリンクのHTMLデザインを、CSSフレームワークであるBootstrap 5に対応させるための設定です。AppServiceProvider.phpboot メソッドに Paginator::useBootstrapFive(); と記述することで、アプリケーション全体でページネーションのデザインが自動的にBootstrap 5のスタイルになります。boot メソッドはアプリケーションの起動時に実行されるため、ここに記述することで全体に設定が適用されます。

変更点: 投稿一覧にページネーションリンクを表示

/resources/views/posts/index.blade.php
1     @foreach ($posts as $post)
2         <div class="card mb-3">
3             <div class="card-body">
4             </div>
5         </div>
6     @endforeach
7+
8+    <!-- ページネーションリンク -->
9+    <div class="d-flex justify-content-center mt-4">
10+        {{ $posts->links() }}
11+    </div>
12 @endsection

コントローラーから渡された $posts 変数を使って、ページネーションリンク(「1, 2, 3...」や「次へ」といったリンク)をビューに表示します。paginate() メソッドで取得したデータは、links() メソッドを持っています。このメソッドを {{ }} で呼び出すだけで、Laravelが自動的に現在のページや総ページ数を計算し、適切なHTMLリンクを生成してくれます。d-flex justify-content-center はBootstrapのクラスで、リンクを中央に配置するためのものです。

変更点: ビューで受け取るコメント変数の変更

/resources/views/posts/show.blade.php
1     {{-- コメント一覧 --}}
2     <h3>コメント一覧</h3>
3-    @if ($post->comments->isEmpty())
4+    @if ($comments->isEmpty())
5        <p>コメントはまだありません。</p>
6     @else
7-        @foreach ($post->comments as $comment)
8+        @foreach ($comments as $comment)
9             <div class="card mb-2">
10                 <div class="card-body">
11                     <p class="card-text">{{ $comment->content }}</p>

コントローラーの show メソッドで、ページネーション化されたコメントを新しく $comments という変数でビューに渡すように変更しました。そのため、ビュー側もその変更に合わせる必要があります。これまでコメントの有無の判定や一覧表示に使っていた $post->comments を、新しく渡された $comments 変数に書き換えています。

変更点: コメント一覧にページネーションリンクを表示

/resources/views/posts/show.blade.php
1     @else
2         <p>コメントを投稿するにはログインしてください。</p>
3     @endauth
4+
5+    {{-- コメントのページネーションリンク --}}
6+    <div class="d-flex justify-content-center mt-4">
7+        {{ $comments->links() }}
8+    </div>
9+
10 @endsection

投稿一覧ページと同様に、コメント一覧の下にもページネーションリンクを追加します。コントローラーから渡された $comments 変数に対して links() メソッドを呼び出すことで、コメント用のページネーションリンクがHTMLとして生成・表示されます。これにより、ユーザーはコメントをページ単位で閲覧できるようになります。

おわりに

おわりに

今回はLaravelのページネーション機能について学びました。コントローラーでデータの取得方法をget()からpaginate()メソッドに変更するだけで、簡単にページ分割が実現できます。ビュー側ではlinks()メソッドを呼び出すだけでページリンクが自動で生成され、AppServiceProviderに一行追加するだけでBootstrapのデザインを適用できる手軽さもご理解いただけたと思います。

関連コンテンツ