* @license PHP License * @package WB * @subpackage db */ /** * Simple pager * * @version 0.3.4 * @package WB * @subpackage db */ class WBDatasource_Pager extends WBStdClass { /** * datasource * @var WBDatasource_Table */ protected $_source; /** * id * @var string */ protected $_id; /** * limit * @var string */ protected $_limit; /** * position of options * @var int */ protected $_optPos = 1; /** * current pager * @var array */ protected $_pager = array(); /** * args * @var array */ protected $_args = array(); /** * List of Count Options * * Actually fields to count or sum up * @var array */ private $countColumn = array(); /** * Count Group By Options * * Override group by option * @var array */ private $countGroup = null; /** * Count Data * * Associative array of count data * @var array */ private $countData = array(); /** * session * @var patSession_Storage */ protected $_sess; /** * constructor * * @param array $parameter */ public function __construct( $parameter = array() ) { if (!isset($parameter['id'])) { WBClass::load('WBException_Argument'); throw new WBException_Argument('Pager id is required.', 1, __CLASS__); } if (!isset($parameter['source'])) { WBClass::load('WBException_Argument'); throw new WBException_Argument('Source is required.', 2, __CLASS__); } if (!isset($parameter['limit'])) { WBClass::load('WBException_Argument'); throw new WBException_Argument('Limit is required.', 3, __CLASS__); } if (!isset($parameter['options'])) { WBClass::load('WBException_Argument'); throw new WBException_Argument('Need to know the position of get options.', 4, __CLASS__); } $this->_source = $parameter['source']; $this->_limit = $parameter['limit']; $this->_optPos = $parameter['options']; $this->_id = $parameter['id'] . '-' . $this->_limit; // $this->_sess = WBClass::create('patSession'); // if ($this->_sess->has( 'WBDatasource.Pager.' . $this->_id)) { // $this->_pager = $this->_sess->get( 'WBDatasource.Pager.' . $this->_id ); // } // if (empty($this->_pager)) { $this->_pager = array(); $this->_pager['id'] = $this->_id; $this->_pager['limit'] = $this->_limit; $this->_pager['total'] = '__undefined'; $this->_pager['pages'] = '__undefined'; $this->_pager['next'] = 0; $this->_pager['prev'] = 0; $this->_pager['offset'] = 0; $this->_pager['current'] = 0; $this->_pager['page'] = 1; $this->_pager['page_prev'] = 0; $this->_pager['page_next'] = 0; } } /** * destruct * * save current pager position in session */ public function __destruct() { //$this->_sess->set('WBDatasource.Pager.' . $this->_id, $this->_pager); } /** * init pager * * @param mixed $args... * @return bool true on success */ public function setArgs() { $this->_args = func_get_args(); return true; } /** * Wrapper for get function to receive a list * * @return array list */ public function get() { $args = $this->_args; $args[$this->_optPos]['limit'] = $this->_pager['limit']; $args[$this->_optPos]['offset'] = $this->_pager['offset']; $list = call_user_func_array(array($this->_source, 'get'), $args); foreach ($list as $i => &$l) { $l['pager_row_var'] = $this->_pager['offset'] + 1 + $i; } return $list; } /** * Set List To Count * * Set column definition for columns to count or sum or whatever * @param array */ public function setCountColumn($column = array()) { $this->countColumn = $column; } /** * Set Grouping Options for Count * * Set column definition for columns to count or sum or whatever * @param array */ public function setCountGroup($group = null) { $this->countGroup = $group; } /** * Fetch Count Data * * Use this method after browse() to collect count data * * @see setCountColumn() * @return array */ public function getCount() { return $this->countData; } /** * go to page number # * * Calculate offest for next get(). * * @param string|int $goto page number * @return array $pager info */ public function browse( $goto = '__first' ) { $this->countData = array(); $args = $this->_args; $opt = $args[$this->_optPos]; $opt['column'] = array(); // use count(DISTINCT) instead of GROUP BY if (empty($opt['groupby'])) { if (empty($opt['distinct'])) { $opt['column'][] = array( 'native' => 'count(*)', 'field' => '*', 'as' => 'row_count' ); } else { $opt['column'][] = array( 'native' => 'count(DISTINCT ' . $opt['distinct']. ')', 'field' => $opt['distinct'], 'as' => 'row_count' ); } } else { if (!is_array($opt['groupby']) || !isset($opt['groupby'][0])) { $opt['groupby'] = array($opt['groupby']); } // build count(DISTINCT) $dist = array(); foreach ($opt['groupby'] as $g) { if (!is_array($g)) { $g = array( 'field' => $g ); } if (empty($g['table'])) { if (!is_array($g['field'])) { $g['field'] = array($g['field']); } foreach ($g['field'] as $f) { $dist[] = $f; } } else { $tInfo = $this->_source->getTableInfo($g['table']); $dist[] = $tInfo['table'] . '.' . $g['field']; } } $opt['column'][] = array( 'native' => sprintf('count(DISTINCT %s)', implode(', ', $dist)), 'field' => '*', 'as' => 'row_count' ); // .. and remove group by unset($opt['groupby']); } $opt['column'] = array_merge($this->countColumn, $opt['column']); if (!is_null($this->countGroup)) { $opt['groupby'] = $this->countGroup; } // switch off callback for count $opt['callback'] = null; $args[$this->_optPos] = $opt; $list = call_user_func_array(array($this->_source, 'get'), $args); if (1 != count($list)) { $this->_pager['pages'] = 0; $this->_pager['total'] = 0; $this->_pager['next'] = 0; $this->_pager['prev'] = 0; return $this->_pager; } $list = $list[0]; $this->countData = $list; $total = $list['row_count']; $pages = ceil($total / $this->_limit); $this->_pager['pages'] = $pages; $this->_pager['total'] = $total; $this->_pager['next'] = 0; $this->_pager['prev'] = 0; if (empty($goto)) { $goto = '__first'; } switch (strtolower($goto)) { case '__first': $goto = 0; break; case '__prev': $goto = $this->_pager['current']; --$goto; break; case '__current': $goto = $this->_pager['current']; break; case '__next': $goto = $this->_pager['current']; ++$goto; break; case '__last': $goto = $pages - 1; break; default: // goto starts at zero but human readable pages start at one --$goto; break; } // stay within boundaries if ($goto < 0) { $goto = 0; } if ($goto > ($pages - 1)) { $goto = $pages - 1; } // is it allow to browse next and previous? if ($goto > 0) { $this->_pager['prev'] = 1; } if ($goto < ($pages -1)) { $this->_pager['next'] = 1; } // assample pager information $this->_pager['current'] = $goto; $this->_pager['page'] = $goto + 1; $this->_pager['offset'] = $goto * $this->_limit; $this->_pager['page_prev'] = $this->_pager['page'] - $this->_pager['prev']; $this->_pager['page_next'] = $this->_pager['page'] + $this->_pager['next']; return $this->_pager; } }