Laravel5.1+ 分頁 Pagination 解析以及擴充套件

Ryan發表於2016-05-12

本文最早發表於本人部落格: Laravel5.1+ 分頁Pagination解析以及擴充套件

Laravel 的分頁很方便,其實擴充套件起來也挺容易的,下面就來做個示例,擴充套件一下paginate()simplePaginate()方法,來實現我們自定義分頁樣式,比如顯示"上一頁""下一頁",而不是"《""》",當然擴充套件的方法掌握了你就可以肆無忌憚的擴充套件一個你想要的分頁了,比如跳轉到某一頁,分頁顯示一共多少記錄,當前顯示的記錄範圍等等巴拉巴拉的。。。

5.1和5.2應該是同樣的方法,我這裡用的是5.2的版本。文件告訴我們Paginator 對應於查詢語句構造器和 Eloquent 的 simplePaginate 方法,而 LengthAwarePaginator則等同於 paginate 方法。那我們還是來看下原始碼,具體這個 paginate 是如何實現render()的,

  • Illuminate/Pagination/LengthAwarePaginator.php
<?php

namespace Illuminate\Pagination;

......

class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, JsonSerializable, Jsonable, LengthAwarePaginatorContract
{
......
    public function render(Presenter $presenter = null)
    {
        if (is_null($presenter) && static::$presenterResolver) {
            $presenter = call_user_func(static::$presenterResolver, $this);
        }

        $presenter = $presenter ?: new BootstrapThreePresenter($this);

        return $presenter->render();
    }
......
}

render()中傳入的是一個Presenter的例項,並呼叫這個例項化的render方法來實現分頁的顯示的。如果沒有則呼叫BootstrapThreePresenterrender()的,來看看BootstrapThreePresenter是幹嘛的

  • Illuminate/Pagination/BootstrapThreePresenter.php
<?php

namespace Illuminate\Pagination;

use Illuminate\Support\HtmlString;
use Illuminate\Contracts\Pagination\Paginator as PaginatorContract;
use Illuminate\Contracts\Pagination\Presenter as PresenterContract;

class BootstrapThreePresenter implements PresenterContract
{
    use BootstrapThreeNextPreviousButtonRendererTrait, UrlWindowPresenterTrait;

    /**
     * The paginator implementation.
     *
     * @var \Illuminate\Contracts\Pagination\Paginator
     */
    protected $paginator;

    /**
     * The URL window data structure.
     *
     * @var array
     */
    protected $window;

    /**
     * Create a new Bootstrap presenter instance.
     *
     * @param  \Illuminate\Contracts\Pagination\Paginator  $paginator
     * @param  \Illuminate\Pagination\UrlWindow|null  $window
     * @return void
     */
    public function __construct(PaginatorContract $paginator, UrlWindow $window = null)
    {
        $this->paginator = $paginator;
        $this->window = is_null($window) ? UrlWindow::make($paginator) : $window->get();
    }

    /**
     * Determine if the underlying paginator being presented has pages to show.
     *
     * @return bool
     */
    public function hasPages()
    {
        return $this->paginator->hasPages();
    }

    /**
     * Convert the URL window into Bootstrap HTML.
     *
     * @return \Illuminate\Support\HtmlString
     */
    public function render()
    {
        if ($this->hasPages()) {
            return new HtmlString(sprintf(
                '<ul class="pagination">%s %s %s</ul>',
                $this->getPreviousButton(),
                $this->getLinks(),
                $this->getNextButton()
            ));
        }

        return '';
    }
......
}

這裡可以看到BootstrapThreePresenter實現了PresenterContract 的介面,render() 才是分頁顯示的真正實現,構造方法中的第一個引數PaginatorContract 其實就是一個Paginator我們繼續看下PresenterContract也就是Presenter介面中定義了什麼方法需要實現

  • illuminate/contracts/Pagination/Presenter.php
<?php

namespace Illuminate\Contracts\Pagination;

interface Presenter
{
    /**
     * Render the given paginator.
     *
     * @return \Illuminate\Contracts\Support\Htmlable|string
     */
    public function render();

    /**
     * Determine if the underlying paginator being presented has pages to show.
     *
     * @return bool
     */
    public function hasPages();
}

其中定義了renderhasPages方法需要實現

好了,那我們現在已經很清晰了,我們要自定義分頁的顯示,那麼就要寫一個我們自己的Presenter來實現介面中的render()hasPages()就可以了。

首先就來簡單的實現一個paginate(),顯示出來"上一頁"和"下一頁",中間是分頁數字的例子。

新建檔案如下(個人習慣)app/Foundations/Pagination/CustomerPresenter.php

<?php
namespace App\Foundations\Pagination;

use Illuminate\Contracts\Pagination\Presenter as PresenterContract;
use Illuminate\Contracts\Pagination\LengthAwarePaginator as PaginatorContract;
use Illuminate\Pagination\UrlWindow;
use Illuminate\Support\HtmlString;
use Illuminate\Pagination\BootstrapThreeNextPreviousButtonRendererTrait;
use Illuminate\Pagination\UrlWindowPresenterTrait;

class CustomerPresenter implements PresenterContract
{
    use BootstrapThreeNextPreviousButtonRendererTrait, UrlWindowPresenterTrait;

    protected $paginator;

    protected $window;

    /**
     * Create a new Bootstrap presenter instance.
     *
     * @param  \Illuminate\Contracts\Pagination\Paginator $paginator
     * @param  \Illuminate\Pagination\UrlWindow|null $window
     * @return void
     */
    public function __construct(PaginatorContract $paginator, UrlWindow $window = null)
    {
        $this->paginator = $paginator;
        $this->window = is_null($window) ? UrlWindow::make($paginator) : $window->get();
    }

    /**
     * Determine if the underlying paginator being presented has pages to show.
     *
     * @return bool
     */
    public function hasPages()
    {
        return $this->paginator->hasPages();
    }

    /**
     * Convert the URL window into Bootstrap HTML.
     *
     * @return \Illuminate\Support\HtmlString
     */
    public function render()
    {
        if ($this->hasPages()) {
            return new HtmlString(sprintf(
                '<ul class="pagination">%s %s %s</ul>',
                $this->getPreviousButton('上一頁'),//具體實現可以檢視該方法
                $this->getLinks(),
                $this->getNextButton('下一頁')//具體實現可以檢視該方法
            ));
        }

        return '';
    }

    /**
     * Get HTML wrapper for an available page link.
     *
     * @param  string $url
     * @param  int $page
     * @param  string|null $rel
     * @return string
     */
    protected function getAvailablePageWrapper($url, $page, $rel = null)
    {
        $rel = is_null($rel) ? '' : ' rel="' . $rel . '"';

        return '<li><a href="' . htmlentities($url) . '"' . $rel . '>' . $page . '</a></li>';
    }

    /**
     * Get HTML wrapper for disabled text.
     *
     * @param  string $text
     * @return string
     */
    protected function getDisabledTextWrapper($text)
    {
        return '<li class="disabled hide"><span>' . $text . '</span></li>';
    }

    /**
     * Get HTML wrapper for active text.
     *
     * @param  string $text
     * @return string
     */
    protected function getActivePageWrapper($text)
    {
        return '<li class="active"><span>' . $text . '</span></li>';
    }

    /**
     * Get a pagination "dot" element.
     *
     * @return string
     */
    protected function getDots()
    {
        return $this->getDisabledTextWrapper('...');
    }

    /**
     * Get the current page from the paginator.
     *
     * @return int
     */
    protected function currentPage()
    {
        return $this->paginator->currentPage();
    }

    /**
     * Get the last page from the paginator.
     *
     * @return int
     */
    protected function lastPage()
    {
        return $this->paginator->lastPage();
    }

}

就這麼簡單,主要就是render()方法,如果專案中需要修改分頁樣式,或者新增分頁跳轉之類的需求只要重寫其中的各項顯示的方法中的html元素就可以了,很靈活,在blade模板中也需要修該,比如我們的Paginator$users,預設的分頁顯示是這樣的:

{!! $users->render() !!}

修改成我們自定義後的分頁顯示:

{!! with(new \App\Foundations\Pagination\CustomerPresenter($categories))->render() !!}

好了,這樣在頁面應該就可以看到分頁連結中含有 "上一頁"和"下一頁"加數字的樣式了。

那麼如果擴充套件simplePaginate?其實很簡單,只要繼承剛才的CustomerPresenter,實現hasPagesrender,至於為什麼可以按照我上面檢視原始碼的方式看一下就知道了,比如我們改成"上一篇"和"下一篇"

新建App\Foundations\Pagination\CustomerSimplePresenter.php

<?php
namespace App\Foundations\Pagination;

use Illuminate\Support\HtmlString;
use Illuminate\Contracts\Pagination\Paginator as PaginatorContract;

class CustomerSimplePresenter extends CustomerPresenter
{
    /**
     * Create a simple Bootstrap 3 presenter.
     *
     * @param  \Illuminate\Contracts\Pagination\Paginator $paginator
     * @return void
     */
    public function __construct(PaginatorContract $paginator)
    {
        $this->paginator = $paginator;
    }

    /**
     * Determine if the underlying paginator being presented has pages to show.
     *
     * @return bool
     */
    public function hasPages()
    {
        return $this->paginator->hasPages() && count($this->paginator->items()) > 0;
    }

    /**
     * Convert the URL window into Bootstrap HTML.
     *
     * @return \Illuminate\Support\HtmlString
     */
    public function render()
    {
        if ($this->hasPages()) {
            return new HtmlString(sprintf(
                '<ul class="pager">%s %s</ul>',
                $this->getPreviousButton('上一篇'),
                $this->getNextButton('下一篇')
            ));
        }

        return '';
    }

}

分頁顯示:

{!! with(new \App\Foundations\Pagination\CustomerSimplePresenter($categories))->render() !!}

方法就是這個方法,具體修改按照自己需求重寫其中對應的顯示html元素的方法就可以了。

轉載請註明: 轉載自Ryan是菜鳥 | LNMP技術棧筆記

如果覺得本篇文章對您十分有益,何不 打賞一下

謝謝打賞

相關文章