关于 Laravel 项目 伪静态分页处理

 4075

手上有个 Laravel 的项目,要求做伪静态处理,项目中使用了 Laravel 自带的分页组件,分页组件分页会在你的 URL 用 Query 的方式做页码的传递,达不到伪静态的要求。

想要的效果

我们伪静态想要的效果大体是这样的:

  1. /software/3dmax/created_at/page-1.html

对应 Laravel 的路由是:

  1. /software/{category}/{order}/page-{page}.html

因为 Laravel 路由本身是支持路由参数的,所以说 我们变量的获取是完全没有问题的,但是 Laravel 自带的分页组件会将你的 参数 用 Query 的方式做传递,所以生成的分页地址是下面这种

  1. /software/3dmax/created_at/page-1.html?category=3dmax&order=created_at&page=2

这不是我们需要的,所以我们需要对 Laravel 自带的分页组件进行修改。

Laravel 分页组件

在 Laravel 中我们如果需要分页,会调用 模型中的 paginate 方法,然后传递每页的页码。

paginate 方法会调用 Illuminate\Database\Concerns\BuildsQueries 下的paginator方法。

paginator 方法会构造一个 Illuminate\Pagination\LengthAwarePaginator的实例。

Illuminate\Pagination\LengthAwarePaginator 会使用 Illuminate\Pagination\AbstractPaginator 中的url方法进行构造请求参数和url。

现在我们找到生成 URL 的地方了,我们需要做的就是在这里修改。

重写分页组件

Laravel 中本身支持自定义分页组件,But 我们做的不是自定义分页,我们需要对于方法进行重写。

创建 LengthAwarePaginator 类

  1. mkdir app/Pagination
  2. touch app/Pagination/LengthAwarePaginator.php

文件 app/Pagination/LengthAwarePaginator.php 内容:

  1. <?php
  2. namespace App\Pagination;
  3. use Illuminate\Support\Arr;
  4. use Illuminate\Support\Str;
  5. use Illuminate\Pagination\LengthAwarePaginator as BasePaginator;
  6.  
  7. class LengthAwarePaginator extends BasePaginator
  8. {
  9.  
  10. }

重写 Url 方法

首先 Laravel 自带的分页 会把路由里面的参数放到 Query中,我们需要的是 参数还是放到地址中。

获取到所有的 query 参数

判断需要分页的页面路由中是否有绑定的路由参数

如果没有的话,我们就走 Laravel 本身的分页

如果有的话,我们就通过路由和路由参数进行构建地址,并把它从 query 参数中剔除

判断下当前的 query 参数中是否还有参数,如果还有的话,我们就和之前一样。

修改 app/Pagination/LengthAwarePaginator.php下内容:

  1. ...
  2. public function url($page)
  3. {
  4.     if ($page <= 0) {
  5.         $page = 1;
  6.     } 
  7.     $parameters = [$this->pageName => $page]; 
  8.     if (count($this->query) > 0) {
  9.         $parameters = array_merge($this->query, $parameters);
  10.     }
  11.     
  12.     //判断的参数是否在 路由中 需要绑定的数据
  13.     $params = \request()->route()->parameters(); 
  14.     if (!empty($params)) {
  15.         foreach ($parameters as $key => $parameter) {
  16.             if (isset($params[$key])) {
  17.                 $params[$key] = $parameter;
  18.                 unset($parameters[$key]);
  19.             }
  20.         }
  21.         $path = route(\request()->route()->getAction('as'), $params);
  22.     } else {
  23.         $path = $this->path;
  24.     } 
  25.     
  26.     // 判断是否有参数
  27.     if (empty(Arr::query($parameters))) {
  28.         return $path . $this->buildFragment();
  29.     }
  30.     
  31.     return $path
  32.         . (Str::contains($this->path, '?') ? '&' : '?')
  33.         . Arr::query($parameters)
  34.         . $this->buildFragment();
  35. }
  36. ...

使用自定义的分页组件

在 Laravel 中我们如果需要分页,会调用 模型中的 paginate 方法,但是paginate方法的定义在Illuminate\Database\Eloquent\Builder下,如果我们需要重写的话,会很麻烦,并且还有一个问题就是,并不是我们所有的分页都是需要伪静态的,比如我们用户中心的数据可能不太需要伪静态。所以我们需要一个可以手动设置的东西,Larave 模型中有一个 本地作用域,我们可以写一个方法staticPaginate,当需要使用静态分页的时候,我们可以Model->query()->staticPaginate(); 来调用,所需要的参数和 Laravel 自带的 pageinage 方法类似。

公共的Model 基类文件

Laravel项目中的 Model 我们一般不会直接继承Illuminate\Database\Eloquent\Model 我们一般都在 app\Models 目录定义一个 Model 基类,所有的模型都继承自 Model 基类,这并不是必须的,只是这样的话对于模型修改,或添加公共的方法比较方便。

在模型中定义本地作用域

你只需要拷贝 Illuminate\Database\Eloquent\Builder下的paginate方法的内容并修改$this的指向就可以了

  1. ...
  2. use Illuminate\Pagination\Paginator;
  3. # Laravel 自带的。
  4. use Illuminate\Contracts\Pagination\LengthAwarePaginator;
  5. ...
  6.  
  7. /**
  8.  * 自定义静态分页
  9.  * @author kingofzihua
  10.  * @param Builder $builder
  11.  * @param int $perPage
  12.  * @param array $columns
  13.  * @param string $pageName
  14.  * @param int|null $page
  15.  * @return LengthAwarePaginator
  16.  *
  17.  * @throws \InvalidArgumentException
  18.  */
  19. public function scopeStaticPaginate($builder, $perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
  20. {
  21.     if (request('page')) {
  22.         request()->offsetSet('page', request('page'));
  23.     }
  24.     
  25.     $page = $page ?: Paginator::resolveCurrentPage($pageName); 
  26.     $perPage = $perPage ?: $builder->getModel()->getPerPage();
  27.     
  28.     $results = ($total = $builder->toBase()->getCountForPagination())
  29.         ? $builder->forPage($page, $perPage)->get($columns)
  30.         : $builder->getModel()->newCollection();
  31.         
  32.     return $this->paginator($results, $total, $perPage, $page, [
  33.         'path' => Paginator::resolveCurrentPath(),
  34.         'pageName' => $pageName,
  35.     ]);
  36. }
  37. ...

替换自定义的分页组件

  1. # 替换
  2. use App\Pagination\LengthAwarePaginator;
  3. # --- use  Illuminate\Contracts\Pagination\LengthAwarePaginator;  // 注释 
  4.  
  5. ... 
  6. /**
  7.  *
  8.  * @param \Illuminate\Support\Collection $items
  9.  * @param int $total
  10.  * @param int $perPage
  11.  * @param int $currentPage
  12.  * @param array $options
  13.  * @return LengthAwarePaginator
  14.  */
  15. protected function paginator($items, $total, $perPage, $currentPage, $options)
  16. {
  17.     return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact(
  18.         'items', 'total', 'perPage', 'currentPage', 'options'
  19.     ));
  20. }
  21. ...

在项目中使用静态分页组件

  1. Model::query()->staticPaginate($pageSize);


本文网址:https://www.zztuku.com/index.php/detail-8673.html
站长图库 - 关于 Laravel 项目 伪静态分页处理
申明:如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐