标签:
<?php namespace Illuminate\Pagination; use Closure; use ArrayIterator; abstract class AbstractPaginator { /** * All of the items being paginated. * * @var \Illuminate\Support\Collection */ protected $items; /** * The number of items to be shown per page. * * @var int */ protected $perPage; /** * The current page being "viewed". * * @var int */ protected $currentPage; /** * The base path to assign to all URLs. * * @var string */ protected $path = ‘/‘; /** * The query parameters to add to all URLs. * * @var array */ protected $query = []; /** * The URL fragment to add to all URLs. * * @var string|null */ protected $fragment = null; /** * The query string variable used to store the page. * * @var string */ protected $pageName = ‘page‘; /** * The current page resolver callback. * * @var \Closure */ protected static $currentPathResolver; /** * The current page resolver callback. * * @var \Closure */ protected static $currentPageResolver; /** * The default presenter resolver. * * @var \Closure */ protected static $presenterResolver; /** * Determine if the given value is a valid page number. * * @param int $page * @return bool */ protected function isValidPageNumber($page) { return $page >= 1 && filter_var($page, FILTER_VALIDATE_INT) !== false; } /** * Create a range of pagination URLs. * * @param int $start * @param int $end * @return string */ public function getUrlRange($start, $end) { $urls = []; for ($page = $start; $page <= $end; $page++) { $urls[$page] = $this->url($page); } return $urls; } /** * Get a URL for a given page number. * * @param int $page * @return string */ public function url($page) { if ($page <= 0) $page = 1; // If we have any extra query string key / value pairs that need to be added // onto the URL, we will put them in query string form and then attach it // to the URL. This allows for extra information like sortings storage. $parameters = [$this->pageName => $page]; if (count($this->query) > 0) { $parameters = array_merge($this->query, $parameters); } return $this->path.‘?‘ .http_build_query($parameters, null, ‘&‘) .$this->buildFragment(); } /** * Get the URL for the previous page. * * @return string|null */ public function previousPageUrl() { if ($this->currentPage() > 1) { return $this->url($this->currentPage() - 1); } } /** * Get / set the URL fragment to be appended to URLs. * * @param string|null $fragment * @return $this|string|null */ public function fragment($fragment = null) { if (is_null($fragment)) return $this->fragment; $this->fragment = $fragment; return $this; } /** * Add a set of query string values to the paginator. * * @param array|string $key * @param string|null $value * @return $this */ public function appends($key, $value = null) { if (is_array($key)) return $this->appendArray($key); return $this->addQuery($key, $value); } /** * Add an array of query string values. * * @param array $keys * @return $this */ protected function appendArray(array $keys) { foreach ($keys as $key => $value) { $this->addQuery($key, $value); } return $this; } /** * Add a query string value to the paginator. * * @param string $key * @param string $value * @return $this */ public function addQuery($key, $value) { if ($key !== $this->pageName) { $this->query[$key] = $value; } return $this; } /** * Build the full fragment portion of a URL. * * @return string */ protected function buildFragment() { return $this->fragment ? ‘#‘.$this->fragment : ‘‘; } /** * Get the slice of items being paginated. * * @return array */ public function items() { return $this->items->all(); } /** * Get the number of the first item in the slice. * * @return int */ public function firstItem() { return ($this->currentPage - 1) * $this->perPage + 1; } /** * Get the number of the last item in the slice. * * @return int */ public function lastItem() { return $this->firstItem() + $this->count() - 1; } /** * Get the number of items shown per page. * * @return int */ public function perPage() { return $this->perPage; } /** * Get the current page. * * @return int */ public function currentPage() { return $this->currentPage; } /** * Determine if there are enough items to split into multiple pages. * * @return bool */ public function hasPages() { return ! ($this->currentPage() == 1 && ! $this->hasMorePages()); } /** * Resolve the current request path or return the default value. * * @param string $default * @return string */ public static function resolveCurrentPath($default = ‘/‘) { if (isset(static::$currentPathResolver)) { return call_user_func(static::$currentPathResolver); } return $default; } /** * Set the current request path resolver callback. * * @param \Closure $resolver * @return void */ public static function currentPathResolver(Closure $resolver) { static::$currentPathResolver = $resolver; } /** * Resolve the current page or return the default value. * * @param int $default * @return int */ public static function resolveCurrentPage($default = 1) { if (isset(static::$currentPageResolver)) { return call_user_func(static::$currentPageResolver); } return $default; } /** * Set the current page resolver callback. * * @param \Closure $resolver * @return void */ public static function currentPageResolver(Closure $resolver) { static::$currentPageResolver = $resolver; } /** * Set the default Presenter resolver. * * @param \Closure $resolver * @return void */ public static function presenter(Closure $resolver) { static::$presenterResolver = $resolver; } /** * Set the query string variable used to store the page. * * @param string $name * @return $this */ public function setPageName($name) { $this->pageName = $name; return $this; } /** * Set the base path to assign to all URLs. * * @param string $path * @return $this */ public function setPath($path) { $this->path = $path; return $this; } /** * Get an iterator for the items. * * @return \ArrayIterator */ public function getIterator() { return new ArrayIterator($this->items->all()); } /** * Determine if the list of items is empty or not. * * @return bool */ public function isEmpty() { return $this->items->isEmpty(); } /** * Get the number of items for the current page. * * @return int */ public function count() { return $this->items->count(); } /** * Get the paginator‘s underlying collection. * * @return \Illuminate\Support\Collection */ public function getCollection() { return $this->items; } /** * Determine if the given item exists. * * @param mixed $key * @return bool */ public function offsetExists($key) { return $this->items->has($key); } /** * Get the item at the given offset. * * @param mixed $key * @return mixed */ public function offsetGet($key) { return $this->items->get($key); } /** * Set the item at the given offset. * * @param mixed $key * @param mixed $value * @return void */ public function offsetSet($key, $value) { $this->items->put($key, $value); } /** * Unset the item at the given key. * * @param mixed $key * @return void */ public function offsetUnset($key) { $this->items->forget($key); } /** * Make dynamic calls into the collection. * * @param string $method * @param array $parameters * @return mixed */ public function __call($method, $parameters) { return call_user_func_array([$this->getCollection(), $method], $parameters); } /** * Render the contents of the paginator when casting to string. * * @return string */ public function __toString() { return $this->render(); } }
1 <?php namespace Illuminate\Pagination; 2 3 trait BootstrapThreeNextPreviousButtonRendererTrait { 4 5 /** 6 * Get the previous page pagination element. 7 * 8 * @param string $text 9 * @return string 10 */ 11 protected function getPreviousButton($text = ‘«‘) 12 { 13 // If the current page is less than or equal to one, it means we can‘t go any 14 // further back in the pages, so we will render a disabled previous button 15 // when that is the case. Otherwise, we will give it an active "status". 16 if ($this->paginator->currentPage() <= 1) 17 { 18 return $this->getDisabledTextWrapper($text); 19 } 20 21 $url = $this->paginator->url( 22 $this->paginator->currentPage() - 1 23 ); 24 25 return $this->getPageLinkWrapper($url, $text, ‘prev‘); 26 } 27 28 /** 29 * Get the next page pagination element. 30 * 31 * @param string $text 32 * @return string 33 */ 34 protected function getNextButton($text = ‘»‘) 35 { 36 // If the current page is greater than or equal to the last page, it means we 37 // can‘t go any further into the pages, as we‘re already on this last page 38 // that is available, so we will make it the "next" link style disabled. 39 if ( ! $this->paginator->hasMorePages()) 40 { 41 return $this->getDisabledTextWrapper($text); 42 } 43 44 $url = $this->paginator->url($this->paginator->currentPage() + 1); 45 46 return $this->getPageLinkWrapper($url, $text, ‘next‘); 47 } 48 49 }
<?php namespace Illuminate\Pagination; 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 string */ public function render() { if ($this->hasPages()) { return 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="‘.$url.‘"‘.$rel.‘>‘.$page.‘</a></li>‘; } /** * Get HTML wrapper for disabled text. * * @param string $text * @return string */ protected function getDisabledTextWrapper($text) { return ‘<li class="disabled"><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(); } }
<?php namespace Illuminate\Pagination; use Countable; use ArrayAccess; use IteratorAggregate; use Illuminate\Support\Collection; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Pagination\Presenter; use Illuminate\Contracts\Pagination\LengthAwarePaginator as LengthAwarePaginatorContract; class LengthAwarePaginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, LengthAwarePaginatorContract { /** * The total number of items before slicing. * * @var int */ protected $total; /** * The last available page. * * @var int */ protected $lastPage; /** * Create a new paginator instance. * * @param mixed $items * @param int $total * @param int $perPage * @param int|null $currentPage * @param array $options (path, query, fragment, pageName) * @return void */ public function __construct($items, $total, $perPage, $currentPage = null, array $options = []) { foreach ($options as $key => $value) { $this->{$key} = $value; } $this->total = $total; $this->perPage = $perPage; $this->lastPage = (int) ceil($total / $perPage); $this->currentPage = $this->setCurrentPage($currentPage, $this->lastPage); $this->path = $this->path != ‘/‘ ? rtrim($this->path, ‘/‘).‘/‘ : $this->path; $this->items = $items instanceof Collection ? $items : Collection::make($items); } /** * Get the current page for the request. * * @param int $currentPage * @param int $lastPage * @return int */ protected function setCurrentPage($currentPage, $lastPage) { $currentPage = $currentPage ?: static::resolveCurrentPage(); // The page number will get validated and adjusted if it either less than one // or greater than the last page available based on the count of the given // items array. If it‘s greater than the last, we‘ll give back the last. if (is_numeric($currentPage) && $currentPage > $lastPage) { return $lastPage > 0 ? $lastPage : 1; } return $this->isValidPageNumber($currentPage) ? (int) $currentPage : 1; } /** * Get the URL for the next page. * * @return string */ public function nextPageUrl() { if ($this->lastPage() > $this->currentPage()) { return $this->url($this->currentPage() + 1); } } /** * Determine if there are more items in the data source. * * @return bool */ public function hasMorePages() { return $this->currentPage() < $this->lastPage(); } /** * Get the total number of items being paginated. * * @return int */ public function total() { return $this->total; } /** * Get the last page. * * @return int */ public function lastPage() { return $this->lastPage; } /** * Render the paginator using the given presenter. * * @param \Illuminate\Contracts\Pagination\Presenter|null $presenter * @return string */ 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(); } /** * Get the instance as an array. * * @return array */ public function toArray() { return [ ‘total‘ => $this->total(), ‘per_page‘ => $this->perPage(), ‘current_page‘ => $this->currentPage(), ‘last_page‘ => $this->lastPage(), ‘next_page_url‘ => $this->nextPageUrl(), ‘prev_page_url‘ => $this->previousPageUrl(), ‘from‘ => $this->firstItem(), ‘to‘ => $this->lastItem(), ‘data‘ => $this->items->toArray() ]; } /** * Convert the object to its JSON representation. * * @param int $options * @return string */ public function toJson($options = 0) { return json_encode($this->toArray(), $options); } }
<?php namespace Illuminate\Pagination; use Illuminate\Support\ServiceProvider; class PaginationServiceProvider extends ServiceProvider { /** * Register the service provider. * * @return void */ public function register() { Paginator::currentPathResolver(function() { return $this->app[‘request‘]->url(); }); Paginator::currentPageResolver(function() { return $this->app[‘request‘]->input(‘page‘); }); } }
<?php namespace Illuminate\Pagination; use Countable; use ArrayAccess; use IteratorAggregate; use Illuminate\Support\Collection; use Illuminate\Contracts\Support\Jsonable; use Illuminate\Contracts\Support\Arrayable; use Illuminate\Contracts\Pagination\Presenter; use Illuminate\Contracts\Pagination\Paginator as PaginatorContract; class Paginator extends AbstractPaginator implements Arrayable, ArrayAccess, Countable, IteratorAggregate, Jsonable, PaginatorContract { /** * Determine if there are more items in the data source. * * @return bool */ protected $hasMore; /** * Create a new paginator instance. * * @param mixed $items * @param int $perPage * @param int|null $currentPage * @param array $options (path, query, fragment, pageName) * @return void */ public function __construct($items, $perPage, $currentPage = null, array $options = []) { foreach ($options as $key => $value) { $this->{$key} = $value; } $this->perPage = $perPage; $this->currentPage = $this->setCurrentPage($currentPage); $this->path = $this->path != ‘/‘ ? rtrim($this->path, ‘/‘).‘/‘ : $this->path; $this->items = $items instanceof Collection ? $items : Collection::make($items); $this->checkForMorePages(); } /** * Get the current page for the request. * * @param int $currentPage * @return int */ protected function setCurrentPage($currentPage) { $currentPage = $currentPage ?: static::resolveCurrentPage(); return $this->isValidPageNumber($currentPage) ? (int) $currentPage : 1; } /** * Check for more pages. The last item will be sliced off. * * @return void */ protected function checkForMorePages() { $this->hasMore = count($this->items) > ($this->perPage); $this->items = $this->items->slice(0, $this->perPage); } /** * Get the URL for the next page. * * @return string|null */ public function nextPageUrl() { if ($this->hasMore) { return $this->url($this->currentPage() + 1); } } /** * Determine if there are more items in the data source. * * @return bool */ public function hasMorePages() { return $this->hasMore; } /** * Render the paginator using the given presenter. * * @param \Illuminate\Contracts\Pagination\Presenter|null $presenter * @return string */ public function render(Presenter $presenter = null) { if (is_null($presenter) && static::$presenterResolver) { $presenter = call_user_func(static::$presenterResolver, $this); } $presenter = $presenter ?: new SimpleBootstrapThreePresenter($this); return $presenter->render(); } /** * Get the instance as an array. * * @return array */ public function toArray() { return [ ‘per_page‘ => $this->perPage(), ‘current_page‘ => $this->currentPage(), ‘next_page_url‘ => $this->nextPageUrl(), ‘prev_page_url‘ => $this->previousPageUrl(), ‘from‘ => $this->firstItem(), ‘to‘ => $this->lastItem(), ‘data‘ => $this->items->toArray() ]; } /** * Convert the object to its JSON representation. * * @param int $options * @return string */ public function toJson($options = 0) { return json_encode($this->toArray(), $options); } }
<?php namespace Illuminate\Pagination; use Illuminate\Contracts\Pagination\Paginator as PaginatorContract; class SimpleBootstrapThreePresenter extends BootstrapThreePresenter { /** * 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 string */ public function render() { if ($this->hasPages()) { return sprintf( ‘<ul class="pager">%s %s</ul>‘, $this->getPreviousButton(), $this->getNextButton() ); } return ‘‘; } }
<?php namespace Illuminate\Pagination; use Illuminate\Contracts\Pagination\LengthAwarePaginator as PaginatorContract; class UrlWindow { /** * The paginator implementation. * * @var \Illuminate\Contracts\Pagination\LengthAwarePaginator */ protected $paginator; /** * Create a new URL window instance. * * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator * @return void */ public function __construct(PaginatorContract $paginator) { $this->paginator = $paginator; } /** * Create a new URL window instance. * * @param \Illuminate\Contracts\Pagination\LengthAwarePaginator $paginator * @param int $onEachSide * @return array */ public static function make(PaginatorContract $paginator, $onEachSide = 3) { return (new static($paginator))->get($onEachSide); } /** * Get the window of URLs to be shown. * * @param int $onEachSide * @return array */ public function get($onEachSide = 3) { if ($this->paginator->lastPage() < ($onEachSide * 2) + 6) { return $this->getSmallSlider(); } return $this->getUrlSlider($onEachSide); } /** * Get the slider of URLs there are not enough pages to slide. * * @return array */ protected function getSmallSlider() { return [ ‘first‘ => $this->paginator->getUrlRange(1, $this->lastPage()), ‘slider‘ => null, ‘last‘ => null ]; } /** * Create a URL slider links. * * @param int $onEachSide * @return array */ protected function getUrlSlider($onEachSide) { $window = $onEachSide * 2; if ( ! $this->hasPages()) { return [ ‘first‘ => null, ‘slider‘ => null, ‘last‘ => null ]; } // If the current page is very close to the beginning of the page range, we will // just render the beginning of the page range, followed by the last 2 of the // links in this list, since we will not have room to create a full slider. if ($this->currentPage() <= $window) { return $this->getSliderTooCloseToBeginning($window); } // If the current page is close to the ending of the page range we will just get // this first couple pages, followed by a larger window of these ending pages // since we‘re too close to the end of the list to create a full on slider. elseif ($this->currentPage() > ($this->lastPage() - $window)) { return $this->getSliderTooCloseToEnding($window); } // If we have enough room on both sides of the current page to build a slider we // will surround it with both the beginning and ending caps, with this window // of pages in the middle providing a Google style sliding paginator setup. return $this->getFullSlider($onEachSide); } /** * Get the slider of URLs when too close to beginning of window. * * @param int $window * @return array */ protected function getSliderTooCloseToBeginning($window) { return [ ‘first‘ => $this->paginator->getUrlRange(1, $window + 2), ‘slider‘ => null, ‘last‘ => $this->getFinish() ]; } /** * Get the slider of URLs when too close to ending of window. * * @param int $window * @return array */ protected function getSliderTooCloseToEnding($window) { $last = $this->paginator->getUrlRange( $this->lastPage() - ($window + 2), $this->lastPage() ); return [ ‘first‘ => $this->getStart(), ‘slider‘ => null, ‘last‘ => $last ]; } /** * Get the slider of URLs when a full slider can be made. * * @param int $onEachSide * @return array */ protected function getFullSlider($onEachSide) { return [ ‘first‘ => $this->getStart(), ‘slider‘ => $this->getAdjacentUrlRange($onEachSide), ‘last‘ => $this->getFinish() ]; } /** * Get the page range for the current page window. * * @param int $onEachSide * @return array */ public function getAdjacentUrlRange($onEachSide) { return $this->paginator->getUrlRange( $this->currentPage() - $onEachSide, $this->currentPage() + $onEachSide ); } /** * Get the starting URLs of a pagination slider. * * @return array */ public function getStart() { return $this->paginator->getUrlRange(1, 2); } /** * Get the ending URLs of a pagination slider. * * @return array */ public function getFinish() { return $this->paginator->getUrlRange( $this->lastPage() - 1, $this->lastPage() ); } /** * Determine if the underlying paginator being presented has pages to show. * * @return bool */ public function hasPages() { return $this->paginator->lastPage() > 1; } /** * 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(); } }
<?php namespace Illuminate\Pagination; trait UrlWindowPresenterTrait { /** * Render the actual link slider. * * @return string */ protected function getLinks() { $html = ‘‘; if (is_array($this->window[‘first‘])) { $html .= $this->getUrlLinks($this->window[‘first‘]); } if (is_array($this->window[‘slider‘])) { $html .= $this->getDots(); $html .= $this->getUrlLinks($this->window[‘slider‘]); } if (is_array($this->window[‘last‘])) { $html .= $this->getDots(); $html .= $this->getUrlLinks($this->window[‘last‘]); } return $html; } /** * Get the links for the URLs in the given array. * * @param array $urls * @return string */ protected function getUrlLinks(array $urls) { $html = ‘‘; foreach ($urls as $page => $url) { $html .= $this->getPageLinkWrapper($url, $page); } return $html; } /** * Get HTML wrapper for a page link. * * @param string $url * @param int $page * @param string|null $rel * @return string */ protected function getPageLinkWrapper($url, $page, $rel = null) { if ($page == $this->paginator->currentPage()) { return $this->getActivePageWrapper($page); } return $this->getAvailablePageWrapper($url, $page, $rel); } }
标签:
原文地址:http://www.cnblogs.com/chenjianxiang/p/4433305.html