Laravel Yajra Datatables服务端分页异常:点击第二页后无法进入第三页
问题分析与解决方案
问题根源
- 手动分页导致Datatables无法获取总记录数:你在查询中手动使用
skip()和take()截取当前页数据,传给Datatables时它只能拿到当前页的2条数据,无法计算出总共有8条记录,因此分页按钮生成逻辑错误,第三页及以后的按钮消失。 - 条件判断错误:
if (!empty($req['start']))会在start=0(第一页)时返回false,导致第一页能拿到全部数据、分页显示正常;但第二页start=2时会执行手动分页,Datatables拿到部分数据后分页逻辑混乱。 - 日期过滤条件笔误:
!empty($req['date_to']) && !empty($req['date_to'])重复判断了date_to,应该同时校验date_from和date_to。 - SQL注入风险:直接拼接日期参数到
whereRaw中存在注入风险,需改用参数绑定。
修复方案
- 移除手动的
skip()和take()逻辑,让Laravel Datatables自动处理分页参数 - 将未执行
get()的查询构建器直接传给Datatables::of(),这样Datatables能获取总记录数和过滤后的记录数,正确生成分页按钮 - 修正日期过滤的条件判断
- 替换SQL拼接为参数绑定,避免注入风险
修正后的代码
public function reservationListing(Request $request) { $req = $request->all(); $query = EventReservation::selectRaw(" reservation_date, event_reservations.outlet_id, event_reservations.event_id, SUM(event_reservations.total_adults) as ttl_adult, SUM(event_reservations.total_kids) as ttl_kid, SUM(event_reservations.total_adults + event_reservations.total_kids) as ttl_pax, SUM(CASE WHEN event_reservations.total_attendees is NULL then 0 Else event_reservations.total_attendees End) as ttl_attended, SUM(CASE WHEN payment_status = 'pending' THEN 1 ELSE 0 END) as ttl_pending, SUM(CASE WHEN payment_status = 'paid' THEN 1 ELSE 0 END) as ttl_paid, events.name as event_name, outlets.name as outlet_name ") ->leftjoin("events", "events.id", "=", "event_reservations.event_id") ->leftjoin("outlets", "outlets.id", "=", "event_reservations.outlet_id") ->groupby('reservation_date', 'outlet_id', 'event_id'); // 修正日期过滤条件,使用参数绑定避免SQL注入 if (!empty($req['date_from']) && !empty($req['date_to'])) { $query->whereRaw("DATE(reservation_date) BETWEEN ? AND ?", [$req['date_from'], $req['date_to']]); } if (!empty($req['outlet_id'])) { $query->where("event_reservations.outlet_id", $req['outlet_id']); } if (!empty($req['event_id'])) { $query->where("event_reservations.event_id", $req['event_id']); } $query->orderBy("reservation_date"); // 直接传入查询构建器,而非分页后的集合 return Datatables::of($query) ->addIndexColumn() ->make(true); }
补充说明
Laravel Datatables包会自动识别请求中的start、length、search等参数,自动完成分页、排序、过滤操作,不需要手动处理skip()、take()或setOffset()。只要传入完整的查询构建器,它会负责计算总记录数、过滤后记录数,并生成正确的分页数据。
内容的提问来源于stack exchange,提问作者Najwa Tech
相关产品推荐
相关产品推荐

