Skip to content

Instantly share code, notes, and snippets.

@mcfog
Created January 3, 2015 03:32
Show Gist options
  • Save mcfog/2df96e37fc7fe3edbc6e to your computer and use it in GitHub Desktop.
Save mcfog/2df96e37fc7fe3edbc6e to your computer and use it in GitHub Desktop.

Revisions

  1. mcfog created this gist Jan 3, 2015.
    213 changes: 213 additions & 0 deletions Paginator.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,213 @@
    <?php

    class Paginator implements \IteratorAggregate
    {
    const TPL_WRAPPER = 'wrapper';
    const TPL_NUM = 'num';
    const TPL_NUM_CURRENT = 'currentNum';
    const TPL_TAG = 'tag';
    const TPL_NEXT = 'next';
    const TPL_PREV = 'prev';
    const TPL_TEXT = 'text';
    const CFG_FIELD_NAME = 'fieldName';
    /**
    * 当前页前后显示几页
    */
    const CFG_NUM_MIDDLE = 'middleNum';
    /**
    * 末页前显示几页
    */
    const CFG_NUM_TAIL = 'tailNum';
    /**
    * 首页后显示几页
    */
    const CFG_NUM_HEAD = 'headNum';

    protected $app;
    protected $data;

    /**
    * @var IListProvider
    */
    protected $list;

    protected $config = [
    self::CFG_NUM_HEAD => 1,
    self::CFG_NUM_TAIL => 1,
    self::CFG_NUM_MIDDLE => 2,
    self::CFG_FIELD_NAME => 'page',
    ];

    protected $template = [
    self::TPL_WRAPPER => <<<'HTML'
    <div class="page_right fontsize9 fontcolor3">%s</div>
    HTML
    ,
    self::TPL_NUM => <<<'HTML'
    <a class="p_num" href="%2$s">%1$d</a>
    HTML
    ,
    self::TPL_NUM_CURRENT => <<<'HTML'
    <a class="p_num selected">%1$d</a>
    HTML
    ,
    self::TPL_TAG => <<<'HTML'
    <a class="p_num first_or_last" href="%2$s">%1$s</a>
    HTML
    ,
    self::TPL_TEXT => <<<'HTML'
    <span class="page_dian">%s</span>
    HTML
    ,
    self::TPL_NEXT => <<<'HTML'
    <a class="p_num next" href="%1$s">下一页</a>
    HTML
    ,
    self::TPL_PREV => <<<'HTML'
    <a class="p_num previous" href="%1$s">上一页</a>
    HTML
    ,
    ];
    /**
    * @var string
    */
    protected $urlBase;

    /**
    * @param Site $app
    * @param IListProvider $list
    * @param string $urlBase
    */
    public function __construct(Site $app, IListProvider $list, $urlBase = null)
    {
    if (is_null($urlBase)) {
    $urlBase = $app->request->getPath();
    }

    $this->app = $app;
    $this->list = $list;
    $this->urlBase = $urlBase;
    }

    /**
    * (PHP 5 &gt;= 5.0.0)<br/>
    * Retrieve an external iterator
    * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
    * @return Traversable An instance of an object implementing <b>Iterator</b> or
    * <b>Traversable</b>
    */
    public function getIterator()
    {
    return new \ArrayIterator($this->getData());
    }

    public function renderPaginator()
    {
    $maxPage = $this->getMaxPage();
    $curPage = $this->getCurrentPage();

    if($maxPage <= 1) {
    return '';
    }

    $contents = [];
    // $contents[] = $this->renderTpl(self::TPL_TAG, '首页', $this->getUrlForPage(1));
    if ($curPage !== 1) {
    $contents[] = $this->renderTpl(self::TPL_PREV, $this->getUrlForPage($curPage - 1));
    }

    for ($i = 1; $i <= $maxPage; $i++) {
    $middleCount = $this->config[self::CFG_NUM_MIDDLE];
    switch (true) {
    case $i === $curPage:
    $contents[] = $this->renderTpl(self::TPL_NUM_CURRENT, $i);
    break;
    case $i >= $curPage - $middleCount && $i <= $curPage + $middleCount:
    case $i <= $this->config[self::CFG_NUM_HEAD]:
    case $i > $maxPage - $this->config[self::CFG_NUM_TAIL]:
    $contents[] = $this->renderTpl(self::TPL_NUM, $i, $this->getUrlForPage($i));
    break;
    default:
    if ($i < $curPage) {
    $contents[] = $this->renderTpl(self::TPL_TEXT, '...');
    $i = $curPage - $middleCount - 1;
    } else {
    $contents[] = $this->renderTpl(self::TPL_TEXT, '...');
    $i = $maxPage - $this->config[self::CFG_NUM_TAIL];
    }
    }
    }

    if ($curPage !== $maxPage) {
    $contents[] = $this->renderTpl(self::TPL_NEXT, $this->getUrlForPage($curPage + 1));
    }
    // $contents[] = $this->renderTpl(self::TPL_TAG, '末页', $this->getUrlForPage($maxPage));

    return $this->renderTpl(self::TPL_WRAPPER, implode('', $contents));
    }

    public function getUrlForPage($page)
    {
    $part = parse_url($this->urlBase);
    $query = [];
    if (isset($part['query'])) {
    parse_str($part['query'], $query);
    }
    $query[$this->config[self::CFG_FIELD_NAME]] = $page;

    if (!isset($part['path'])) {
    $part['path'] = '/';
    }

    return sprintf('%s?%s', $part['path'], http_build_query($query));
    }

    protected function renderTpl($tpl)
    {
    $args = func_get_args();
    $args[0] = $this->template[$tpl];

    return call_user_func_array('sprintf', $args);
    }

    /**
    * @return int
    */
    protected function getCurrentPage()
    {
    $page = intval($this->app->request->get($this->config[self::CFG_FIELD_NAME]));

    return min(max($page, 1), $this->getMaxPage());
    }

    protected function getPager()
    {
    return $this->list->getPager();
    }

    public function getItemCount()
    {
    $pager = $this->getPager();

    return intval($pager['count']);
    }

    public function getMaxPage()
    {
    $pager = $this->getPager();

    return intval($pager['maxPage']);
    }

    /**
    * @return array
    */
    protected function getData()
    {
    if (!isset($this->data)) {
    $this->data = $this->list->fetch($this->getCurrentPage());
    }

    return $this->data;
    }
    }