Laravel: Pagination (Phân trang)

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Mục lục bài viết

Giới thiệu

Cách sử dụng cơ bản

Hiển thị kết quả phân trang

Tùy chỉnh Chế độ xem Phân trang

Các phương thức của Paginator

Giới thiệu

Trình phân trang của Laravel được tích hợp với Query Builder (trình tạo truy vấn) và Eloquent ORM và cung cấp phân trang thuận tiện và dễ sử dụng cho các kết quả truy vấn cơ sở dữ liệu. Theo mặc định thì HTML được tạo bởi trình phân trang tương thích với framework CSS Tailwind; tuy nhiên, các view Bootstrap cũng làm được điều này.

Cách sử dụng cơ bản

Phân trang kết quả của trình tạo truy vấn

Có một số cách để phân trang các mục. Đơn giản nhất là sử dụng phương thức paginate trên trình tạo truy vấn hoặc Eloquent ORM. Phương thức paginate tự động thiết lập các giới hạn phù hợp và bù đắp dựa trên trang hiện tại đang được xem bởi người sử dụng. Theo mặc định, trang hiện tại được phát hiện bởi giá trị của đối số page (là biến GET trên thanh địa chỉ) của chuỗi truy vấn trên yêu cầu HTTP. Giá trị này được Laravel tự động phát hiện và cũng được tự động chèn vào các liên kết do trình phân trang tạo ra.

Trong ví dụ sau, đối số duy nhất được truyền cho phương thức paginate là số mục bạn muốn được hiển thị trên mỗi trang mà trong ví dụ này là 15:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\DB;

class UserController extends Controller
{
    public function index()
    {
        $users = DB::table('users')->paginate(15); //lấy 15 mục mỗi trang đối với bảng users

        return view('user.index', ['users' => $users]);
    }
}

Hiện tại, các thao tác phân trang sử dụng câu lệnh groupBy không thể được thực thi một cách hiệu quả bởi Laravel. Nếu bạn cần sử dụng groupBy để phân trang, bạn nên truy vấn cơ sở dữ liệu và tạo bộ phân trang theo cách thủ công.

Phân trang đơn giản

Nếu bạn chỉ cần hiển thị các liên kết đơn giản theo kiểu "Tiếp theo - Next" và "Trước đó - Previous" trong dạng xem phân trang của mình, bạn có thể sử dụng phương thức simplePaginate để thực hiện một truy vấn hiệu quả hơn. Điều này rất hữu ích cho các tập dữ liệu lớn khi bạn không cần hiển thị liên kết cho mỗi số trang khi hiển thị chế độ xem của mình:

$users = DB::table('users')->simplePaginate(15);

Phân trang kết quả truy vấn với Eloquent

Bạn cũng có thể phân trang cho truy vấn Eloquent. Trong ví dụ này dưới đây ta sẽ phân trang model User với 15 mục trên mỗi trang:

$users = App\Models\User::paginate(15);

Bạn có thể gọi paginate sau khi đặt các ràng buộc khác trên truy vấn, chẳng hạn như mệnh đề where:

$users = User::where('votes', '>', 100)->paginate(15);

Bạn cũng có thể sử dụng phương thức simplePaginate khi phân trang với Eloquent:

$users = User::where('votes', '>', 100)->simplePaginate(15);

Phân trang theo cách thủ công

Đôi khi bạn có thể muốn phân trang theo cách thủ công, bạn có thể làm bằng cách tạo một thể hiện Illuminate\Pagination\Paginator, hoặc Illuminate\Pagination\LengthAwarePaginator tùy thuộc vào nhu cầu của bạn.

Lớp Paginator không cần phải biết tổng số mục trong tập kết quả; tuy nhiên, vì điều này, lớp không có các phương thức để lấy chỉ mục của trang cuối cùng. Khi đó LengthAwarePaginator sẽ chấp nhận các đối số gần như tương tự như Paginator; tuy nhiên, nó yêu cầu đếm tổng số mục trong tập kết quả.

Nói cách khác, giá trị Paginator tương ứng với phương thức simplePaginate trên trình tạo truy vấn và Eloquent, trong khi giá trị LengthAwarePaginator tương ứng với phương thức paginate.

Khi tạo một phiên bản phân trang theo cách thủ công, bạn nên "cắt" mảng kết quả mà bạn chuyển cho trình phân trang theo cách thủ công. Nếu bạn không chắc chắn về cách thực hiện việc này, hãy xem hàm array_slice của PHP.

Hiển thị kết quả phân trang

Khi gọi phương thức paginate, bạn sẽ nhận được một thể hiện của Illuminate\Pagination\LengthAwarePaginator. Khi gọi phương thức simplePaginate, bạn sẽ nhận được một thể hiện của Illuminate\Pagination\Paginator. Các đối tượng này cung cấp một số phương thức mô tả tập kết quả. Ngoài các phương thức trợ giúp này, các thể hiện của bộ trang là các trình vòng lặp và có thể được lặp lại dưới dạng một mảng. Vì vậy, khi bạn đã truy xuất kết quả, bạn có thể hiển thị kết quả và hiển thị các liên kết trang bằng Blade:

<div class="container">
    @foreach ($users as $user)
        {{ $user->name }}
    @endforeach
</div>

{{ $users->links() }}

Phương thức links sẽ hiển thị kết quả phân trang. Mỗi liên kết này sẽ chứa biến page là biến chứa trang số hiện thời. HTML được tạo bởi phương thức links tương thích với framework CSS Tailwind.

Tùy chỉnh URI Paginator

Phương thức withPath cho phép bạn tùy chỉnh các URI được sử dụng bởi các paginator khi tạo liên kết. Ví dụ: nếu bạn muốn trình phân trang tạo các liên kết http://example.com/custom/url?page=N thì bạn cần truyền custom/url đến phương thức withPath

Route::get('users', function () {
    $users = App\Models\User::paginate(15);

    $users->withPath('custom/url');

    //
});

Nối vào các liên kết phân trang

Bạn có thể thêm vào chuỗi truy vấn của các liên kết phân trang bằng phương thức appends. Ví dụ: để thêm sort=votes vào mỗi liên kết phân trang thì bạn làm như sau:

{{ $users->appends(['sort' => 'votes'])->links() }}

Nếu bạn muốn nối tất cả các giá trị chuỗi truy vấn hiện tại vào các liên kết phân trang, bạn có thể sử dụng phương thức withQueryString:

{{ $users->withQueryString()->links() }}

Nếu bạn muốn nối "đoạn băm - phần sau của #" vào URL của trình phân trang, bạn có thể sử dụng phương thức fragment. Ví dụ: để thêm #foo vào cuối mỗi liên kết phân trang bạn làm như sau:

{{ $users->fragment('foo')->links() }}

Điều chỉnh cửa sổ liên kết phân trang

Bạn có thể kiểm soát số lượng liên kết bổ sung được hiển thị ở mỗi bên của "cửa sổ" URL của trình phân trang. Theo mặc định, ba liên kết được hiển thị ở mỗi bên của các liên kết phân trang chính. Tuy nhiên, bạn có thể kiểm soát số này bằng phương thức onEachSide:

{{ $users->onEachSide(5)->links() }}

Chuyển đổi kết quả thành JSON

Laravel dễ dàng chuyển đổi kết quả phân trang thành JSON như sau:

Route::get('users', function () {
    return App\Models\User::paginate();
});

JSON từ paginator sẽ bao gồm thông tin meta như totalcurrent_pagelast_page. Các đối tượng kết quả thực tế sẽ có sẵn thông qua key data trong mảng JSON. Dưới đây là một ví dụ về JSON được tạo bằng cách trả về một phiên bản phân trang từ một route:

{
   "total": 50,
   "per_page": 15,
   "current_page": 1,
   "last_page": 4,
   "first_page_url": "http://laravel.app?page=1",
   "last_page_url": "http://laravel.app?page=4",
   "next_page_url": "http://laravel.app?page=2",
   "prev_page_url": null,
   "path": "http://laravel.app",
   "from": 1,
   "to": 15,
   "data":[
        {
            // Result Object
        },
        {
            // Result Object
        }
   ]
}

Tùy chỉnh Chế độ xem Phân trang

Theo mặc định, các dạng xem sẽ hiển thị các liên kết phân trang tương thích với framework CSS Tailwind. Tuy nhiên, nếu bạn không sử dụng Tailwind, bạn có thể tự do xác định chế độ xem của riêng bạn để hiển thị các liên kết này. Khi gọi phương thức links trên một thể hiện phân trang, hãy chuyển tên dạng xem làm đối số đầu tiên cho phương thức:

{{ $paginator->links('view.name') }}

// Truyền dữ liệu tới view
{{ $paginator->links('view.name', ['foo' => 'bar']) }}

Tuy nhiên, cách dễ nhất để tùy chỉnh các dạng xem phân trang là xuất chúng vào thư mục resources/views/vendor bằng lệnh: vendor:publish

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

Lệnh này sẽ đặt các view vào thư mục resources/views/vendor/pagination. File tailwind.blade.php trong thư mục này tương ứng với view phân trang mặc định. Bạn có thể chỉnh sửa tệp này để sửa đổi HTML phân trang.

Nếu bạn muốn chỉ định một tệp khác làm chế độ xem phân trang mặc định, bạn có thể sử dụng các phương thức defaultView và defaultSimpleView trong AppServiceProvider như sau:

use Illuminate\Pagination\Paginator;

public function boot()
{
    Paginator::defaultView('view-name');

    Paginator::defaultSimpleView('view-name');
}

Sử dụng Bootstrap

Laravel bao gồm các dạng xem phân trang được xây dựng bằng Bootstrap CSS. Để sử dụng các chế độ xem này thay vì các chế độ xem Tailwind mặc định, bạn có thể gọi phương thức  useBootstrap trong AppServiceProvider:

use Illuminate\Pagination\Paginator;

public function boot()
{
    Paginator::useBootstrap();
}

Các phương thức của Paginator

Mỗi thể hiện của Paginator cung cấp thông tin phân trang bổ sung thông qua các phương thức sau:

Phương thức Mô tả
$paginator->count() Nhận số lượng các mục cho trang hiện tại.
$paginator->currentPage() Lấy số trang hiện tại.
$paginator->firstItem() Lấy số kết quả của mục đầu tiên trong kết quả.
$paginator->getOptions() Nhận các tùy chọn phân trang.
$paginator->getUrlRange($start, $end) Tạo một loạt các URL phân trang.
$paginator->hasPages() Xác định xem có đủ mục để chia thành nhiều trang hay không.
$paginator->hasMorePages() Xác định xem có nhiều mục hơn trong kho dữ liệu hay không.
$paginator->items() Nhận các mục cho trang hiện tại.
$paginator->lastItem() Lấy số kết quả của mục cuối cùng trong kết quả.
$paginator->lastPage() Lấy số trang của trang cuối cùng có sẵn. (Không có sẵn khi sử dụng simplePaginate).
$paginator->nextPageUrl() Lấy URL cho trang tiếp theo.
$paginator->onFirstPage() Xác định xem bộ phân trang có ở trang đầu tiên hay không.
$paginator->perPage() Số lượng mục được hiển thị trên mỗi trang.
$paginator->previousPageUrl() Lấy URL cho trang trước.
$paginator->total() Xác định tổng số mục phù hợp trong kho dữ liệu. (Không có sẵn khi sử dụng simplePaginate).
$paginator->url($page) Lấy URL cho một số trang nhất định.
$paginator->getPageName() Nhận biến chuỗi truy vấn được sử dụng để lưu trữ trang.
$paginator->setPageName($name) Đặt biến chuỗi truy vấn được sử dụng để lưu trữ trang.
» Tiếp: Di chuyển dữ liệu (Migrations)
« Trước: Query Builder
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!