* Copyright 2001-2012 Strangecode, LLC
*
* This file is part of The Strangecode Codebase.
*
* The Strangecode Codebase is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* The Strangecode Codebase is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* The Strangecode Codebase. If not, see .
*/
/**
* PageNumbers.inc.php
*
* The PageNumbers class provides a common abstracted interface to the
* multiple pages features. It sets the various numbers needed to display items
* on a page, and includes functions for working with these numbers.
* You must call set setTotalItems(), setPerPage() and setPageNumber() before calling calculate()
* this the other various values will be set automatically. Then you can call printPerPageLinks,
* printPageNumbers, etc, and use the various page object properties in your page templates.
*
* @author Quinn Comendant
* @version 1.61
*/
require_once dirname(__FILE__) . '/Prefs.inc.php';
class PageNumbers
{
public $total_items; // Total quantity of items.
public $total_pages; // The total number of pages.
public $current_page = 1; // Current page number.
public $first_item; // The counter for the first item on this page (zero index).
public $last_item; // The counter for the last item on this page (zero index).
public $max_num_links = 5; // The max number of links to show on page (odd numbers look best).
protected $_num_links; // The number of links to show on page.
protected $_per_page = 50; // Items per page.
// Flags to ensure all necessary values have been set before calling calculate().
public $set_per_page_initialized = false;
public $set_page_number_initialized = false;
public $set_total_items_initialized = false;
// These are initialized in the constructor.
public $per_page_options;
public $left_arrow;
public $left_arrow_disabled;
public $left_dbl_arrow;
public $left_dbl_arrow_disabled;
public $right_arrow;
public $right_arrow_disabled;
public $right_dbl_arrow;
public $right_dbl_arrow_disabled;
public $url_base;
public $prefs;
/**
* PageNumbers constructor. All arguments are depreciated. Use set* functions instead.
*/
public function __construct()
{
// Default options for the quantity per page links.
$this->per_page_options = array(50, 100, 250, 1000);
// Default options for the page number links.
$this->left_arrow = _("back");
$this->left_arrow_disabled = '' . _("back") . '';
$this->left_dbl_arrow = '«';
$this->left_dbl_arrow_disabled = '«';
$this->right_arrow = _("next");
$this->right_arrow_disabled = '' . _("next") . '';
$this->right_dbl_arrow = '»';
$this->right_dbl_arrow_disabled = '»';
// Default url base. This will be set manually after instantiation
// in special cases like using a /my/page/# scheme.
$this->url_base = $_SERVER['PHP_SELF'] . '?page_number=';
$this->prefs = new Prefs($_SERVER['PHP_SELF']);
$this->prefs->setParam(array('persistent' => false));
}
private function _validNumber($num)
{
if (!isset($num) || '' === $num) {
return false;
}
return preg_match('/^\d+$/', $num);
}
/**
* Set the number of items per page.
*/
public function setPerPage($per_page, $default=25, $save_value=true)
{
// (1) By provided argument, if valid.
// (2) By saved preference, if available.
// (3) Set to default value if provided and valid.
// (4) Keep as Class default of 25.
if ($this->_validNumber($per_page) && $per_page > 0) {
$this->_per_page = $per_page;
if ($save_value) {
$this->prefs->set('items_per_page', $this->_per_page);
}
} else if ($save_value && $this->prefs->exists('items_per_page')) {
$this->_per_page = (int)$this->prefs->get('items_per_page');
} else if ($this->_validNumber($default) && $default > 0) {
$this->_per_page = $default;
}
$this->set_per_page_initialized = true;
}
/**
* Set the current page number.
*/
public function setPageNumber($page_number, $save_value=true)
{
// (1) By provided argument, if valid.
// (2) By saved preference, if available.
// (3) Don't change from what was provided at class instantiation.
if ($this->_validNumber($page_number)) {
if ($page_number < 1) {
// FIXME: How to go back around to the last page? Hmmm. Set to 1 for now.
$this->current_page = 1;
} else {
$this->current_page = $page_number;
}
if ($save_value) {
$this->prefs->set('page_number', $this->current_page);
}
} else if ($save_value && $this->prefs->exists('page_number')) {
$this->current_page = (int)$this->prefs->get('page_number');
}
$this->set_page_number_initialized = true;
}
/**
* Set the total number of items.
*/
public function setTotalItems($total_items)
{
if ($this->_validNumber($total_items) && $total_items > 0) {
$this->total_items = $total_items;
} else {
$this->total_items = 0;
}
$this->set_total_items_initialized = true;
}
/**
* After $total_items or other options are set, this function calculates
* all the other numbers needed. If you set any variables manually,
* for example if $page_number comes from
* some place other than the GET or POST array, you should call this
* function manually, otherwise it happens at object instantiation.
*
* @access public
*/
public function calculate()
{
$app =& App::getInstance();
if (!$this->set_per_page_initialized) {
$app->logMsg(sprintf('set_per_page not initialized'), LOG_ERR, __FILE__, __LINE__);
}
if (!$this->set_page_number_initialized) {
$app->logMsg(sprintf('set_page_number not initialized'), LOG_ERR, __FILE__, __LINE__);
}
if (!$this->set_total_items_initialized) {
$app->logMsg(sprintf('set_total_items not initialized'), LOG_ERR, __FILE__, __LINE__);
}
// If the specified page exceeds total pages or is less than 1, set the page to 1.
if ($this->_per_page * $this->current_page >= $this->total_items + $this->_per_page || $this->_per_page * $this->current_page < 1) {
$this->current_page = 1;
}
// The first item to be shown on this page.
$this->first_item = ($this->current_page - 1) * $this->_per_page;
// The last item to be shown on this page.
if ($this->total_items < $this->current_page * $this->_per_page) {
$this->last_item = $this->total_items - 1;
} else {
$this->last_item = $this->current_page * $this->_per_page - 1;
}
// Zeroing. Just in case. Paranoia. Yeah, negative numbers perturb me.
if ($this->first_item < 1) {
$this->first_item = 0;
}
if ($this->last_item < 1) {
$this->last_item = 0;
}
if ($this->total_items < 1) {
$this->total_items = 0;
}
// The total number of pages.
$this->total_pages = ceil($this->total_items / $this->_per_page);
// Figure out how many page number links to print.
if ($this->total_pages >= $this->max_num_links) {
$this->_num_links = $this->max_num_links;
} else {
$this->_num_links = $this->total_pages;
}
}
/**
* Returns the SQL code to limit query to items that are on current page.
*/
public function getLimitSQL()
{
$app =& App::getInstance();
$db =& DB::getInstance();
if ($this->_validNumber($this->first_item) && $this->_validNumber($this->_per_page)) {
return ' LIMIT ' . $db->escapeString($this->first_item) . ', ' . $db->escapeString($this->_per_page) . ' ';
} else {
$app->logMsg(sprintf('Could not find SQL to LIMIT by %s %s.', $this->first_item, $this->_per_page), LOG_WARNING, __FILE__, __LINE__);
return '';
}
}
/**
* Prints links to change the number of items shown per page.
*
* @access public
*/
public function printPerPageLinks($query_key='per_page')
{
$app =& App::getInstance();
$sp = '';
for ($i=0; $iper_page_options); $i++) {
if ($this->_per_page != $this->per_page_options[$i]) {
printf('%s%s',
$sp,
$app->oHREF($_SERVER['PHP_SELF'] . '?' . $query_key . '=' . $this->per_page_options[$i]),
$this->per_page_options[$i]
);
} else {
echo $sp . '' . $this->per_page_options[$i] . '';
}
$sp = ' ';
}
}
/**
* Outputs an $app->oHREF compatible url that goes to the page $page_number.
* Depends on $this->base_url to build the url onto. This is used in the
* page_number.ihtml template.
*
* @param int $page_number The page number this page will go to.
*
* @return string The URL.
*
* @access public
*/
public function getPageNumURL($page_number, $carry_args=null)
{
$app =& App::getInstance();
return $app->oHREF($this->url_base . $page_number, $carry_args);
}
public function printPageNumURL($page_number, $carry_args=null)
{
echo $this->getPageNumURL($page_number, $carry_args);
}
/**
* Returns an array of page number links.
*
* @access public
*/
public function getPageNumbersArray($carry_args=null)
{
$page_numbers = array();
for ($i = 1; $i <= $this->total_pages; $i++) {
$page_numbers[] = array(
'number' => $i,
'url' => $this->getPageNumURL($i, $carry_args),
'current' => ($this->current_page == $i)
);
}
return $page_numbers;
}
/**
* Returns a string containing the page number links.
*
* @access public
*/
public function getPageNumbers($carry_args=null)
{
$page_numbers_string = '';
if ($this->current_page > $this->total_pages - floor($this->_num_links / 2)) {
$high_num = $this->total_pages;
$low_num = $high_num - $this->_num_links + 1;
} else {
$low_num = $this->current_page - floor($this->_num_links / 2);
if ($low_num < 1) {
$low_num = 1;
}
$high_num = $low_num + $this->_num_links - 1;
}
if ($this->current_page != 1) {
// Print "first" and "previous" page links.
if ($this->left_dbl_arrow) {
$page_numbers_string .= sprintf('%s ', $this->getPageNumURL(1, $carry_args), _("Go to the first page"), $this->left_dbl_arrow);
}
if ($this->left_arrow) {
$page_numbers_string .= sprintf('%s ', $this->getPageNumURL($this->current_page - 1, $carry_args), _("Go back one page"), $this->left_arrow);
}
// Print links to specific page numbers before the current page.
for ($i = $low_num; $i < $this->current_page; $i++) {
$page_numbers_string .= sprintf('%s ', $this->getPageNumURL($i, $carry_args), $i);
}
} else {
if ($this->left_dbl_arrow) {
$page_numbers_string .= $this->left_dbl_arrow_disabled . ' ';
}
if ($this->left_arrow) {
$page_numbers_string .= $this->left_arrow_disabled . ' ';
}
}
if ($this->_num_links > 0) {
// Print the current page number.
$page_numbers_string .= sprintf('%s ', $this->current_page);
}
if ($this->current_page < $this->total_pages) {
// Print links to specific page numbers after the current page.
for ($i = $this->current_page + 1; $i <= $high_num; $i++) {
$page_numbers_string .= sprintf('%s ', $this->getPageNumURL($i, $carry_args), $i);
}
// Print "last" and "next" page links.
if ($this->right_arrow) {
$page_numbers_string .= sprintf('%s ', $this->getPageNumURL($this->current_page + 1, $carry_args), _("Go forward one page"), $this->right_arrow);
}
if ($this->right_dbl_arrow) {
$page_numbers_string .= sprintf('%s ', $this->getPageNumURL($this->total_pages, $carry_args), _("Go to the last page"), $this->right_dbl_arrow);
}
} else {
if ($this->right_arrow_disabled) {
$page_numbers_string .= $this->right_arrow_disabled . ' ';
}
if ($this->right_dbl_arrow_disabled) {
$page_numbers_string .= $this->right_dbl_arrow_disabled;
}
}
return $page_numbers_string;
}
public function printPageNumbers($carry_args=null)
{
echo $this->getPageNumbers($carry_args);
}
}