Laravel custom collection pagination and how to paginate eager loading relationship
Lâu rồi mới biên một bài post mới phần vì lười đi nhiều cũng như ngập ngụa trong công việc 😅😅 hehe
Chuyện là hôm nay có làm quả eloquent query vào db với nội dung là lấy ra pagination cho relationship. Đại loại kiểu mối quan hệ many-to-many relationship lấy ví dụ trong bài viết này luôn.
$shop->load([
'products' => function ($q) {
$q->paginate();
},
])
À ha, game là dễ phải không mọi người ha... hehe cho đến khi xem debugbar thì thấy ôi thôi duplicate query.
Hễ trong cái callback function kia cho thêm gì vào là nhân đôi lên
Ok. Chúng ta khoan hãy nói đến việc duplicate đi, xử lý sau. Quan trọng hơn là kết quả trả về không phải là dạng pagianate (có thể sử dụng kiểu {{ $shop->products->links() }} ngoài view) mà là một collection.
Đến đây thì cái tiêu đề mình đặt trên kia có vẻ vô lý mạc sầu nhưng lại rất thuyết mộ dung phục rồi đấy.
Thôi thì tầm này liêm sỉ gì nữa, chả hiểu là bug laravel hay trình mình gà, bắt tay vô xử lý từng cái vậy.
Đầu tiên là paginae, thực chất nó chỉ là dùng limit() và offset() thôi, vậy phân trang 15 items và đang ở page 3 thì ta sẽ có limit(15) và offset(30) -> (3 - 1) * 15 nhỉ.
Đoạn code phân trang ở trên sẽ viết lại thành ntn
$shop->load([
'products' => function ($q) {
$page = Paginator::resolveCurrentPage('page');
$perPage = 15;
$q->skip(($page - 1) * $perPage)->take($perPage);
},
]);
Bây giờ kết quả trả về là một collection. Rồi giờ tiếp đến là trả về phân trang như khi dùng paginate, sau khi kiểm tra collection trong laravel không hề hỗ trợ paginate method nên mình đành phải tạo một cái vậy. Collection hỗ trợ macro function nên bạn hoàn toàn có thể inject một collection method bằng cách viết vào phương thức boot
của app\Providers\AppServiceProvider.php
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Collection::macro('paginate', function ($total = null, $perPage = 15, $pageName = 'page', $page = null) {
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$total = $total ?: $this->count();
$items = $total ? $this : $this->forPage($page, $perPage);
return new LengthAwarePaginator($items, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
});
}
Ở trên thì mình có thêm vào 1 tham số total mặc định là null, paginate ở đây có 2 nghĩa. Nếu có total truyền vào thì ta hiểu là cái collection hiện tại đã được lấy về là số phần tử của một trang rồi, còn ngược lại k có thì hiểu là collection này chứa full items nhé.
Ở ví dụ trên thì sẽ dùng trường hợp 1 đó là truyền total vào, nên ta cần thêm tí chỉnh sửa nữa
$total = $shop->products()->count();
$shop->load([
'products' => function ($q) {
$page = Paginator::resolveCurrentPage('page');
$perPage = 15;
$q->skip(($page - 1) * $perPage)->take($perPage);
},
]);
$shop->products = $shop->products->paginate($total);
Đấy xong rồi
Viết bài chỉ mong được nhiều like thôi, các bạn like cho mình đi 😍
Ủng hộ Chung Nguyễn Blog
Chung Nguyễn Blog sử dụng FlashVPS - Dịch vụ quản trị máy chủ chuyên nghiệp để quản lý VPS
#FlashVPS là dịch vụ cloud panel trên nền tảng web hỗ trợ khách hàng:
- * Quản lý máy chủ số lượng nhiều
- * Không có kinh nghiệm quản lý máy chủ
- * Thích sử dụng giao diện web đơn giản, trực quan hơn terminal
- * Quá nhàm chán với việc ghi nhớ và lặp lại việc gõ các câu lệnh
- * Muốn tự động hóa mọi thao tác
- * Muốn tiết kiệm thời gian quản trị máy chủ
- * Muốn tiết kiệm tiền bạc, nhân lực quản trị máy chủ 👉 https://flashvps.dev
Các bài viết trên website thường xuyên được đăng tải và cập nhật trên trang Facebook Chung Nguyễn Blog hãy tặng cho Chung một LIKE nhé! Mãi yêu các bạn!
813 👍
Bình luận