下面由Laravel教程欄目給大家介紹Laravel 項(xiàng)目 偽靜態(tài)分頁處理 ,希望對(duì)需要的朋友有所幫助!
手上有個(gè) Laravel 的項(xiàng)目,要求做偽靜態(tài)處理,項(xiàng)目中使用了 Laravel 自帶的分頁組件,分頁組件分頁會(huì)在你的 URL 用 Query 的方式做頁碼的傳遞,達(dá)不到偽靜態(tài)的要求。
想要的效果
我們偽靜態(tài)想要的效果大體是這樣的:
/software/3dmax/created_at/page-1.html
對(duì)應(yīng) Laravel 的路由是:
/software/{category}/{order}/page-{page}.html
因?yàn)?Laravel 路由本身是支持路由參數(shù)的,所以說 我們變量的獲取是完全沒有問題的,但是 Laravel 自帶的分頁組件會(huì)將你的 參數(shù) 用 Query 的方式做傳遞,所以生成的分頁地址是下面這種
/software/3dmax/created_at/page-1.html?category=3dmax&order=created_at&page=2
這不是我們需要的,所以我們需要對(duì) Laravel 自帶的分頁組件進(jìn)行修改。
Laravel 分頁組件
在 Laravel 中我們?nèi)绻枰猪?,?huì)調(diào)用 模型中的 paginate
方法,然后傳遞每頁的頁碼。
paginate
方法會(huì)調(diào)用IlluminateDatabaseConcernsBuildsQueries
下的paginator
方法。paginator
方法會(huì)構(gòu)造一個(gè)IlluminatePaginationLengthAwarePaginator
的實(shí)例。IlluminatePaginationLengthAwarePaginator
會(huì)使用IlluminatePaginationAbstractPaginator
中的url
方法進(jìn)行構(gòu)造請(qǐng)求參數(shù)和url。
現(xiàn)在我們找到生成 URL 的地方了,我們需要做的就是在這里修改。
重寫分頁組件
Laravel 中本身支持自定義分頁組件,But 我們做的不是自定義分頁,我們需要對(duì)于方法進(jìn)行重寫。
創(chuàng)建 LengthAwarePaginator 類
mkdir app/Pagination touch app/Pagination/LengthAwarePaginator.php
文件 app/Pagination/LengthAwarePaginator.php 內(nèi)容:
<?php namespace AppPagination; use IlluminateSupportArr; use IlluminateSupportStr; use IlluminatePaginationLengthAwarePaginator as BasePaginator; class LengthAwarePaginator extends BasePaginator { }
重寫 Url 方法
首先 Laravel 自帶的分頁 會(huì)把路由里面的參數(shù)放到 Query中,我們需要的是 參數(shù)還是放到地址中。
- 獲取到所有的 query 參數(shù)
- 判斷需要分頁的頁面路由中是否有綁定的路由參數(shù)
- 如果沒有的話,我們就走 Laravel 本身的分頁
- 如果有的話,我們就通過路由和路由參數(shù)進(jìn)行構(gòu)建地址,并把它從 query 參數(shù)中剔除
- 判斷下當(dāng)前的 query 參數(shù)中是否還有參數(shù),如果還有的話,我們就和之前一樣。
修改 app/Pagination/LengthAwarePaginator.php下內(nèi)容:
... public function url($page) { if ($page <= 0) { $page = 1; } $parameters = [$this->pageName => $page]; if (count($this->query) > 0) { $parameters = array_merge($this->query, $parameters); } //判斷的參數(shù)是否在 路由中 需要綁定的數(shù)據(jù) $params = request()->route()->parameters(); if (!empty($params)) { foreach ($parameters as $key => $parameter) { if (isset($params[$key])) { $params[$key] = $parameter; unset($parameters[$key]); } } $path = route(request()->route()->getAction('as'), $params); } else { $path = $this->path; } // 判斷是否有參數(shù) if (empty(Arr::query($parameters))) { return $path . $this->buildFragment(); } return $path . (Str::contains($this->path, '?') ? '&' : '?') . Arr::query($parameters) . $this->buildFragment(); } ...
使用自定義的分頁組件
在 Laravel 中我們?nèi)绻枰猪摚瑫?huì)調(diào)用 模型中的 paginate
方法,但是paginate
方法的定義在IlluminateDatabaseEloquentBuilder
下,如果我們需要重寫的話,會(huì)很麻煩,并且還有一個(gè)問題就是,并不是我們所有的分頁都是需要偽靜態(tài)的,比如我們用戶中心的數(shù)據(jù)可能不太需要偽靜態(tài)。所以我們需要一個(gè)可以手動(dòng)設(shè)置的東西,Larave 模型中有一個(gè) 本地作用域,我們可以寫一個(gè)方法staticPaginate
,當(dāng)需要使用靜態(tài)分頁的時(shí)候,我們可以Model->query()->staticPaginate();
來調(diào)用,所需要的參數(shù)和 Laravel 自帶的 pageinage
方法類似。
公共的Model 基類文件
Laravel項(xiàng)目中的 Model 我們一般不會(huì)直接繼承IlluminateDatabaseEloquentModel
我們一般都在 appModels
目錄定義一個(gè) Model 基類,所有的模型都繼承自 Model 基類,這并不是必須的,只是這樣的話對(duì)于模型修改,或添加公共的方法比較方便。
在模型中定義本地作用域
你只需要拷貝 IlluminateDatabaseEloquentBuilder
下的paginate
方法的內(nèi)容并修改$this
的指向就可以了
... use IlluminatePaginationPaginator; # Laravel 自帶的。 use IlluminateContractsPaginationLengthAwarePaginator; ... /** * 自定義靜態(tài)分頁 * @author kingofzihua * @param Builder $builder * @param int $perPage * @param array $columns * @param string $pageName * @param int|null $page * @return LengthAwarePaginator * * @throws InvalidArgumentException */ public function scopeStaticPaginate($builder, $perPage = null, $columns = ['*'], $pageName = 'page', $page = null) { if (request('page')) { request()->offsetSet('page', request('page')); } $page = $page ?: Paginator::resolveCurrentPage($pageName); $perPage = $perPage ?: $builder->getModel()->getPerPage(); $results = ($total = $builder->toBase()->getCountForPagination()) ? $builder->forPage($page, $perPage)->get($columns) : $builder->getModel()->newCollection(); return $this->paginator($results, $total, $perPage, $page, [ 'path' => Paginator::resolveCurrentPath(), 'pageName' => $pageName, ]); } ...
替換自定義的分頁組件
# 替換 use AppPaginationLengthAwarePaginator; # --- use IlluminateContractsPaginationLengthAwarePaginator; // 注釋 ... /** * * @param IlluminateSupportCollection $items * @param int $total * @param int $perPage * @param int $currentPage * @param array $options * @return LengthAwarePaginator */ protected function paginator($items, $total, $perPage, $currentPage, $options) { return Container::getInstance()->makeWith(LengthAwarePaginator::class, compact( 'items', 'total', 'perPage', 'currentPage', 'options' )); } ...
在項(xiàng)目中使用靜態(tài)分頁組件
Model::query()->staticPaginate($pageSize);