request = $request; parent::__construct($list); } /** * Returns the GET var that is used to set the page start. This defaults * to "start". * * If there is more than one paginated list on a page, it is neccesary to * set a different get var for each using {@link setPaginationGetVar()}. * * @return string */ public function getPaginationGetVar() { return $this->getVar; } /** * Sets the GET var used to set the page start. * * @param string $var */ public function setPaginationGetVar($var) { $this->getVar = $var; } /** * Returns the number of items displayed per page. This defaults to 10. * * @return int. */ public function getPageLength() { return $this->pageLength; } /** * Set the number of items displayed per page. * * @param int $length */ public function setPageLength($length) { $this->pageLength = $length; } /** * Sets the current page. * * @param int $page */ public function setCurrentPage($page) { $this->pageStart = ($page - 1) * $this->pageLength; } /** * Returns the offset of the item the current page starts at. * * @return int */ public function getPageStart() { if ($this->pageStart === null) { if ($this->request && isset($this->request[$this->getVar])) { $this->pageStart = (int) $this->request[$this->getVar]; } else { $this->pageStart = 0; } } return $this->pageStart; } /** * Sets the offset of the item that current page starts at. This should be * a multiple of the page length. * * @param int $start */ public function setPageStart($start) { $this->pageStart = $start; } /** * Returns the total number of items in the unpaginated list. * * @return int */ public function getTotalItems() { if ($this->totalItems === null) { $this->totalItems = count($this->list); } return $this->totalItems; } /** * Sets the total number of items in the list. This is useful when doing * custom pagination. * * @param int $items */ public function setTotalItems($items) { $this->totalItems = $items; } /** * Sets the page length, page start and total items from a query object's * limit, offset and unlimited count. The query MUST have a limit clause. * * @param SQLQuery $query */ public function setPaginationFromQuery(SQLQuery $query) { if ($query->limit) { $this->setPageLength($query->limit['limit']); $this->setPageStart($query->limit['start']); $this->setTotalItems($query->unlimitedRowCount()); } } /** * @return IteratorIterator */ public function getIterator() { return new IteratorIterator( $this->list->getRange($this->getPageStart(), $this->pageLength) ); } /** * Returns a set of links to all the pages in the list. This is useful for * basic pagination. * * By default it returns links to every page, but if you pass the $max * parameter the number of pages will be limited to that number, centered * around the current page. * * @param int $max * @return DataObjectSet */ public function Pages($max = null) { $result = new DataObjectSet(); if ($max) { $start = ($this->CurrentPage() - floor($max / 2)) - 1; $end = $this->CurrentPage() + floor($max / 2); if ($start < 0) { $start = 0; $end = $max; } if ($end > $this->TotalPages()) { $end = $this->TotalPages(); $start = max(0, $end - $max); } } else { $start = 0; $end = $this->TotalPages(); } for ($i = $start; $i < $end; $i++) { $result->push(new ArrayData(array( 'PageNum' => $i + 1, 'Link' => HTTP::setGetVar($this->getVar, $i * $this->pageLength), 'CurrentBool' => $this->CurrentPage() == ($i + 1) ))); } return $result; } /** * Returns a summarised pagination which limits the number of pages shown * around the current page for visually balanced. * * Example: 25 pages total, currently on page 6, context of 4 pages * [prev] [1] ... [4] [5] [[6]] [7] [8] ... [25] [next] * * Example template usage: * * <% if MyPages.MoreThanOnePage %> * <% if MyPages.NotFirstPage %> * * <% end_if %> * <% control MyPages.PaginationSummary(4) %> * <% if CurrentBool %> * $PageNum * <% else %> * <% if Link %> * $PageNum * <% else %> * ... * <% end_if %> * <% end_if %> * <% end_control %> * <% if MyPages.NotLastPage %> * * <% end_if %> * <% end_if %> * * * @param int $context The number of pages to display around the current * page. The number should be event, as half the number of each pages * are displayed on either side of the current one. * @return DataObjectSet */ public function PaginationSummary($context = 4) { $result = new DataObjectSet(); $current = $this->CurrentPage(); $total = $this->TotalPages(); // Make the number even for offset calculations. if ($context % 2) { $context--; } // If the first or last page is current, then show all context on one // side of it - otherwise show half on both sides. if ($current == 1 || $current == $total) { $offset = $context; } else { $offset = floor($context / 2); } $left = max($current - $offset, 1); $range = range($current - $offset, $current + $offset); if ($left + $context > $total) { $left = $total - $context; } for ($i = 0; $i < $total; $i++) { $link = HTTP::setGetVar($this->getVar, $i * $this->pageLength); $num = $i + 1; $emptyRange = $num != 1 && $num != $total && ( $num == $left - 1 || $num == $left + $context + 1 ); if ($emptyRange) { $result->push(new ArrayData(array( 'PageNum' => null, 'Link' => null, 'CurrentBool' => false ))); } elseif ($num == 1 || $num == $total || in_array($num, $range)) { $result->push(new ArrayData(array( 'PageNum' => $num, 'Link' => $link, 'CurrentBool' => $current == $num ))); } } return $result; } /** * @return int */ public function CurrentPage() { return floor($this->getPageStart() / $this->pageLength) + 1; } /** * @return int */ public function TotalPages() { return ceil($this->getTotalItems() / $this->pageLength); } /** * @return bool */ public function MoreThanOnePage() { return $this->TotalPages() > 1; } /** * @return bool */ public function NotFirstPage() { return $this->CurrentPage() != 1; } /** * @return bool */ public function NotLastPage() { return $this->CurrentPage() != $this->TotalPages(); } /** * Returns the number of the first item being displayed on the current * page. This is useful for things like "displaying 10-20". * * @return int */ public function FirstItem() { return ($start = $this->getPageStart()) ? $start + 1 : 1; } /** * Returns the number of the last item being displayed on this page. * * @return int */ public function LastItem() { if ($start = $this->getPageStart()) { return min($start + $this->pageLength, $this->getTotalItems()); } else { return min($this->pageLength, $this->getTotalItems()); } } /** * Returns a link to the first page. * * @return string */ public function FirstLink() { return HTTP::setGetVar($this->getVar, 0); } /** * Returns a link to the last page. * * @return string */ public function LastLink() { return HTTP::setGetVar($this->getVar, ($this->TotalPages() - 1) * $this->pageLength); } /** * Returns a link to the next page, if there is another page after the * current one. * * @return string */ public function NextLink() { if ($this->NotLastPage()) { return HTTP::setGetVar($this->getVar, $this->getPageStart() + $this->pageLength); } } /** * Returns a link to the previous page, if the first page is not currently * active. * * @return string */ public function PrevLink() { if ($this->NotFirstPage()) { return HTTP::setGetVar($this->getVar, $this->getPageStart() - $this->pageLength); } } // DEPRECATED -------------------------------------------------------------- /** * @deprecated 3.0 Use individual getter methods. */ public function getPageLimits() { return array( 'pageStart' => $this->getPageStart(), 'pageLength' => $this->pageLength, 'totalSize' => $this->getTotalItems(), ); } /** * @deprecated 3.0 Use individual setter methods. */ public function setPageLimits($pageStart, $pageLength, $totalSize) { $this->setPageStart($pageStart); $this->setPageLength($pageLength); $this->setTotalSize($totalSize); } }