adodb-pager.inc.php 7.96 KB
Newer Older
Penny Leach's avatar
Penny Leach committed
1
2
3
<?php

/*
4
	@version   v5.20.14  06-Jan-2019
5
6
	@copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
	@copyright (c) 2014      Damien Regad, Mark Newnham and the ADOdb community
7
8
9
	  Released under both BSD license and Lesser GPL library license.
	  Whenever there is any discrepancy between the two licenses,
	  the BSD license will take precedence.
Penny Leach's avatar
Penny Leach committed
10
11
	  Set tabs to 4 for best viewing.

12
13
14
  	This class provides recordset pagination with
	First/Prev/Next/Last links.

Penny Leach's avatar
Penny Leach committed
15
	Feel free to modify this class for your own use as
16
	it is very basic. To learn how to use it, see the
Penny Leach's avatar
Penny Leach committed
17
	example in adodb/tests/testpaging.php.
18

Penny Leach's avatar
Penny Leach committed
19
	"Pablo Costa" <pablo@cbsp.com.br> implemented Render_PageLinks().
20
21

	Please note, this class is entirely unsupported,
Penny Leach's avatar
Penny Leach committed
22
23
24
25
26
27
28
29
30
31
32
33
	and no free support requests except for bug reports
	will be entertained by the author.

*/
class ADODB_Pager {
	var $id; 	// unique id for pager (defaults to 'adodb')
	var $db; 	// ADODB connection object
	var $sql; 	// sql used
	var $rs;	// recordset generated
	var $curr_page;	// current page number before Render() called, calculated in constructor
	var $rows;		// number of rows per page
    var $linksPerPage=10; // number of links per page in navigation bar
34
    var $showPageLinks;
Penny Leach's avatar
Penny Leach committed
35
36

	var $gridAttributes = 'width=100% border=1 bgcolor=white';
37

Penny Leach's avatar
Penny Leach committed
38
39
40
41
42
43
44
45
46
47
48
49
	// Localize text strings here
	var $first = '<code>|&lt;</code>';
	var $prev = '<code>&lt;&lt;</code>';
	var $next = '<code>>></code>';
	var $last = '<code>>|</code>';
	var $moreLinks = '...';
	var $startLinks = '...';
	var $gridHeader = false;
	var $htmlSpecialChars = true;
	var $page = 'Page';
	var $linkSelectedColor = 'red';
	var $cache = 0;  #secs to cache with CachePageExecute()
50

Penny Leach's avatar
Penny Leach committed
51
52
53
54
55
	//----------------------------------------------
	// constructor
	//
	// $db	adodb connection object
	// $sql	sql statement
56
57
	// $id	optional id to identify which pager,
	//		if you have multiple on 1 page.
Penny Leach's avatar
Penny Leach committed
58
59
	//		$id should be only be [a-z0-9]*
	//
60
	function __construct(&$db,$sql,$id = 'adodb', $showPageLinks = false)
Penny Leach's avatar
Penny Leach committed
61
	{
62
	global $PHP_SELF, $SESSION;
63

Penny Leach's avatar
Penny Leach committed
64
		$curr_page = $id.'_curr_page';
65
		if (!empty($PHP_SELF)) $PHP_SELF = htmlspecialchars($_SERVER['PHP_SELF']); // htmlspecialchars() to prevent XSS attacks
66

Penny Leach's avatar
Penny Leach committed
67
68
69
70
		$this->sql = $sql;
		$this->id = $id;
		$this->db = $db;
		$this->showPageLinks = $showPageLinks;
71
72
73

		$next_page = $id.'_next_page';

Penny Leach's avatar
Penny Leach committed
74
		if (isset($_GET[$next_page])) {
75
			$SESSION->set($curr_page, (integer) $_GET[$next_page]);
Penny Leach's avatar
Penny Leach committed
76
		}
77
		if (empty($SESSION->get($curr_page))) $SESSION->set($curr_page, 1); ## at first page
78

79
		$this->curr_page = $SESSION->get($curr_page);
80

Penny Leach's avatar
Penny Leach committed
81
	}
82

Penny Leach's avatar
Penny Leach committed
83
84
85
86
87
88
89
	//---------------------------
	// Display link to first page
	function Render_First($anchor=true)
	{
	global $PHP_SELF;
		if ($anchor) {
	?>
90
		<a href="<?php echo $PHP_SELF,'?',$this->id;?>_next_page=1"><?php echo $this->first;?></a> &nbsp;
Penny Leach's avatar
Penny Leach committed
91
92
93
94
95
	<?php
		} else {
			print "$this->first &nbsp; ";
		}
	}
96

Penny Leach's avatar
Penny Leach committed
97
98
99
100
101
	//--------------------------
	// Display link to next page
	function render_next($anchor=true)
	{
	global $PHP_SELF;
102

Penny Leach's avatar
Penny Leach committed
103
104
		if ($anchor) {
		?>
105
		<a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() + 1 ?>"><?php echo $this->next;?></a> &nbsp;
Penny Leach's avatar
Penny Leach committed
106
107
108
109
110
		<?php
		} else {
			print "$this->next &nbsp; ";
		}
	}
111

Penny Leach's avatar
Penny Leach committed
112
113
	//------------------
	// Link to last page
114
	//
Penny Leach's avatar
Penny Leach committed
115
116
117
118
119
120
	// for better performance with large recordsets, you can set
	// $this->db->pageExecuteCountRows = false, which disables
	// last page counting.
	function render_last($anchor=true)
	{
	global $PHP_SELF;
121

Penny Leach's avatar
Penny Leach committed
122
		if (!$this->db->pageExecuteCountRows) return;
123

Penny Leach's avatar
Penny Leach committed
124
125
		if ($anchor) {
		?>
126
			<a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->LastPageNo() ?>"><?php echo $this->last;?></a> &nbsp;
Penny Leach's avatar
Penny Leach committed
127
128
129
130
131
		<?php
		} else {
			print "$this->last &nbsp; ";
		}
	}
132

Penny Leach's avatar
Penny Leach committed
133
	//---------------------------------------------------
134
	// original code by "Pablo Costa" <pablo@cbsp.com.br>
Penny Leach's avatar
Penny Leach committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
        function render_pagelinks()
        {
        global $PHP_SELF;
            $pages        = $this->rs->LastPageNo();
            $linksperpage = $this->linksPerPage ? $this->linksPerPage : $pages;
            for($i=1; $i <= $pages; $i+=$linksperpage)
            {
                if($this->rs->AbsolutePage() >= $i)
                {
                    $start = $i;
                }
            }
			$numbers = '';
            $end = $start+$linksperpage-1;
			$link = $this->id . "_next_page";
            if($end > $pages) $end = $pages;
151
152


Penny Leach's avatar
Penny Leach committed
153
154
155
			if ($this->startLinks && $start > 1) {
				$pos = $start - 1;
				$numbers .= "<a href=$PHP_SELF?$link=$pos>$this->startLinks</a>  ";
156
157
            }

Penny Leach's avatar
Penny Leach committed
158
159
160
			for($i=$start; $i <= $end; $i++) {
                if ($this->rs->AbsolutePage() == $i)
                    $numbers .= "<font color=$this->linkSelectedColor><b>$i</b></font>  ";
161
                else
Penny Leach's avatar
Penny Leach committed
162
                     $numbers .= "<a href=$PHP_SELF?$link=$i>$i</a>  ";
163

Penny Leach's avatar
Penny Leach committed
164
            }
165
			if ($this->moreLinks && $end < $pages)
Penny Leach's avatar
Penny Leach committed
166
167
168
169
170
171
172
173
174
				$numbers .= "<a href=$PHP_SELF?$link=$i>$this->moreLinks</a>  ";
            print $numbers . ' &nbsp; ';
        }
	// Link to previous page
	function render_prev($anchor=true)
	{
	global $PHP_SELF;
		if ($anchor) {
	?>
175
176
		<a href="<?php echo $PHP_SELF,'?',$this->id,'_next_page=',$this->rs->AbsolutePage() - 1 ?>"><?php echo $this->prev;?></a> &nbsp;
	<?php
Penny Leach's avatar
Penny Leach committed
177
178
179
180
		} else {
			print "$this->prev &nbsp; ";
		}
	}
181

Penny Leach's avatar
Penny Leach committed
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
	//--------------------------------------------------------
	// Simply rendering of grid. You should override this for
	// better control over the format of the grid
	//
	// We use output buffering to keep code clean and readable.
	function RenderGrid()
	{
	global $gSQLBlockRows; // used by rs2html to indicate how many rows to display
		include_once(ADODB_DIR.'/tohtml.inc.php');
		ob_start();
		$gSQLBlockRows = $this->rows;
		rs2html($this->rs,$this->gridAttributes,$this->gridHeader,$this->htmlSpecialChars);
		$s = ob_get_contents();
		ob_end_clean();
		return $s;
	}
198

Penny Leach's avatar
Penny Leach committed
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
	//-------------------------------------------------------
	// Navigation bar
	//
	// we use output buffering to keep the code easy to read.
	function RenderNav()
	{
		ob_start();
		if (!$this->rs->AtFirstPage()) {
			$this->Render_First();
			$this->Render_Prev();
		} else {
			$this->Render_First(false);
			$this->Render_Prev(false);
		}
        if ($this->showPageLinks){
            $this->Render_PageLinks();
        }
		if (!$this->rs->AtLastPage()) {
			$this->Render_Next();
			$this->Render_Last();
		} else {
			$this->Render_Next(false);
			$this->Render_Last(false);
		}
		$s = ob_get_contents();
		ob_end_clean();
		return $s;
	}
227

Penny Leach's avatar
Penny Leach committed
228
229
230
231
232
233
234
235
236
237
	//-------------------
	// This is the footer
	function RenderPageCount()
	{
		if (!$this->db->pageExecuteCountRows) return '';
		$lastPage = $this->rs->LastPageNo();
		if ($lastPage == -1) $lastPage = 1; // check for empty rs.
		if ($this->curr_page > $lastPage) $this->curr_page = 1;
		return "<font size=-1>$this->page ".$this->curr_page."/".$lastPage."</font>";
	}
238

Penny Leach's avatar
Penny Leach committed
239
240
241
242
243
	//-----------------------------------
	// Call this class to draw everything.
	function Render($rows=10)
	{
	global $ADODB_COUNTRECS;
244

Penny Leach's avatar
Penny Leach committed
245
		$this->rows = $rows;
246

Penny Leach's avatar
Penny Leach committed
247
		if ($this->db->dataProvider == 'informix') $this->db->cursorType = IFX_SCROLL;
248

Penny Leach's avatar
Penny Leach committed
249
250
251
		$savec = $ADODB_COUNTRECS;
		if ($this->db->pageExecuteCountRows) $ADODB_COUNTRECS = true;
		if ($this->cache)
252
			$rs = $this->db->CachePageExecute($this->cache,$this->sql,$rows,$this->curr_page);
Penny Leach's avatar
Penny Leach committed
253
		else
254
			$rs = $this->db->PageExecute($this->sql,$rows,$this->curr_page);
Penny Leach's avatar
Penny Leach committed
255
		$ADODB_COUNTRECS = $savec;
256

257
		$this->rs = $rs;
Penny Leach's avatar
Penny Leach committed
258
259
260
261
		if (!$rs) {
			print "<h3>Query failed: $this->sql</h3>";
			return;
		}
262
263

		if (!$rs->EOF && (!$rs->AtFirstPage() || !$rs->AtLastPage()))
Penny Leach's avatar
Penny Leach committed
264
265
266
			$header = $this->RenderNav();
		else
			$header = "&nbsp;";
267

Penny Leach's avatar
Penny Leach committed
268
269
		$grid = $this->RenderGrid();
		$footer = $this->RenderPageCount();
270

Penny Leach's avatar
Penny Leach committed
271
		$this->RenderLayout($header,$grid,$footer);
272

Penny Leach's avatar
Penny Leach committed
273
274
275
		$rs->Close();
		$this->rs = false;
	}
276

Penny Leach's avatar
Penny Leach committed
277
278
279
280
281
282
283
284
285
286
287
288
289
	//------------------------------------------------------
	// override this to control overall layout and formating
	function RenderLayout($header,$grid,$footer,$attributes='border=1 bgcolor=beige')
	{
		echo "<table ".$attributes."><tr><td>",
				$header,
			"</td></tr><tr><td>",
				$grid,
			"</td></tr><tr><td>",
				$footer,
			"</td></tr></table>";
	}
}