| | <?php |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | namespace think; |
| |
|
| | use ArrayAccess; |
| | use ArrayIterator; |
| | use Countable; |
| | use IteratorAggregate; |
| | use JsonSerializable; |
| | use Traversable; |
| |
|
| | abstract class Paginator implements ArrayAccess, Countable, IteratorAggregate, JsonSerializable |
| | { |
| | |
| | protected $simple = false; |
| |
|
| | |
| | protected $items; |
| |
|
| | |
| | protected $currentPage; |
| |
|
| | |
| | protected $lastPage; |
| |
|
| | |
| | protected $total; |
| |
|
| | |
| | protected $listRows; |
| |
|
| | |
| | protected $hasMore; |
| |
|
| | |
| | protected $options = [ |
| | 'var_page' => 'page', |
| | 'path' => '/', |
| | 'query' => [], |
| | 'fragment' => '', |
| | ]; |
| |
|
| | |
| | protected $nextItem; |
| |
|
| | public function __construct($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = []) |
| | { |
| | $this->options = array_merge($this->options, $options); |
| |
|
| | $this->options['path'] = '/' != $this->options['path'] ? rtrim($this->options['path'], '/') : $this->options['path']; |
| |
|
| | $this->simple = $simple; |
| | $this->listRows = $listRows; |
| |
|
| | if (!$items instanceof Collection) { |
| | $items = Collection::make($items); |
| | } |
| |
|
| | if ($simple) { |
| | $this->currentPage = $this->setCurrentPage($currentPage); |
| | $this->hasMore = count($items) > ($this->listRows); |
| | if ($this->hasMore) { |
| | $this->nextItem = $items->slice($this->listRows, 1); |
| | } |
| | $items = $items->slice(0, $this->listRows); |
| | } else { |
| | $this->total = $total; |
| | $this->lastPage = (int) ceil($total / $listRows); |
| | $this->currentPage = $this->setCurrentPage($currentPage); |
| | $this->hasMore = $this->currentPage < $this->lastPage; |
| | } |
| | $this->items = $items; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function make($items, $listRows, $currentPage = null, $total = null, $simple = false, $options = []) |
| | { |
| | return new static($items, $listRows, $currentPage, $total, $simple, $options); |
| | } |
| |
|
| | protected function setCurrentPage($currentPage) |
| | { |
| | if (!$this->simple && $currentPage > $this->lastPage) { |
| | return $this->lastPage > 0 ? $this->lastPage : 1; |
| | } |
| |
|
| | return $currentPage; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | protected function url($page) |
| | { |
| | if ($page <= 0) { |
| | $page = 1; |
| | } |
| |
|
| | if (strpos($this->options['path'], '[PAGE]') === false) { |
| | $parameters = [$this->options['var_page'] => $page]; |
| | $path = $this->options['path']; |
| | } else { |
| | $parameters = []; |
| | $path = str_replace('[PAGE]', $page, $this->options['path']); |
| | } |
| | if (count($this->options['query']) > 0) { |
| | $parameters = array_merge($this->options['query'], $parameters); |
| | } |
| | $url = $path; |
| | if (!empty($parameters)) { |
| | $url .= '?' . http_build_query($parameters, null, '&'); |
| | } |
| | return $url . $this->buildFragment(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public static function getCurrentPage($varPage = 'page', $default = 1) |
| | { |
| | $page = (int) Request::instance()->param($varPage); |
| |
|
| | if (filter_var($page, FILTER_VALIDATE_INT) !== false && $page >= 1) { |
| | return $page; |
| | } |
| |
|
| | return $default; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | public static function getCurrentPath() |
| | { |
| | return Request::instance()->baseUrl(); |
| | } |
| |
|
| | public function total() |
| | { |
| | if ($this->simple) { |
| | throw new \DomainException('not support total'); |
| | } |
| | return $this->total; |
| | } |
| |
|
| | public function listRows() |
| | { |
| | return $this->listRows; |
| | } |
| |
|
| | public function currentPage() |
| | { |
| | return $this->currentPage; |
| | } |
| |
|
| | public function lastPage() |
| | { |
| | if ($this->simple) { |
| | throw new \DomainException('not support last'); |
| | } |
| | return $this->lastPage; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | public function hasPages() |
| | { |
| | return !(1 == $this->currentPage && !$this->hasMore); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public function getUrlRange($start, $end) |
| | { |
| | $urls = []; |
| |
|
| | for ($page = $start; $page <= $end; $page++) { |
| | $urls[$page] = $this->url($page); |
| | } |
| |
|
| | return $urls; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public function fragment($fragment) |
| | { |
| | $this->options['fragment'] = $fragment; |
| | return $this; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | public function appends($key, $value = null) |
| | { |
| | if (!is_array($key)) { |
| | $queries = [$key => $value]; |
| | } else { |
| | $queries = $key; |
| | } |
| |
|
| | foreach ($queries as $k => $v) { |
| | if ($k !== $this->options['var_page']) { |
| | $this->options['query'][$k] = $v; |
| | } |
| | } |
| |
|
| | return $this; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | protected function buildFragment() |
| | { |
| | return $this->options['fragment'] ? '#' . $this->options['fragment'] : ''; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | abstract public function render(); |
| |
|
| | public function items() |
| | { |
| | return $this->items->all(); |
| | } |
| |
|
| | public function getCollection() |
| | { |
| | return $this->items; |
| | } |
| |
|
| | public function isEmpty() |
| | { |
| | return $this->items->isEmpty(); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public function each(callable $callback) |
| | { |
| | foreach ($this->items as $key => $item) { |
| | $result = $callback($item, $key); |
| | if (false === $result) { |
| | break; |
| | } elseif (!is_object($item)) { |
| | $this->items[$key] = $result; |
| | } |
| | } |
| |
|
| | return $this; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public function getIterator() |
| | { |
| | return new ArrayIterator($this->items->all()); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public function offsetExists($offset) |
| | { |
| | return $this->items->offsetExists($offset); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public function offsetGet($offset) |
| | { |
| | return $this->items->offsetGet($offset); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | public function offsetSet($offset, $value) |
| | { |
| | $this->items->offsetSet($offset, $value); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | public function offsetUnset($offset) |
| | { |
| | $this->items->offsetUnset($offset); |
| | } |
| |
|
| | |
| | |
| | |
| | public function count() |
| | { |
| | return $this->items->count(); |
| | } |
| |
|
| | public function __toString() |
| | { |
| | return (string) $this->render(); |
| | } |
| |
|
| | public function toArray() |
| | { |
| | if ($this->simple) { |
| | return [ |
| | 'per_page' => $this->listRows, |
| | 'current_page' => $this->currentPage, |
| | 'has_more' => $this->hasMore, |
| | 'next_item' => $this->nextItem, |
| | 'data' => $this->items->toArray(), |
| | ]; |
| | } else { |
| | return [ |
| | 'total' => $this->total, |
| | 'per_page' => $this->listRows, |
| | 'current_page' => $this->currentPage, |
| | 'last_page' => $this->lastPage, |
| | 'data' => $this->items->toArray(), |
| | ]; |
| | } |
| |
|
| | } |
| |
|
| | |
| | |
| | |
| | public function jsonSerialize() |
| | { |
| | return $this->toArray(); |
| | } |
| |
|
| | public function __call($name, $arguments) |
| | { |
| | $collection = $this->getCollection(); |
| |
|
| | $result = call_user_func_array([$collection, $name], $arguments); |
| |
|
| | if ($result === $collection) { |
| | return $this; |
| | } |
| |
|
| | return $result; |
| | } |
| |
|
| | } |
| |
|