laravel 自带的分页系统paginate 非常好用,但是当遇到去重的时候,自带的分页就是出现一些小麻烦,页面总数total还是没有去重之前的total
$blogs = DB::table('blogs')->distinct()->select('blogs.id','blogs.title','blogs.created_at','blogs.description','blogs.thumb')->join('blog_category', 'blogs.id', '=', 'blog_category.blog_id')->whereIn('blog_category.blog_category_id',$CategoryChildren)->orderBy('blogs.created_at','desc')->paginate(4);
如上面这个数据,即使前面加了 distinct和select,系统计算出的总数仍然是未去重的。
这时候执行的sql语句(计算total的)为:
select count(*) as aggregate from `blogs` inner join `blog_category` on `blogs`.`id` = `blog_category`.`blog_id` where `blog_category`.`blog_category_id` in (10, 11, 12)
网上搜索了很久没找到相关资料,包括官方文档(中文)中也没有提及。最后只有自己看源码
网站根目录\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php
找到了paginate 方法,
public function paginate($perPage = 15, $columns = ['*'], $pageName = 'page', $page = null)
{
$page = $page ?: Paginator::resolveCurrentPage($pageName);
$total = $this->getCountForPagination($columns);
$results = $total ? $this->forPage($page, $perPage)->get($columns) : collect();
return $this->paginator($results, $total, $perPage, $page, [
'path' => Paginator::resolveCurrentPath(),
'pageName' => $pageName,
]);
}
public function getCountForPagination($columns = ['*'])
{
$results = $this->runPaginationCountQuery($columns);
// Once we have run the pagination count query, we will get the resulting count and
// take into account what type of query it was. When there is a group by we will
// just return the count of the entire results set since that will be correct.
if (isset($this->groups)) {
return count($results);
} elseif (! isset($results[0])) {
return 0;
} elseif (is_object($results[0])) {
return (int) $results[0]->aggregate;
}
return (int) array_change_key_case((array) $results[0])['aggregate'];
}
protected function runPaginationCountQuery($columns = ['*'])
{
return $this->cloneWithout(['columns', 'orders', 'limit', 'offset'])
->cloneWithoutBindings(['select', 'order'])
->setAggregate('count', $this->withoutSelectAliases($columns))
->get()->all();
}
而计算total数量就是利用了 count方法。
我们把之前失败的方法改为下面即可:
$blogs = DB::table('blogs')->distinct()->select('blogs.id','blogs.title','blogs.created_at','blogs.description','blogs.thumb')->join('blog_category', 'blogs.id', '=', 'blog_category.blog_id')->whereIn('blog_category.blog_category_id',$CategoryChildren)->orderBy('blogs.created_at','desc')->paginate(4);
paginate 这个方法其实还可以接受一个数组参数,当有数组参数的时候,sql语句会变为:
select count(distinct `id`) as aggregate from `blogss` inner join `blog_category` on `blogs`.`id` = `blog_category`.`blog_id` where `blog_category`.`blog_category_id` in (10, 11, 12)