1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* osCommerce Online Merchant |
4
|
|
|
* |
5
|
|
|
* @copyright (c) 2016 osCommerce; https://www.oscommerce.com |
6
|
|
|
* @license MIT; https://www.oscommerce.com/license/mit.txt |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
namespace OSC\OM; |
10
|
|
|
|
11
|
|
|
use OSC\OM\Cache; |
12
|
|
|
use OSC\OM\Db; |
13
|
|
|
use OSC\OM\HTML; |
14
|
|
|
use OSC\OM\Language; |
15
|
|
|
use OSC\OM\OSCOM; |
16
|
|
|
use OSC\OM\Registry; |
17
|
|
|
|
18
|
|
|
class DbStatement extends \PDOStatement |
19
|
|
|
{ |
20
|
|
|
protected $pdo; |
21
|
|
|
protected $is_error = false; |
22
|
|
|
protected $page_set_keyword = 'page'; |
23
|
|
|
protected $page_set; |
24
|
|
|
protected $page_set_results_per_page; |
25
|
|
|
protected $cache; |
26
|
|
|
protected $cache_expire; |
27
|
|
|
protected $cache_data; |
28
|
|
|
protected $cache_read = false; |
29
|
|
|
protected $cache_empty_results = false; |
30
|
|
|
protected $query_call; |
31
|
|
|
|
32
|
|
|
public function bindValue($parameter, $value, $data_type = \PDO::PARAM_STR) |
33
|
|
|
{ |
34
|
|
|
return parent::bindValue($parameter, $value, $data_type); |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
public function bindInt($parameter, $value) |
38
|
|
|
{ |
39
|
|
|
// force type to int (see http://bugs.php.net/bug.php?id=44639) |
40
|
|
|
return $this->bindValue($parameter, (int)$value, \PDO::PARAM_INT); |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
public function bindBool($parameter, $value) |
44
|
|
|
{ |
45
|
|
|
// force type to bool (see http://bugs.php.net/bug.php?id=44639) |
46
|
|
|
return $this->bindValue($parameter, (bool)$value, \PDO::PARAM_BOOL); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
public function bindDecimal($parameter, $value) { |
50
|
|
|
return $this->bindValue($parameter, (float)$value); // there is no \PDO::PARAM_FLOAT |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
public function bindNull($parameter) |
54
|
|
|
{ |
55
|
|
|
return $this->bindValue($parameter, null, \PDO::PARAM_NULL); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
public function setPageSet($max_results, $page_set_keyword = null, $placeholder_offset = 'page_set_offset', $placeholder_max_results = 'page_set_max_results') |
59
|
|
|
{ |
60
|
|
|
if (!empty($page_set_keyword)) { |
61
|
|
|
$this->page_set_keyword = $page_set_keyword; |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
$this->page_set = (isset($_GET[$this->page_set_keyword]) && is_numeric($_GET[$this->page_set_keyword]) && ($_GET[$this->page_set_keyword] > 0)) ? $_GET[$this->page_set_keyword] : 1; |
65
|
|
|
$this->page_set_results_per_page = $max_results; |
66
|
|
|
|
67
|
|
|
$offset = max(($this->page_set * $max_results) - $max_results, 0); |
68
|
|
|
|
69
|
|
|
$this->bindInt(':' . $placeholder_offset, $offset); |
70
|
|
|
$this->bindInt(':' . $placeholder_max_results, $max_results); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
public function execute($input_parameters = null) |
74
|
|
|
{ |
75
|
|
|
if (isset($this->cache)) { |
76
|
|
|
if (isset($this->page_set)) { |
77
|
|
|
$this->cache->setKey($this->cache->getKey() . '-pageset' . $this->page_set); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
if ($this->cache->exists($this->cache_expire)) { |
81
|
|
|
$this->cache_data = $this->cache->get(); |
82
|
|
|
|
83
|
|
|
if (isset($this->cache_data['data']) && isset($this->cache_data['total'])) { |
84
|
|
|
$this->page_set_total_rows = $this->cache_data['total']; |
|
|
|
|
85
|
|
|
$this->cache_data = $this->cache_data['data']; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
$this->cache_read = true; |
89
|
|
|
} |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
if ($this->cache_read === false) { |
93
|
|
|
if (empty($input_parameters)) { |
94
|
|
|
$input_parameters = null; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
$this->is_error = !parent::execute($input_parameters); |
98
|
|
|
|
99
|
|
|
if ($this->is_error === true) { |
100
|
|
|
trigger_error($this->queryString); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
if (strpos($this->queryString, ' SQL_CALC_FOUND_ROWS ') !== false) { |
104
|
|
|
$this->page_set_total_rows = $this->pdo->query('select found_rows()')->fetchColumn(); |
|
|
|
|
105
|
|
|
} elseif (isset($this->page_set)) { |
106
|
|
|
trigger_error('OSC\OM\DbStatement::execute(): Page Set query does not contain SQL_CALC_FOUND_ROWS. Please add it to the query: ' . $this->queryString); |
107
|
|
|
} |
108
|
|
|
} |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
public function fetch( |
112
|
|
|
$fetch_style = \PDO::FETCH_ASSOC, |
113
|
|
|
$cursor_orientation = \PDO::FETCH_ORI_NEXT, |
114
|
|
|
$cursor_offset = 0 |
115
|
|
|
) { |
116
|
|
|
if ($this->cache_read === true) { |
117
|
|
|
list(, $this->result) = each($this->cache_data); |
|
|
|
|
118
|
|
|
} else { |
119
|
|
|
$this->result = parent::fetch($fetch_style, $cursor_orientation, $cursor_offset); |
|
|
|
|
120
|
|
|
|
121
|
|
|
if (isset($this->cache) && ($this->result !== false)) { |
|
|
|
|
122
|
|
|
if (!isset($this->cache_data)) { |
123
|
|
|
$this->cache_data = []; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
$this->cache_data[] = $this->result; |
|
|
|
|
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
return $this->result; |
|
|
|
|
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
public function fetchAll($fetch_style = \PDO::FETCH_ASSOC, $fetch_argument = null, $ctor_args = []) |
134
|
|
|
{ |
135
|
|
|
if ($this->cache_read === true) { |
136
|
|
|
$this->result = $this->cache_data; |
|
|
|
|
137
|
|
|
} else { |
138
|
|
|
// fetchAll() fails if second argument is passed in a fetch style that does not |
139
|
|
|
// use the optional argument |
140
|
|
|
if (in_array($fetch_style, array(\PDO::FETCH_COLUMN, \PDO::FETCH_CLASS, \PDO::FETCH_FUNC))) { |
141
|
|
|
$this->result = parent::fetchAll($fetch_style, $fetch_argument, $ctor_args); |
|
|
|
|
142
|
|
|
} else { |
143
|
|
|
$this->result = parent::fetchAll($fetch_style); |
|
|
|
|
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
if (isset($this->cache) && ($this->result !== false)) { |
|
|
|
|
147
|
|
|
$this->cache_data = $this->result; |
|
|
|
|
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
return $this->result; |
|
|
|
|
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
public function check() |
155
|
|
|
{ |
156
|
|
|
if (!isset($this->result)) { |
157
|
|
|
$this->fetch(); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
return $this->result !== false; |
|
|
|
|
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
public function toArray() |
164
|
|
|
{ |
165
|
|
|
if (!isset($this->result)) { |
166
|
|
|
$this->fetch(); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
return $this->result; |
|
|
|
|
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
public function setCache($key, $expire = null, $cache_empty_results = false) |
173
|
|
|
{ |
174
|
|
|
if (!is_numeric($expire)) { |
175
|
|
|
$expire = 0; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
if (!is_bool($cache_empty_results)) { |
179
|
|
|
$cache_empty_results = false; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
$this->cache = new Cache($key); |
183
|
|
|
$this->cache_expire = $expire; |
184
|
|
|
$this->cache_empty_results = $cache_empty_results; |
185
|
|
|
|
186
|
|
|
if ($this->query_call != 'prepare') { |
187
|
|
|
trigger_error('OSC\\OM\\DbStatement::setCache(): Cannot set cache (\'' . $key . '\') on a non-prepare query. Please change the query to a prepare() query.'); |
188
|
|
|
} |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
protected function valueMixed($column, $type = 'string') |
192
|
|
|
{ |
193
|
|
|
if (!isset($this->result)) { |
194
|
|
|
$this->fetch(); |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
switch ($type) { |
198
|
|
|
case 'protected': |
199
|
|
|
return HTML::outputProtected($this->result[$column]); |
|
|
|
|
200
|
|
|
break; |
|
|
|
|
201
|
|
|
|
202
|
|
|
case 'int': |
203
|
|
|
return (int)$this->result[$column]; |
|
|
|
|
204
|
|
|
break; |
|
|
|
|
205
|
|
|
|
206
|
|
|
case 'decimal': |
207
|
|
|
return (float)$this->result[$column]; |
|
|
|
|
208
|
|
|
break; |
|
|
|
|
209
|
|
|
|
210
|
|
|
case 'string': |
211
|
|
|
default: |
212
|
|
|
return $this->result[$column]; |
|
|
|
|
213
|
|
|
} |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
public function value($column) |
217
|
|
|
{ |
218
|
|
|
return $this->valueMixed($column, 'string'); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
public function valueProtected($column) |
222
|
|
|
{ |
223
|
|
|
return $this->valueMixed($column, 'protected'); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
public function valueInt($column) |
227
|
|
|
{ |
228
|
|
|
return $this->valueMixed($column, 'int'); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
public function valueDecimal($column) |
232
|
|
|
{ |
233
|
|
|
return $this->valueMixed($column, 'decimal'); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
public function hasValue($column) { |
237
|
|
|
if (!isset($this->result)) { |
238
|
|
|
$this->fetch(); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
return isset($this->result[$column]); |
|
|
|
|
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
public function isError() |
245
|
|
|
{ |
246
|
|
|
return $this->is_error; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
public function getQuery() |
250
|
|
|
{ |
251
|
|
|
return $this->queryString; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
public function setQueryCall($type) |
255
|
|
|
{ |
256
|
|
|
$this->query_call = $type; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
public function getQueryCall() |
260
|
|
|
{ |
261
|
|
|
return $this->query_call; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
public function getCurrentPageSet() { |
265
|
|
|
return $this->page_set; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
public function getPageSetResultsPerPage() |
269
|
|
|
{ |
270
|
|
|
return $this->page_set_results_per_page; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
public function getPageSetTotalRows() |
274
|
|
|
{ |
275
|
|
|
return $this->page_set_total_rows; |
|
|
|
|
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
public function setPDO(\PDO $instance) |
279
|
|
|
{ |
280
|
|
|
$this->pdo = $instance; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
public function getPageSetLabel($text) |
284
|
|
|
{ |
285
|
|
|
if ($this->page_set_total_rows < 1) { |
|
|
|
|
286
|
|
|
$from = 0; |
287
|
|
|
} else { |
288
|
|
|
$from = max(($this->page_set * $this->page_set_results_per_page) - $this->page_set_results_per_page, 1); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
$to = min($this->page_set * $this->page_set_results_per_page, $this->page_set_total_rows); |
|
|
|
|
292
|
|
|
|
293
|
|
|
if ($to > $this->page_set_results_per_page) { |
294
|
|
|
$from++; |
295
|
|
|
} |
296
|
|
|
|
297
|
|
|
return '<span class="pagination">' . Language::parseDefinition($text, [ |
298
|
|
|
'listing_from' => $from, |
299
|
|
|
'listing_to' => $to, |
300
|
|
|
'listing_total' => $this->page_set_total_rows |
|
|
|
|
301
|
|
|
]) . '</span>'; |
302
|
|
|
} |
303
|
|
|
|
304
|
|
|
public function getPageSetLinks($parameters = null) |
305
|
|
|
{ |
306
|
|
|
global $PHP_SELF; |
307
|
|
|
|
308
|
|
|
$number_of_pages = ceil($this->page_set_total_rows / $this->page_set_results_per_page); |
|
|
|
|
309
|
|
|
|
310
|
|
|
if (empty($parameters)) { |
311
|
|
|
$parameters = ''; |
312
|
|
|
} |
313
|
|
|
|
314
|
|
|
if (!empty($parameters)) { |
315
|
|
|
parse_str($parameters, $p); |
316
|
|
|
|
317
|
|
|
if (isset($p[$this->page_set_keyword])) { |
318
|
|
|
unset($p[$this->page_set_keyword]); |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
$parameters = !empty($p) ? http_build_query($p) . '&' : ''; |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
$pages = []; |
325
|
|
|
|
326
|
|
|
for ($i = 1; $i <= $number_of_pages; $i++) { |
327
|
|
|
$pages[] = [ |
328
|
|
|
'id' => $i, |
329
|
|
|
'text' => $i |
330
|
|
|
]; |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
$output = '<ul class="pagination">'; |
334
|
|
|
|
335
|
|
View Code Duplication |
if ($number_of_pages > 1) { |
|
|
|
|
336
|
|
|
$output .= '<li>' . HTML::selectField('pageset' . $this->page_set_keyword, $pages, $this->page_set, 'style="vertical-align: top; display: inline-block; float: left; width: 80px;" data-pageseturl="' . HTML::output(OSCOM::link($PHP_SELF, $parameters . $this->page_set_keyword . '=PAGESETGOTO')) . '"') . '</li>'; |
337
|
|
|
} else { |
338
|
|
|
$output .= '<li class="disabled"><a class="text-center" style="width: 80px;">1</a></li>'; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
// previous button |
342
|
|
View Code Duplication |
if ($this->page_set > 1) { |
|
|
|
|
343
|
|
|
$output .= '<li><a href="' . OSCOM::link($PHP_SELF, $parameters . $this->page_set_keyword . '=' . ($this->page_set - 1)) . '" title="' . OSCOM::getDef('prevnext_title_previous_page') . '" class="text-center" style="width: 80px;"><span class="fa fa-fw fa-chevron-left"></span></a></li>'; |
344
|
|
|
} else { |
345
|
|
|
$output .= '<li class="disabled"><a class="text-center" style="width: 80px;"><span class="fa fa-fw fa-chevron-left"></span></a></li>'; |
346
|
|
|
} |
347
|
|
|
|
348
|
|
|
// next button |
349
|
|
|
if (($this->page_set < $number_of_pages) && ($number_of_pages != 1)) { |
350
|
|
|
$output .= '<li><a href="' . OSCOM::link($PHP_SELF, $parameters . $this->page_set_keyword . '=' . ($this->page_set + 1)) . '" title="' . OSCOM::getDef('prevnext_title_next_page') . '" class="text-center" style="width: 80px;"><span class="fa fa-fw fa-chevron-right"></span></a></li>'; |
351
|
|
|
} else { |
352
|
|
|
$output .= '<li class="disabled"><a class="text-center" style="width: 80px;"><span class="fa fa-fw fa-chevron-right"></span></a></li>'; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
$output .= '</ul>'; |
356
|
|
|
|
357
|
|
|
if ($number_of_pages > 1) { |
358
|
|
|
$output .= <<<EOD |
359
|
|
|
<script> |
360
|
|
|
$(function() { |
361
|
|
|
$('select[name="pageset{$this->page_set_keyword}"]').on('change', function() { |
362
|
|
|
window.location = $(this).data('pageseturl').replace('PAGESETGOTO', $(this).children(':selected').val()); |
363
|
|
|
}); |
364
|
|
|
}); |
365
|
|
|
</script> |
366
|
|
|
EOD; |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
return $output; |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
public function __destruct() |
373
|
|
|
{ |
374
|
|
|
if (($this->cache_read === false) && isset($this->cache) && is_array($this->cache_data)) { |
375
|
|
|
if ($this->cache_empty_results || (isset($this->cache_data[0]) && ($this->cache_data[0] !== false))) { |
376
|
|
|
$cache_data = $this->cache_data; |
377
|
|
|
|
378
|
|
|
if (isset($this->page_set_total_rows)) { |
379
|
|
|
$cache_data = [ |
380
|
|
|
'data' => $cache_data, |
381
|
|
|
'total' => $this->page_set_total_rows |
|
|
|
|
382
|
|
|
]; |
383
|
|
|
} |
384
|
|
|
|
385
|
|
|
$this->cache->save($cache_data); |
386
|
|
|
} |
387
|
|
|
} |
388
|
|
|
} |
389
|
|
|
} |
390
|
|
|
|
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.