diff --git a/include/class.orm.php b/include/class.orm.php index 662349227c5bc7ac9c0cd33ab5c27c3102d99455..761f91dee25bf683896e26582d449ee2c56e7df3 100644 --- a/include/class.orm.php +++ b/include/class.orm.php @@ -1111,6 +1111,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl const OPT_NOSORT = 'nosort'; const OPT_NOCACHE = 'nocache'; + const OPT_MYSQL_FOUND_ROWS = 'found_rows'; const ITER_MODELS = 1; const ITER_HASH = 2; @@ -1122,6 +1123,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl var $query; var $count; + var $total; function __construct($model) { $this->model = $model; @@ -1315,6 +1317,42 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl return $this->count = $compiler->compileCount($this); } + /** + * Similar to count, except that the LIMIT and OFFSET parts are not + * considered in the counts. That is, this will return the count of rows + * if the query were not windowed with limit() and offset(). + * + * For MySQL, the query will be submitted and fetched and the + * SQL_CALC_FOUND_ROWS hint will be sent in the query. Afterwards, the + * result of FOUND_ROWS() is fetched and is the result of this function. + * + * The result of this function is cached. If further changes are made + * after this is run, the changes should be made in a clone. + */ + function total() { + // Optimize the query with the CALC_FOUND_ROWS if + // - the compiler supports it + // - the iterator hasn't yet been built, that is, the query for this + // statement has not yet been sent to the database + $compiler = $this->compiler; + if ($compiler::supportsOption(self::OPT_MYSQL_FOUND_ROWS) + && !isset($this->_iterator) + ) { + // This optimization requires caching + $this->options(array( + self::OPT_MYSQL_FOUND_ROWS => 1, + self::OPT_NOCACHE => null, + )); + $this->exists(true); + $compiler = new $compiler(); + return $this->total = $compiler->getFoundRows(); + } + + $query = clone $this; + $query->limit(false)->offset(false)->order_by(false); + return $this->total = $query->count(); + } + function toSql($compiler, $model, $alias=false) { // FIXME: Force root model of the compiler to $model $exec = $this->getQuery(array('compiler' => get_class($compiler), @@ -1431,6 +1469,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess, Serializable, Countabl unset($this->_iterator); unset($this->query); unset($this->count); + unset($this->total); } function __call($name, $args) { @@ -1556,6 +1595,7 @@ EOF; unset($info['offset']); unset($info['_iterator']); unset($info['count']); + unset($info['total']); return serialize($info); } @@ -2761,6 +2801,10 @@ class MySqlCompiler extends SqlCompiler { return sprintf("`%s`", str_replace("`", "``", $what)); } + function supportsOption($option) { + return true; + } + /** * getWhereClause * @@ -2803,6 +2847,12 @@ class MySqlCompiler extends SqlCompiler { return is_array($row) ? (int) $row[0] : null; } + function getFoundRows() { + $exec = new MysqlExecutor('SELECT FOUND_ROWS()', array()); + $row = $exec->getRow(); + return is_array($row) ? (int) $row[0] : null; + } + function compileSelect($queryset) { $model = $queryset->model; // Use an alias for the root model table @@ -2971,7 +3021,10 @@ class MySqlCompiler extends SqlCompiler { $joins = $this->getJoins($queryset); - $sql = 'SELECT '.implode(', ', $fields).' FROM ' + $sql = 'SELECT '; + if ($queryset->hasOption(QuerySet::OPT_MYSQL_FOUND_ROWS)) + $sql .= 'SQL_CALC_FOUND_ROWS '; + $sql .= implode(', ', $fields).' FROM ' .$table.$joins.$where.$group_by.$having.$sort; // UNIONS if ($queryset->chain) { diff --git a/include/staff/templates/queue-tickets.tmpl.php b/include/staff/templates/queue-tickets.tmpl.php index 0cf3ad09d44bc37a171d67a6bf2f206abc5a0546..664a8d6e151fce4312b5af48c484f55bebc80f6a 100644 --- a/include/staff/templates/queue-tickets.tmpl.php +++ b/include/staff/templates/queue-tickets.tmpl.php @@ -26,12 +26,6 @@ if (!$view_all_tickets) { $tickets->filter($visibility); } -$page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$count = count($tickets); -$pageNav = new Pagenate($count, $page, PAGE_LIMIT); -$pageNav->setURL('tickets.php', $args); -$tickets = $pageNav->paginate($tickets); - // Make sure the cdata materialized view is available TicketForm::ensureDynamicDataView(); @@ -199,6 +193,12 @@ foreach ($columns as $C) { </thead> <tbody> <?php +$page = ($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; +$count = $tickets->total(); +$pageNav = new Pagenate($count, $page, PAGE_LIMIT); +$pageNav->setURL('tickets.php', $args); +$tickets = $pageNav->paginate($tickets); + foreach ($tickets as $T) { echo '<tr>'; if ($canManageTickets) { ?>