Laravel 把傳參的分頁 url 改為 /page/11

kuibatian發表於2019-11-01

Laravel 中通過自定義分頁器分頁方法實現偽靜態分頁連結以利於 SEO

我們知道,Laravel 自帶的分頁器方法包含 simplePaginate 和 paginate 方法,一個返回不帶頁碼的分頁連結,另一個返回帶頁碼的分頁連結,但是這兩種分頁連結頁碼都是以帶問號的動態引數形式附加在查詢字串中,形如 https://laravelacademy.org?page=100,但是這種包含動態引數的 URL 格式對 SEO 不友好,我們最好將其轉化為 https://laravelacademy.org/page/100 這種不帶問號的偽靜態分頁連結格式,遺憾的是 Laravel 並沒有提供對這種偽靜態分頁連結格式的自定義支援,只好自己動手了。

我們將基於 paginate 方法實現的分頁進行擴充套件,只是修改其分頁連結格式,該方法底層呼叫了 Illuminate\Pagination\LengthAwarePaginator 類實現分頁,所以我們需要自定義一個繼承自該分頁器類的 app/Utils/AcademyPaginator.php,詳細如下看:

http://www.24test.com/news/zhongchao?page=...

把url改為/page/11

找到了
news 路由 指向與

D:\web\work\trunk\24_project\project_test\sports-transfer\module\Article\Controller\Web\type()

type指向了 topic方法

topic 中的分頁是 直接使用了

$this->paging()

paging 位於ArticlePaging的一個trait

分頁的頁碼是直接使用了引數來獲取的

$request = app(Request::class);

改動路由,把引數改為路由佔位符傳參
找到路由檔案
D:\web\work\trunk\24_project\project_test\sports-transfer\module\Article\Provider\RouteProvider.php--68line

我們直接加上路由引數

    Route::get("/news/{type}/page/{pages}/", "ListController@type");// pagine 改為佔位符

直接如下

修改分頁樣式

在 article.blade.php中我們找到了引入了分頁檔案
位於:D:\web\work\trunk\24_project\project_test\sports-transfer\resources\views\pc\layout\block-pagination-style.blade.php

那我們在此處直接修改分頁生產的url

我們需要去找到類去修改 更為合適

直接修改分頁類

D:\web\work\trunk\24_project\project_test\sports-transfer\vendor\laravel\framework\src\Illuminate\Pagination\AbstractPaginator.php--line 137

加上正則的判斷

/**
     * Get the URL for a given page number.
     *
     * @param  int  $page
     * @return string
     */
    // public function url($page)
    // {
    //     if ($page <= 0) {
    //         $page = 1;
    //     }

    //     // If we have any extra query string key / value pairs that need to be added
    //     // onto the URL, we will put them in query string form and then attach it
    //     // to the URL. This allows for extra information like sortings storage.
    //     $parameters = [$this->pageName => $page];

    //     if (count($this->query) > 0) {
    //         $parameters = array_merge($this->query, $parameters);
    //     }

    //     return $this->path
    //                     .(Str::contains($this->path, '?') ? '&' : '?')
    //                     .http_build_query($parameters, '', '&')
    //                     .$this->buildFragment();
    // }

    /**
     * 重寫頁面 URL 實現程式碼,去掉分頁中的問號,實現偽靜態連結
     * @access public 
     * @param int $page
     * @since 1.1 
     * @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;
    }

它是在這裡將分頁資訊作為查詢引數的一部分放到分頁連結中,所以我們需要在自定義的 AcademyPaginator 類中重寫這個方法覆蓋父類實現:

/**
 * 重寫頁面 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;
}

至此,我們自定義的分頁器類已經編寫好了,接下來還要將這個分頁器註冊到模型類的查詢構建器中以便可以像simplePaginate 和 paginate 方法那樣在模型例項上呼叫,這裡我們需要藉助查詢構建器 Illuminate\Database\Eloquent\Builder 提供的靜態 macro 方法在執行時動態擴充套件其提供的方法,我們還是在 AcademyPaginator 中定義這個方法擴充套件實現:

/**
 * 將新增的分頁方法註冊到查詢構建器中,以便在模型例項上使用
 * 註冊方式:
 * 在 AppServiceProvider 的 boot 方法中註冊:AcademyPaginator::rejectIntoBuilder();
 * 使用方式:
 * 將之前程式碼中在模型例項上呼叫 paginate 方法改為呼叫 seoPaginate 方法即可:
 * Article::where('status', 1)->seoPaginate(15, ['*'], 'page', page);
 */
public static function injectIntoBuilder()
{
    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'
        ));
    });
}

這樣,在模型例項上呼叫 seoPaginate 方法,將通過 AcademyPaginator 進行分頁,最後我們在 AppServiceProvider 的 boot 方法中全域性呼叫這個注入:

// 為查詢構建器注入自己實現的分頁器方法
AcademyPaginator::injectIntoBuilder();
接下來,就可以在自己的程式碼中編寫以下這種程式碼實現偽靜態分頁連結了:

$articles = Article::with('author', 'category')->public()->orderBy('id', 'desc')->seoPaginate($pageSize, $this->listColumns, 'page', $page);

https://www.cnblogs.com/liangzia/p/6223129...

為啥子 只要使用seoPaginate?

因為

// 為查詢構建器注入自己實現的分頁器方法
        // Builder 提供的靜態macro 方法在執行時動態擴充套件 所以我們實現時候只要
        // 將之前程式碼中在模型例項上呼叫 paginate 方法改為呼叫 seoPaginate 方法即可:
        // @author bobo
        // @date 2019-11-01

本人程式碼是自己寫的實現分頁方法 直接new到了 laravel底層的類傳入屬性

那我們這裡不可以呼叫屬性seoPaginate

解決方法:

直接new AcademyPaginator 類傳入屬性即可

/**
     * @param $articles Collection
     * @param int $pn
     * @return LengthAwarePaginator
     */
    /** 
    * topic  
    * 分頁 佔位符方式傳參
    * 此處方法為相容版本 擔心其他地方呼叫報錯
    * @access public 
    * @param mixed $arg1 列表頁資料型別 
    * @param int $arg2 分頁條目數 預設為空 
    * @param int $arg3 頁碼 預設為空 
    * @date 2019-11-01
    * @author bobo<1576554465@qq.com>
    * @version     $1.1$ 
    * @since 1.0 
    * @return html 
    */ 
    public function paging($articles, $pn = 10,$page=null) {

        $request = app(Request::class);
        // dd($request);
        // 拿到頁碼  request有 
        if ($request->has('page')) {
            $pl = $request->input('page');
            $pl = $pl <= 0 ? 1 :$pl;
        } elseif(!empty($page)) {
            // 傳遞的頁碼不為空則直接賦值
            $pl = $page;
            $pl = $pl <= 0 ? 1 :$pl;
        } else {
            $pl = 1;
        }
        // $object = new LengthAwarePaginator($articles->slice(($pl-1)*$pn, $pn), $articles->count(), $pn, $pl,[
        // 使用新方法seoPaginate 
        $object = new AcademyPaginator($articles->slice(($pl-1)*$pn, $pn), $articles->count(), $pn, $pl,[
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => 'page',
        ]);
        $object->clazz = 'page';

        return $object;
    }

排查其他受影響的url

基本不影響,因為我們是適配使用的,只要你使用的是laravel提供的分頁類即可。
而且路由沒有進行大改

本作品採用《CC 協議》,轉載必須註明作者和本文連結

每天5分鐘,與你一起蛻變!上海php自學中心,目前專注於php,python,golang~撒花!
S3d25uqwht.png!large
公眾號7Dn78VKKcW.jpg!large

相關文章