Laravel 分页如何自定义传参页码?

这个是laravel文档的解释,

默认情况下,当前页通过HTTP请求查询字符串参数?page的值判断。当然,该值由Laravel自动检测,然后自动插入分页器生成的链接中

然后我想咨询一下,我想通过这个控制器把page这个参数动态传输,这样有什么办法不?

本帖已被设为精华帖!
本帖由 Summer 于 7年前 加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 17

如果觉得方法有疑惑,多去看入门文档Api文档

我们可以通过laravel的Api文档看到paginate的Api参数如下

paginate(int $perPage = null, array $columns = array('*'), string $pageName = 'page', int|null $page = null)

如果你想动态传输当前page,可以通过第四个参数来实现
例如想要第10页数据

$perPage = 15;
$columns = ['*'];
$pageName = 'page';
$currentPage = 10;
paginate($perPage, $columns, $pageName, $currentPage);

至于为什么默认情况下,当前页通过HTTP请求查询字符串参数?page的值判断。下面的可以做一下参考


执行Eloquent的paginate方法时

    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
    {
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
        $perPage = $perPage ?: $this->model->getPerPage();
        $query = $this->toBase();
        $total = $query->getCountForPagination();
        $results = $total
            ? $this->forPage($page, $perPage)->get($columns)
            : $this->model->newCollection();
        return new LengthAwarePaginator($results, $total, $perPage, $page, [
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => $pageName,
        ]);
    }

留意到$page = $page ?: Paginator::resolveCurrentPage($pageName);

其中resolveCurrentPage方法时继承于Illuminate/Pagination/AbstractPaginator.php

    /**
     * Resolve the current page or return the default value.
     *
     * @param  string  $pageName
     * @param  int  $default
     * @return int
     */
    public static function resolveCurrentPage($pageName = 'page', $default = 1)
    {
        if (isset(static::$currentPageResolver)) {
            return call_user_func(static::$currentPageResolver, $pageName);
        }
        return $default;
    }

    /**
     * Set the current page resolver callback.
     *
     * @param  \Closure  $resolver
     * @return void
     */
    public static function currentPageResolver(Closure $resolver)
    {
        static::$currentPageResolver = $resolver;
    }

看到这里你会发现当前页码取决于static::$currentPageResolver如果不存在就返回默认1

然而这个抽象类以及子类中并没有定义static::$currentPageResolver,那laravel为什么默认情况下,当前页能通过HTTP请求查询字符串参数?page的值判断呢?别急,看laravel的代码看ServiceProvider很重要。

我们可以发现在Illuminate/Pagination/PaginationServiceProvider.php

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        Paginator::viewFactoryResolver(function () {
            return $this->app['view'];
        });
        Paginator::currentPathResolver(function () {
            return $this->app['request']->url();
        });
        Paginator::currentPageResolver(function ($pageName = 'page') {
            $page = $this->app['request']->input($pageName);
            if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
                return $page;
            }
            return 1;
        });
    }

对的你没看错在PaginationServiceProvider分页这个服务提供者中注册了这个方法的闭包

        Paginator::currentPageResolver(function ($pageName = 'page') {
            $page = $this->app['request']->input($pageName);
            if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
                return $page;
            }
            return 1;
        });

通过request服务取到路径中的$pageName也就是默认的page,然后判断一下是否是int型且大于等于1,是就返回$page值,否则就是默认的1

没错laravel就是这么神奇

That's all
Enjoy

7年前 评论
charming-xiaoxia 4年前
sunny123456 3年前

如果觉得方法有疑惑,多去看入门文档Api文档

我们可以通过laravel的Api文档看到paginate的Api参数如下

paginate(int $perPage = null, array $columns = array('*'), string $pageName = 'page', int|null $page = null)

如果你想动态传输当前page,可以通过第四个参数来实现
例如想要第10页数据

$perPage = 15;
$columns = ['*'];
$pageName = 'page';
$currentPage = 10;
paginate($perPage, $columns, $pageName, $currentPage);

至于为什么默认情况下,当前页通过HTTP请求查询字符串参数?page的值判断。下面的可以做一下参考


执行Eloquent的paginate方法时

    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
    {
        $page = $page ?: Paginator::resolveCurrentPage($pageName);
        $perPage = $perPage ?: $this->model->getPerPage();
        $query = $this->toBase();
        $total = $query->getCountForPagination();
        $results = $total
            ? $this->forPage($page, $perPage)->get($columns)
            : $this->model->newCollection();
        return new LengthAwarePaginator($results, $total, $perPage, $page, [
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => $pageName,
        ]);
    }

留意到$page = $page ?: Paginator::resolveCurrentPage($pageName);

其中resolveCurrentPage方法时继承于Illuminate/Pagination/AbstractPaginator.php

    /**
     * Resolve the current page or return the default value.
     *
     * @param  string  $pageName
     * @param  int  $default
     * @return int
     */
    public static function resolveCurrentPage($pageName = 'page', $default = 1)
    {
        if (isset(static::$currentPageResolver)) {
            return call_user_func(static::$currentPageResolver, $pageName);
        }
        return $default;
    }

    /**
     * Set the current page resolver callback.
     *
     * @param  \Closure  $resolver
     * @return void
     */
    public static function currentPageResolver(Closure $resolver)
    {
        static::$currentPageResolver = $resolver;
    }

看到这里你会发现当前页码取决于static::$currentPageResolver如果不存在就返回默认1

然而这个抽象类以及子类中并没有定义static::$currentPageResolver,那laravel为什么默认情况下,当前页能通过HTTP请求查询字符串参数?page的值判断呢?别急,看laravel的代码看ServiceProvider很重要。

我们可以发现在Illuminate/Pagination/PaginationServiceProvider.php

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        Paginator::viewFactoryResolver(function () {
            return $this->app['view'];
        });
        Paginator::currentPathResolver(function () {
            return $this->app['request']->url();
        });
        Paginator::currentPageResolver(function ($pageName = 'page') {
            $page = $this->app['request']->input($pageName);
            if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
                return $page;
            }
            return 1;
        });
    }

对的你没看错在PaginationServiceProvider分页这个服务提供者中注册了这个方法的闭包

        Paginator::currentPageResolver(function ($pageName = 'page') {
            $page = $this->app['request']->input($pageName);
            if (filter_var($page, FILTER_VALIDATE_INT) !== false && (int) $page >= 1) {
                return $page;
            }
            return 1;
        });

通过request服务取到路径中的$pageName也就是默认的page,然后判断一下是否是int型且大于等于1,是就返回$page值,否则就是默认的1

没错laravel就是这么神奇

That's all
Enjoy

7年前 评论
charming-xiaoxia 4年前
sunny123456 3年前
幽弥狂

@milkmeowo 你应该单独开个帖子。。。我看到标题时一脸懵逼。。。为什么会被加精呢,,,原来是你的回复

7年前 评论

@xhh110 我只是顺手回复而已,写文章什么的之前试过,写出来之后别人理解不能,就没继续了

7年前 评论
幽弥狂

@milkmeowo 写的很好。。很详细

7年前 评论

@milkmeowo 我像你这样说的传了这个参数进去,会报这样的错误的

Type error: Argument 1 passed to Illuminate\Database\Grammar::columnize() must be of the type array, float given, called in /var/www/enclaveapp/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php on line 121

下面是我的分页代码
$comments = Comment::where(['source_id' => $request->source_id, 'type' => $request->type])->orderBy('id', 'desc')->paginate($count,$currentPage);

7年前 评论

@milkmeowo 我像你这样说的传了这个参数进去,会报这样的错误的

Type error: Argument 1 passed to Illuminate\Database\Grammar::columnize() must be of the type array, float given,
 called in /var/www/enclaveapp/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php on line 121

下面是我的分页代码

$comments = Comment::where(['source_id' => $request->source_id, 'type' => $request->type])->orderBy('id', 'desc')->paginate($count,$currentPage);
7年前 评论

@ChenPHPER 来我们学一下数学

顺序 参数 你的顺序 你的参数
1 $perPage = 15; 1 $count
2 $columns = ['*']; 4 $currentPage
3 $pageName = 'page'; (黑人问号)
4 $currentPage = 10; (黑人问号)
paginate($perPage, $columns, $pageName, $currentPage);

所以你应该

$comments = Comment::where([
    'source_id' => $request->source_id,
    'type' => $request->type,
])
->orderBy('id', 'desc')
->paginate($count, [*], 'page', $currentPage);

@xhh110 看,怎么说来着,写出来之后别人还是理解不能,所以

详细并不一定代表好,只有通俗易懂才是真的好

7年前 评论

@milkmeowo 好啦,是我大意了,谢谢你啦,方便给你qq或者微信我吗?发个红包给你,表示表示,以后有问题还可以请假一下你啦

7年前 评论

@milkmeowo 其实昨天我也去看过这个了,也是刚才那问题,然后就认为不行,是我太不仔细了

7年前 评论
幽弥狂

@milkmeowo 说的好

7年前 评论

回答的好完美 ?

6年前 评论

```

        $limit = $request->limit ? $request->limit : 8; 

        $page  = $request->page ? $request->page - 1 : 0;

        if(!is_numeric($page)){
            return response()->json(['error'=>['message' => '参数错误!']]); 
        }

        $page   = $page < 0 ? 0 : $page ;

        $page   = $page * $limit;

        $model->offset($page)->limit($limit);
3年前 评论

赞,解释的到位

3个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!