Laravel自定义分页-链式伪静态分页SEO分页

Song729 次浏览0个评论2021年10月11日

Laravel自带的simplePaginatepaginate方法的分页方式都为http://test.com?page=*格式;对于SEO不是很友好;我们尝试修改为http://test.com/page/1这种不带问号的伪静态分页链接格式;我们根据文档Laravel分页-手动创建分页

有时你可能希望手动创建分页,并传递一个包含数据的数组给它。这可以通过手动创建Illuminate\Pagination\Paginator或者Illuminate\Pagination\LengthAwarePaginator实例来实现,这取决于你的需要。

一、创建文件app/Utils/AcademyPaginator.php

<?php
namespace App\Utils;

use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Str;
use Illuminate\Pagination\Paginator;
use Illuminate\Pagination\LengthAwarePaginator as BasePaginator;

class AcademyPaginator extends BasePaginator
{
    /**
     * 重写页面 URL 实现代码,去掉分页中的问号,实现伪静态链接
     * @param int $page
     * @return string
     */
    public function url($page)
    {
        if ($page <= 0) {
            $page = 1;
        }

        // 移除路径尾部的/
        $path = rtrim($this->path, '/');

        // 如果路径中包含分页信息则正则替换页码,否则将页码信息追加到路径末尾
        if (preg_match('/\/page\/\d+/', $path)) {
            $path = preg_replace('/\/page\/\d+/', '/page/' . $page, $path);
        } else {
            $path .= '/page/' . $page;
        }
        $this->path = $path;

        if ($this->query) {
            $url = $this->path . (Str::contains($this->path, '?') ? '&' : '?')
                . http_build_query($this->query, '', '&')
                . $this->buildFragment();
        } elseif ($this->fragment) {
            $url = $this->path . $this->buildFragment();
        } else {
            $url = $this->path;
        }

        return $url;
    }

    /**
     * 重写当前页设置方法
     *
     * @param  int  $currentPage
     * @param  string  $pageName
     * @return int
     */
    protected function setCurrentPage($currentPage, $pageName)
    {
        if (!$currentPage && preg_match('/\/page\/(\d+)/', $this->path, $matches)) {
            $currentPage = $matches[1];
        }

        return $this->isValidPageNumber($currentPage) ? (int) $currentPage : 1;
    }

    /**
     * 将新增的分页方法注册到查询构建器中,以便在模型实例上使用
     * 注册方式:
     * 在 AppServiceProvider 的 boot 方法中注册:AcademyPaginator::rejectIntoBuilder();
     * 使用方式:
     * 将之前代码中在模型实例上调用 paginate 方法改为调用 seoPaginate 方法即可:
     * Article::where('status', 1)->seoPaginate(15, ['*'], 'page', page);
     */
    public static function injectIntoBuilder()
    {
        /*
         * $perPage 每页显示多少条
         * $columns 查询的字段
         * $pageName 翻页链接的参数名
         * $page 当前页数
         * */
        Builder::macro('seoPaginate', function ($perPage, $columns, $pageName, $page) {
            $perPage = $perPage ?: $this->model->getPerPage();

            $items = ($total = $this->toBase()->getCountForPagination())
                ? $this->forPage($page, $perPage)->get($columns)
                : $this->model->newCollection();

            $options = [
                'path' => Paginator::resolveCurrentPath(),
                'pageName' => $pageName,
            ];

            return Container::getInstance()->makeWith(AcademyPaginator::class, compact(
                'items', 'total', 'perPage', 'page', 'options'
            ));
        });
    }
}

二、在 app/Providers/AppServiceProvider 的 boot 方法中全局调用这个注入:

// 为查询构建器注入自己实现的分页器方法
AcademyPaginator::injectIntoBuilder();

这样,在模型实例上调用seoPaginate方法,将通过 AcademyPaginator 进行分页。接下来,就可以在自己的代码中编写以下这种代码实现伪静态分页链接了:

# 每页数量
$pageSize = 20;
$page = 1;
$articles = Article::orderBy('id', 'desc')->seoPaginate($pageSize, ['*'], 'page', $page);

参考文档:https://laravelacademy.org/post/9661.html

其他文章

提交评论

请登录后评论

用户评论

    当前暂无评价,快来发表您的观点吧...

更多相关好文

    当前暂无更多相关好文推荐...