DbStatement::valueMixed()   B
last analyzed

Complexity

Conditions 6
Paths 10

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 10
nop 2
dl 0
loc 24
rs 8.5125
c 0
b 0
f 0
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'];
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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();
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
118
        } else {
119
            $this->result = parent::fetch($fetch_style, $cursor_orientation, $cursor_offset);
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
120
121
            if (isset($this->cache) && ($this->result !== false)) {
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
122
                if (!isset($this->cache_data)) {
123
                    $this->cache_data = [];
124
                }
125
126
                $this->cache_data[] = $this->result;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
127
            }
128
        }
129
130
        return $this->result;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
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;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
142
            } else {
143
                $this->result = parent::fetchAll($fetch_style);
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
144
            }
145
146
            if (isset($this->cache) && ($this->result !== false)) {
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
147
                $this->cache_data = $this->result;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
148
            }
149
        }
150
151
        return $this->result;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
152
    }
153
154
    public function check()
155
    {
156
        if (!isset($this->result)) {
157
            $this->fetch();
158
        }
159
160
        return $this->result !== false;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
161
    }
162
163
    public function toArray()
164
    {
165
        if (!isset($this->result)) {
166
            $this->fetch();
167
        }
168
169
        return $this->result;
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
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]);
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
200
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
201
202
            case 'int':
203
                return (int)$this->result[$column];
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
204
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
205
206
            case 'decimal':
207
                return (float)$this->result[$column];
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
208
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
209
210
            case 'string':
211
            default:
212
                return $this->result[$column];
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
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]);
0 ignored issues
show
Bug introduced by
The property result does not seem to exist. Did you mean page_set_results_per_page?

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.

Loading history...
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;
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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) {
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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
0 ignored issues
show
Bug introduced by
The property page_set_total_rows does not seem to exist. Did you mean page_set?

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.

Loading history...
382
                    ];
383
                }
384
385
                $this->cache->save($cache_data);
386
            }
387
        }
388
    }
389
}
390