]> git.llucax.com Git - mecon/meconlib.git/blob - lib/MECON/DB/Pager.php
8aa5d603f5122c4e9d6c4a63e2c1570f6de0b887
[mecon/meconlib.git] / lib / MECON / DB / Pager.php
1 <?php
2 //
3 //  Pear DB Pager - Retrieve and return information of databases
4 //                  result sets
5 //
6 //  Copyright (C) 2001  Tomas Von Veschler Cox <cox@idecnet.com>
7 //
8 //  This library is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This library is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 //  You should have received a copy of the GNU Lesser General Public
19 //  License along with this library; if not, write to the Free Software
20 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 //
22 //
23 // $Id$
24
25 require_once 'PEAR.php';
26 require_once 'DB.php';
27
28 /**
29 * This class handles all the stuff needed for displaying paginated results
30 * from a database query of Pear DB, in a very easy way.
31 * Documentation and examples of use, can be found in:
32 * http://vulcanonet.com/soft/pager/ (could be outdated)
33 *
34 * IMPORTANT!
35 * Since PEAR DB already support native row limit (more fast and avaible in
36 * all the drivers), there is no more need to use $pager->build() or
37 * the $pager->fetch*() methods.
38 *
39 * Usage example:
40 *
41 *< ?php
42 * require_once 'DB/Pager.php';
43 * $db = DB::connect('your DSN string');
44 * $from = 0;   // The row to start to fetch from (you might want to get this
45 *              // param from the $_GET array
46 * $limit = 10; // The number of results per page
47 * $maxpages = 10; // The number of pages for displaying in the pager (optional)
48 * $res = $db->limitQuery($sql, $from, $limit);
49 * $nrows = 0; // Alternative you could use $res->numRows()
50 * while ($row = $res->fetchrow()) {
51 *    // XXX code for building the page here
52 *     $nrows++;
53 * }
54 * $data = DB_Pager::getData($from, $limit, $nrows, $maxpages);
55 * // XXX code for building the pager here
56 * ? >
57 *
58 * @version 0.7
59 * @author Tomas V.V.Cox <cox@idecnet.com>
60 * @see http://vulcanonet.com/soft/pager/
61 */
62
63 class MECON_DB_Pager extends DB_Result
64 {
65
66     /**
67     * Constructor
68     *
69     * Gets all the data needed to paginate results
70     * The object has this properties:
71     *
72     *    'current' => X,    // current page you are
73     *    'numrows' => X,    // total number of results
74     *    'next'    => X,    // row number where next page starts
75     *    'prev'    => X,    // row number where prev page starts
76     *    'remain'  => X,    // number of results remaning *in next page*
77     *    'numpages'=> X,    // total number of pages
78     *    'from'    => X,    // the row to start fetching
79     *    'to'      => X,    // the row to stop fetching
80     *    'limit'   => X,    // how many results per page
81     *    'maxpages'   => X, // how many pages to show (google style)
82     *    'firstpage'  => X, // the row number of the first page
83     *    'lastpage'   => X, // the row number where the last page starts
84     *    'pages'   => array(    // assoc with page "number => start row"
85     *                1 => X,
86     *                2 => X,
87     *                3 => X
88     *                )
89     *    );
90
91     * @param object $res  A DB_result object from Pear_DB
92     * @param int    $from  The row to start fetching
93     * @param int    $limit  How many results per page
94     * @param int    $maxpages  Maximum pages to display
95     * @param int    $numrows Pager will automatically
96     *    find this param if is not given. If your Pear_DB backend extension
97     *    doesn't support numrows(), you can manually calculate it
98     *    and supply later to the constructor
99     * @deprecated
100     */
101     function MECON_DB_Pager (&$res, $from = 0, $limit = 10, $maxpages = 21, $numrows = null)
102     {
103         $this->dbh = $res->dbh;
104         $this->result = $res->result;
105         $this->row_counter = $res->row_counter;
106         $this->limit_from = $res->limit_from;
107         $this->from = $from;
108         $this->limit = $limit;
109         $this->numrows = $numrows;
110         $this->maxpages = $maxpages;
111         $this->build();
112     }
113
114     /**
115     * Calculates all the data needed by Pager to work
116     * @return mixed PEAR_Error if error.
117     */
118     function build()
119     {
120         // if there is no numrows given, calculate it
121         if ($this->numrows === null) {
122             $this->numrows = $this->numrows();
123             if (DB::isError($this->numrows)) {
124                 return $this->numrows;
125             }
126         }
127         // Si no hay resultados no se hace nada.
128         if (empty($this->numrows) or ($this->numrows < 0)) {
129             return;
130         }
131         $this->from = empty($this->from) ? 0 : $this->from;
132
133         if ($this->limit <= 0) {
134             return PEAR::raiseError (null, 'wrong "limit" param', null,
135                                      null, null, 'DB_Error', true);
136         }
137
138         // Total number of pages
139         $this->numpages = ceil($this->numrows/$this->limit);
140
141         // first & last page
142         $this->firstpage = 1;
143         $this->lastpage  = $this->numpages;
144
145         // Build pages array
146         $this->pages = array();
147         for ($i = 1; $i <= $this->numpages; $i++) {
148             $offset = $this->limit * ($i - 1);
149             $this->pages[$i] = $offset;
150             // $from must point to one page
151             if ($this->from == $offset) {
152                 // The current page we are
153                 $this->currentpage = $i;
154             }
155         }
156         if (!isset($this->currentpage)) {
157             return PEAR::raiseError (null, 'wrong "from" param', null,
158                                      null, null, 'DB_Error', true);
159         }
160
161         // Limit number of pages (goole algoritm)
162         if ($this->maxpages) {
163             $radio = floor($this->maxpages/2);
164             $this->firstpage = $this->currentpage - $radio;
165             if (!($this->maxpages % 2)) {
166                 $this->firstpage++;
167             }
168             if ($this->firstpage < 1) {
169                 $this->firstpage = 1;
170             }
171             $this->lastpage = $this->currentpage + $radio;
172             if ($this->lastpage > $this->numpages) {
173                 $this->lastpage = $this->numpages;
174             }
175             foreach (range($this->firstpage, $this->lastpage) as $page) {
176                 $tmp[$page] = $this->pages[$page];
177             }
178             $this->pages = $tmp;
179         }
180
181         // Prev link
182         $this->prev = $this->from - $this->limit;
183         $this->prev = ($this->prev >= 0) ? $this->prev : null;
184
185         // Next link
186         $this->next = $this->from + $this->limit;
187         $this->next = ($this->next < $this->numrows) ? $this->next : null;
188
189         // Results remaining in next page & Last row to fetch
190         if ($this->currentpage == $this->numpages) {
191             $this->remain = 0;
192             $this->to = $this->numrows;
193         } else {
194             if ($this->currentpage == ($this->numpages - 1)) {
195                 $this->remain = $this->numrows - ($this->limit * ($this->numpages - 1));
196             } else {
197                 $this->remain = $this->limit;
198             }
199             $this->to = $this->currentpage * $this->limit;
200         }
201
202         // Current item (when fetching).
203         $this->current = $this->from - 1;
204     }
205
206     function fetchRow($mode=DB_FETCHMODE_DEFAULT, $rownum=null)
207     {
208         $this->current++;
209         if ($this->current >= $this->to) {
210             return null;
211         }
212         return parent::fetchRow($mode, $this->current);
213     }
214
215     function fetchInto(&$arr, $mode=DB_FETCHMODE_DEFAULT)
216     {
217         $this->current++;
218         if ($this->current >= $this->to) {
219             return null;
220         }
221         return parent::fetchInto($arr, $mode, $this->current);
222     }
223 }
224 ?>