Rev 1372 | Blame | Compare with Previous | Last modification | View Log | RSS feed
<?php
// CVS: $Id$
//
// Pager_Wrapper
// -------------
//
// Ready-to-use wrappers for paging the result of a query,
// when fetching the whole resultset is NOT an option.
// This is a performance- and memory-savvy method
// to use PEAR::Pager with a database.
// With this approach, the network load can be
// consistently smaller than with PEAR::DB_Pager.
//
// The following wrappers are provided: one for each PEAR
// db abstraction layer (DB, MDB and MDB2), one for
// PEAR::DB_DataObject, and one for the PHP Eclipse library
//
//
// SAMPLE USAGE
// ------------
//
// $query = 'SELECT this, that FROM mytable';
// require_once 'Pager_Wrapper.php'; //this file
// $pagerOptions = array(
// 'mode' => 'Sliding',
// 'delta' => 2,
// 'perPage' => 15,
// );
// $paged_data = Pager_Wrapper_MDB2($db, $query, $pagerOptions);
// //$paged_data['data']; //paged data
// //$paged_data['links']; //xhtml links for page navigation
// //$paged_data['page_numbers']; //array('current', 'total');
//
/**
* Helper method - Rewrite the query into a "SELECT COUNT(*)" query.
* @param string $sql query
* @return string rewritten query OR false if the query can't be rewritten
* @access private
*/
function rewriteCountQuery($sql)
{
if (preg_match('/^\s*SELECT\s+\bDISTINCT\b/is', $sql) || preg_match('/\s+GROUP\s+BY\s+/is', $sql)) {
return false;
}
$open_parenthesis = '(?:\()';
$close_parenthesis = '(?:\))';
$subquery_in_select = $open_parenthesis.'.*\bFROM\b.*'.$close_parenthesis;
$pattern = '/(?:.*'.$subquery_in_select.'.*)\bFROM\b\s+/Uims';
if (preg_match($pattern, $sql)) {
return false;
}
$subquery_with_limit_order = $open_parenthesis.'.*\b(LIMIT|ORDER)\b.*'.$close_parenthesis;
$pattern = '/.*\bFROM\b.*(?:.*'.$subquery_with_limit_order.'.*).*/Uims';
if (preg_match($pattern, $sql)) {
return false;
}
$queryCount = preg_replace('/(?:.*)\bFROM\b\s+/Uims', 'SELECT COUNT(*) FROM ', $sql, 1);
list($queryCount, ) = preg_split('/\s+ORDER\s+BY\s+/is', $queryCount);
list($queryCount, ) = preg_split('/\bLIMIT\b/is', $queryCount);
return trim($queryCount);
}
/**
* @param object PEAR::DB instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @param integer fetch mode constant
* @param mixed parameters for query placeholders
* If you use placeholders for table names or column names, please
* count the # of items returned by the query and pass it as an option:
* $pager_options['totalItems'] = count_records('some query');
* @return array with links and paged data
*/
function Pager_Wrapper_DB(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = DB_FETCHMODE_ASSOC, $dbparams = null)
{
if (!array_key_exists('totalItems', $pager_options)) {
// be smart and try to guess the total number of records
if ($countQuery = rewriteCountQuery($query)) {
$totalItems = $db->getOne($countQuery, $dbparams);
if (PEAR::isError($totalItems)) {
return $totalItems;
}
} else {
$res =& $db->query($query, $dbparams);
if (PEAR::isError($res)) {
return $res;
}
$totalItems = (int)$res->numRows();
$res->free();
}
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
$page = array();
$page['totalItems'] = $pager_options['totalItems'];
$page['links'] = $pager->links;
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$res = ($disabled)
? $db->limitQuery($query, 0, $totalItems, $dbparams)
: $db->limitQuery($query, $page['from']-1, $pager_options['perPage'], $dbparams);
if (PEAR::isError($res)) {
return $res;
}
$page['data'] = array();
while ($res->fetchInto($row, $fetchMode)) {
$page['data'][] = $row;
}
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
/**
* @param object PEAR::MDB instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @param integer fetch mode constant
* @return array with links and paged data
*/
function Pager_Wrapper_MDB(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = MDB_FETCHMODE_ASSOC)
{
if (!array_key_exists('totalItems', $pager_options)) {
//be smart and try to guess the total number of records
if ($countQuery = rewriteCountQuery($query)) {
$totalItems = $db->queryOne($countQuery);
if (PEAR::isError($totalItems)) {
return $totalItems;
}
} else {
$res = $db->query($query);
if (PEAR::isError($res)) {
return $res;
}
$totalItems = (int)$db->numRows($res);
$db->freeResult($res);
}
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
$page = array();
$page['totalItems'] = $pager_options['totalItems'];
$page['links'] = $pager->links;
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$res = ($disabled)
? $db->limitQuery($query, null, 0, $totalItems)
: $db->limitQuery($query, null, $page['from']-1, $pager_options['perPage']);
if (PEAR::isError($res)) {
return $res;
}
$page['data'] = array();
while ($row = $db->fetchInto($res, $fetchMode)) {
$page['data'][] = $row;
}
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
/**
* @param object PEAR::MDB2 instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @param integer fetch mode constant
* @return array with links and paged data
*/
function Pager_Wrapper_MDB2(&$db, $query, $pager_options = array(), $disabled = false, $fetchMode = MDB2_FETCHMODE_ASSOC)
{
if (!array_key_exists('totalItems', $pager_options)) {
//be smart and try to guess the total number of records
if ($countQuery = rewriteCountQuery($query)) {
$totalItems = $db->queryOne($countQuery);
if (PEAR::isError($totalItems)) {
return $totalItems;
}
} else {
//GROUP BY => fetch the whole resultset and count the rows returned
$res =& $db->queryCol($query);
if (PEAR::isError($res)) {
return $res;
}
$totalItems = count($res);
}
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
$page = array();
$page['links'] = $pager->links;
$page['totalItems'] = $pager_options['totalItems'];
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$page['limit'] = $page['to'] - $page['from'] +1;
if (!$disabled) {
$db->setLimit($pager_options['perPage'], $page['from']-1);
}
$page['data'] = $db->queryAll($query, null, $fetchMode);
if (PEAR::isError($page['data'])) {
return $page['data'];
}
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
/**
* @param object PEAR::DataObject instance
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @return array with links and paged data
* @author Massimiliano Arione <garak@studenti.it>
*/
function Pager_Wrapper_DBDO(&$db, $pager_options = array(), $disabled = false)
{
if (!array_key_exists('totalItems', $pager_options)) {
$totalItems = $db->count();
$pager_options['totalItems'] = $totalItems;
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
$page = array();
$page['links'] = $pager->links;
$page['totalItems'] = $pager_options['totalItems'];
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $pager->numPages()
);
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$page['limit'] = $page['to'] - $page['from'] + 1;
if (!$disabled) {
$db->limit($page['from'] - 1, $pager_options['perPage']);
}
$db->find();
while ($db->fetch()) {
$db->getLinks();
$page['data'][] = $db->toArray('%s', true);
}
return $page;
}
/**
* @param object PHP Eclipse instance
* @param string db query
* @param array PEAR::Pager options
* @param boolean Disable pagination (get all results)
* @return array with links and paged data
* @author Matte Edens <matte@arubanetworks.com>
* @see http://sourceforge.net/projects/eclipselib/
*/
function Pager_Wrapper_Eclipse(&$db, $query, $pager_options = array(), $disabled = false)
{
if (!$disabled) {
require_once(ECLIPSE_ROOT . 'PagedQuery.php');
$query =& new PagedQuery($db->query($query), $pager_options['perPage']);
$totalrows = $query->getRowCount();
$numpages = $query->getPageCount();
$whichpage = isset($_GET[$pager_options['urlVar']]) ? (int)$_GET[$pager_options['urlVar']] - 1 : 0;
if ($whichpage >= $numpages) {
$whichpage = $numpages - 1;
}
$result = $query->getPage($whichpage);
} else {
$result = $db->query($query);
$totalrows = $result->getRowCount();
$numpages = 1;
}
if (!$result->isSuccess()) {
return PEAR::raiseError($result->getErrorMessage());
}
if (!array_key_exists('totalItems', $pager_options)) {
$pager_options['totalItems'] = $totalrows;
}
$page = array();
require_once(ECLIPSE_ROOT . 'QueryIterator.php');
for ($it =& new QueryIterator($result); $it->isValid(); $it->next()) {
$page['data'][] =& $it->getCurrent();
}
require_once 'Pager/Pager.php';
$pager = Pager::factory($pager_options);
$page['links'] = $pager->links;
$page['totalItems'] = $pager_options['totalItems'];
$page['page_numbers'] = array(
'current' => $pager->getCurrentPageID(),
'total' => $numpages
);
$page['perPageSelectBox'] = $pager->getperpageselectbox();
list($page['from'], $page['to']) = $pager->getOffsetByPageId();
$page['limit'] = $page['to'] - $page['from'] +1;
if ($disabled) {
$page['links'] = '';
$page['page_numbers'] = array(
'current' => 1,
'total' => 1
);
}
return $page;
}
?>