2016年10月26日 星期三

Laravel5.1+ 分页 Pagination 解析以及扩展

本文最早发表于本人博客: Laravel5.1+ 分页Pagination解析以及扩展
Laravel 的分页很方便,其实扩展起来也挺容易的,下面就来做个示例,扩展一下paginate()和 simplePaginate()方法,来实现我们自定义分页样式,比如显示"上一页""下一页",而不是"《""》",当然扩展的方法掌握了你就可以肆无忌惮的扩展一个你想要的分页了,比如跳转到某一页,分页显示一共多少记录,当前显示的记录范围等等巴拉巴拉的。。。
5.1和5.2应该是同样的方法,我这里用的是5.2的版本。文档告诉我们Paginator 对应于查询语句构造器和 Eloquent 的 simplePaginate 方法,而 LengthAwarePaginator则等同于 paginate 方法。那我们还是来看下源码,具体这个 paginate 是如何实现render()的,
  • Illuminate/Pagination/LengthAwarePaginator.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方法来实现分页的显示的。如果没有则调用BootstrapThreePresenter 中render()的,来看看BootstrapThreePresenter是干嘛的
  • Illuminate/Pagination/BootstrapThreePresenter.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(
                '
    %s %s %s
'
, $this->getPreviousButton(), $this->getLinks(), $this->getNextButton() )); } return ''; } ...... }
这里可以看到BootstrapThreePresenter实现了PresenterContract 的接口,render() 才是分页显示的真正实现,构造方法中的第一个参数PaginatorContract 其实就是一个Paginator我们继续看下PresenterContract也就是Presenter接口中定义了什么方法需要实现
  • illuminate/contracts/Pagination/Presenter.php
其中定义了renderhasPages方法需要实现
好了,那我们现在已经很清晰了,我们要自定义分页的显示,那么就要写一个我们自己的Presenter来实现接口中的render()hasPages()就可以了。
首先就来简单的实现一个paginate(),显示出来"上一页"和"下一页",中间是分页数字的例子。
新建文件如下(个人习惯)app/Foundations/Pagination/CustomerPresenter.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(
                '
    %s %s %s
'
, $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 '
  • .
  • htmlentities($url) . '"' . $rel . '>' . $page . '
    '; } /** * Get HTML wrapper for disabled text. * * @param string $text * @return string */ protected function getDisabledTextWrapper($text) { return '
  • ' . $text . '
  • '
    ; } /** * Get HTML wrapper for active text. * * @param string $text * @return string */ protected function getActivePageWrapper($text) { return '
  • ' . $text . '
  • '
    ; } /** * 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
    
    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(
                    '
      %s %s
    '
    , $this->getPreviousButton('上一篇'), $this->getNextButton('下一篇') )); } return ''; } }
    分页显示:
    {!! with(new \App\Foundations\Pagination\CustomerSimplePresenter($categories))->render() !!}
    方法就是这个方法,具体修改按照自己需求重写其中对应的显示html元素的方法就可以了。

    from : https://laravel-china.org/topics/2117

    沒有留言:

    wibiya widget