Completed
Push — master ( e5ab12...9197f0 )
by Konstantinos
09:09
created

QueryBuilder::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2
Metric Value
dl 0
loc 13
ccs 0
cts 7
cp 0
rs 9.4286
cc 1
eloc 7
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * This file contains a class to quickly generate database queries for models
4
 *
5
 * @package    BZiON\Models\QueryBuilder
6
 * @license    https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3
7
 */
8
9
/**
10
 * This class can be used to search for models with specific characteristics in
11
 * the database.
12
 *
13
 * Note that most methods of this class return itself, so that you can easily
14
 * add a number of different filters.
15
 *
16
 * <code>
17
 *     return Team::getQueryBuilder()
18
 *     ->active()
19
 *     ->where('name')->startsWith('a')
20
 *     ->sortBy('name')->reverse()
21
 *     ->getModels();
22
 * </code>
23
 *
24
 * @package    BZiON\Models\QueryBuilder
25
 */
26
class QueryBuilder implements Countable
27
{
28
    /**
29
     * The type of the model we're building a query for
30
     * @var string
31
     */
32
    protected $type;
33
34
    /**
35
     * The columns that the model provided us
36
     * @var array
37
     */
38
    protected $columns = array('id' => 'id');
39
40
    /**
41
     * The conditions to include in WHERE
42
     * @var string[]
43
     */
44
    protected $conditions = array();
45
46
    /**
47
     * The MySQL value parameters
48
     * @var array
49
     */
50
    protected $parameters = array();
51
52
    /**
53
     * The MySQL parameter types
54
     * @var string
55
     */
56
    protected $types = '';
57
58
    /**
59
     * The MySQL value parameters for pagination
60
     * @var array
61
     */
62
    protected $paginationParameters = array();
63
64
    /**
65
     * The MySQL parameter types for pagination
66
     * @var string
67
     */
68
    protected $paginationTypes = '';
69
70
    /**
71
     * Extra MySQL query string to pass
72
     * @var string
73
     */
74
    protected $extras = '';
75
76
    /**
77
     * A column based on which we should sort the results
78
     * @var string|null
79
     */
80
    private $sortBy = null;
81
82
    /**
83
     * Whether to reverse the results
84
     * @var bool
85
     */
86
    private $reverseSort = false;
87
88
    /**
89
     * The currently selected column
90
     * @var string|null
91
     */
92
    private $currentColumn = null;
93
94
    /**
95
     * The currently selected column without the table name (unless it was
96
     * explicitly provided)
97
     * @var string|null
98
     */
99
    protected $currentColumnRaw = null;
100
101
    /**
102
     * A column to consider the name of the model
103
     * @var string|null
104
     */
105
    private $nameColumn = null;
106
107
    /**
108
     * Whether to return the results as arrays instead of models
109
     * @var bool
110
     */
111
    private $returnArray = false;
0 ignored issues
show
Unused Code introduced by
The property $returnArray is not used and could be removed.

This check marks private properties in classes that are never used. Those properties can be removed.

Loading history...
112
113
    /**
114
     * The page to return
115
     * @var int|null
116
     */
117
    private $page = null;
118
119
    /**
120
     * Whether the ID of the first/last element has been provided
121
     * @var bool
122
     */
123
    private $limited = false;
124
125
    /**
126
     * The number of elements on every page
127
     * @var int
128
     */
129
    protected $resultsPerPage = 30;
130
131
    /**
132
     * Create a new QueryBuilder
133
     *
134
     * A new query builder should be created on a static getQueryBuilder()
135
     * method on each model. The options array can contain the following
136
     * properties:
137
     *
138
     * - `columns`: An associative array - the key of each entry is the column
139
     *   name that will be used by other methods, while the value is
140
     *   is the column name that is used in the database structure
141
     *
142
     * - `activeStatuses`: If the model has a status column, this should be
143
     *                     a list of values that make the entry be considered
144
     *                     "active"
145
     *
146
     * - `name`: The name of the column which represents the name of the object
147
     *
148
     * @param string $type    The type of the Model (e.g. "Player" or "Match")
149
     * @param array  $options The options to pass to the builder (see above)
150
     */
151 4
    public function __construct($type, $options = array())
152
    {
153 4
        $this->type = $type;
154
155 4
        if (isset($options['columns'])) {
156 4
            $this->columns += $options['columns'];
157
        }
158
159 4
        if (isset($options['name'])) {
160 1
            $this->nameColumn = $options['name'];
161
        }
162 4
    }
163
164
    /**
165
     * Select a column
166
     *
167
     * `$queryBuilder->where('username')->equals('administrator');`
168
     *
169
     * @param  string $column The column to select
170
     * @return self
171
     */
172 4
    public function where($column)
173
    {
174 4
        if (!isset($this->columns[$column])) {
175
            throw new InvalidArgumentException("Unknown column '$column'");
176
        }
177
178 4
        $this->column($this->columns[$column]);
179
180 4
        return $this;
181
    }
182
183
    /**
184
     * Request that a column equals a string (case-insensitive)
185
     *
186
     * @param  string $string The string that the column's value should equal to
187
     * @return self
188
     */
189 1
    public function equals($string)
190
    {
191 1
        $this->addColumnCondition("= ?", $string, 's');
192
193 1
        return $this;
194
    }
195
196
    /**
197
     * Request that a column doesNOT equals a string (case-insensitive)
198
     *
199
     * @param  string $string The string that the column's value should equal to
200
     * @return self
201
     */
202
    public function notEquals($string)
203
    {
204
        $this->addColumnCondition("!= ?", $string, 's');
205
206
        return $this;
207
    }
208
209
    /**
210
     * Request that a timestamp is before the specified time
211
     *
212
     * @param string|TimeDate $time      The timestamp to compare to
213
     * @param bool            $inclusive Whether to include the given timestamp
214
     * @param bool            $reverse   Whether to reverse the results
215
     */
216
    public function isBefore($time, $inclusive = false, $reverse = false)
217
    {
218
        return $this->isAfter($time, $inclusive, !$reverse);
219
    }
220
221
    /**
222
     * Request that a timestamp is after the specified time
223
     *
224
     * @param string|TimeDate $time      The timestamp to compare to
225
     * @param bool            $inclusive Whether to include the given timestamp
226
     * @param bool            $reverse   Whether to reverse the results
227
     */
228
    public function isAfter($time, $inclusive = false, $reverse = false)
229
    {
230
        if ($time instanceof TimeDate) {
231
            $time = $time->toMysql();
232
        }
233
234
        $comparison  = ($reverse)   ? '<' : '>';
235
        $comparison .= ($inclusive) ? '=' : '';
236
237
        $this->addColumnCondition("$comparison ?",  $time, 's');
238
239
        return $this;
240
    }
241
242
    /**
243
     * Request that a column equals a number
244
     *
245
     * @param  int|Model|null $number The number that the column's value should
246
     *                                equal to. If a Model is provided, use the
247
     *                                model's ID, while null values are ignored.
248
     * @return self
249
     */
250 View Code Duplication
    public function is($number)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
251
    {
252
        if ($number === null) {
253
            return $this;
254
        }
255
256
        if ($number instanceof Model) {
257
            $number = $number->getId();
258
        }
259
260
        $this->addColumnCondition("= ?", $number, 'i');
261
262
        return $this;
263
    }
264
265
    /**
266
     * Request that a column equals one of some strings
267
     *
268
     * @param  string[] $strings The list of accepted values for the column
269
     * @return self
270
     */
271 3
    public function isOneOf($strings)
272
    {
273 3
        $count = count($strings);
274 3
        $types = str_repeat('s', $count);
275 3
        $questionMarks = str_repeat(',?', $count);
276
277
        // Remove first comma from questionMarks so that MySQL can read our query
278 3
        $questionMarks = ltrim($questionMarks, ',');
279
280 3
        $this->addColumnCondition("IN ($questionMarks)", $strings, $types);
281
282 3
        return $this;
283
    }
284
285
    /**
286
     * Request that a column value starts with a string (case-insensitive)
287
     *
288
     * @param  string $string The substring that the column's value should start with
289
     * @return self
290
     */
291
    public function startsWith($string)
292
    {
293
        $this->addColumnCondition("LIKE CONCAT(?, '%')", $string, 's');
294
295
        return $this;
296
    }
297
298
    /**
299
     * Request that a specific model is not returned
300
     *
301
     * @param  Model|int $model The ID or model you don't want to get
302
     * @return self
303
     */
304 View Code Duplication
    public function except($model)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
305
    {
306
        if ($model instanceof Model) {
307
            $model = $model->getId();
308
        }
309
310
        $this->where('id');
311
        $this->addColumnCondition("!= ?", $model, 'i');
312
313
        return $this;
314
    }
315
316
    /**
317
     * Return the results sorted by the value of a column
318
     *
319
     * @param  string $column The column based on which the results should be ordered
320
     * @return self
321
     */
322 2
    public function sortBy($column)
323
    {
324 2
        if (!isset($this->columns[$column])) {
325
            throw new Exception("Unknown column");
326
        }
327
328 2
        $this->sortBy = $this->columns[$column];
329
330 2
        return $this;
331
    }
332
333
    /**
334
     * Reverse the order
335
     *
336
     * Note: This only works if you have specified a column in the sortBy() method
337
     *
338
     * @return self
339
     */
340 2
    public function reverse()
341
    {
342 2
        $this->reverseSort = !$this->reverseSort;
343
344 2
        return $this;
345
    }
346
347
    /**
348
     * Specify the number of results per page
349
     *
350
     * @param  int  $count The number of results
351
     * @return self
352
     */
353 2
    public function limit($count)
354
    {
355 2
        $this->resultsPerPage = $count;
356
357 2
        return $this;
358
    }
359
360
    /**
361
     * Only show results from a specific page
362
     *
363
     * @param  int|null $page The page number (or null to show all pages - counting starts from 0)
364
     * @return self
365
     */
366 2
    public function fromPage($page)
367
    {
368 2
        $this->page = $page;
369
370 2
        return $this;
371
    }
372
373
    /**
374
     * End with a specific result
375
     *
376
     * @param  int|Model $model     The model (or database ID) after the first result
377
     * @param  bool   $inclusive Whether to include the provided model
378
     * @param  bool   $reverse   Whether to reverse the results
379
     * @return self
380
     */
381
    public function endAt($model, $inclusive = false, $reverse = false)
382
    {
383
        return $this->startAt($model, $inclusive, !$reverse);
384
    }
385
386
    /**
387
     * Start with a specific result
388
     *
389
     * @param  int|Model $model     The model (or database ID) before the first result
390
     * @param  bool   $inclusive Whether to include the provided model
391
     * @param  bool   $reverse   Whether to reverse the results
392
     * @return self
393
     */
394
    public function startAt($model, $inclusive = false, $reverse = false)
395
    {
396
        if (!$model) {
397
            return $this;
398
        } elseif ($model instanceof Model && !$model->isValid()) {
399
            return $this;
400
        }
401
402
        $this->column($this->sortBy);
403
        $this->limited = true;
404
        $column = $this->currentColumn;
405
        $table  = $this->getTable();
406
407
        $comparison  = $this->reverseSort ^ $reverse;
408
        $comparison  = ($comparison) ? '>' : '<';
409
        $comparison .= ($inclusive)  ? '=' : '';
410
        $id = ($model instanceof Model) ? $model->getId() : $model;
411
412
        // Compare an element's timestamp to the timestamp of $model; if it's the
413
        // same, perform the comparison using IDs
414
        $this->addColumnCondition(
415
            "$comparison (SELECT $column FROM $table WHERE id = ?) OR ($column = (SELECT $column FROM $table WHERE id = ?) AND id $comparison ?)",
416
            array($id, $id, $id),
417
            'iii'
418
        );
419
420
        return $this;
421
    }
422
423
    /**
424
     * Request that only "active" Models should be returned
425
     *
426
     * @return self
427
     */
428 3
    public function active()
429
    {
430 3
        if (!isset($this->columns['status'])) {
431
            return $this;
432
        }
433
434 3
        $type = $this->type;
435
436 3
        return $this->where('status')->isOneOf($type::getActiveStatuses());
437
    }
438
439
    /**
440
     * Make sure that Models invisible to a player are not returned
441
     *
442
     * Note that this method does not take PermissionModel::canBeSeenBy() into
443
     * consideration for performance purposes, so you will have to override this
444
     * in your query builder if necessary.
445
     *
446
     * @param  Player  $player      The player in question
447
     * @param  bool $showDeleted false to hide deleted models even from admins
448
     * @return self
449
     */
450 1
    public function visibleTo($player, $showDeleted = false)
451
    {
452 1
        $type = $this->type;
453
454 1
        if (is_subclass_of($type, "PermissionModel")
455 1
         && $player->hasPermission($type::EDIT_PERMISSION)) {
456
            // The player is an admin who can see hidden models
457
            if ($showDeleted) {
458
                return $this;
459
            } else {
460
                return $this->where('status')->notEquals('deleted');
461
            }
462
        } else {
463 1
            return $this->active();
464
        }
465
    }
466
467
    /**
468
     * Perform the query and get back the results in an array of names
469
     *
470
     * @return string[] An array of the type $id => $name
471
     */
472
    public function getNames()
473
    {
474
        if (!$this->nameColumn) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->nameColumn of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
475
            throw new Exception("You haven't specified a name column");
476
        }
477
478
        $results = $this->getArray($this->nameColumn);
479
480
        return array_column($results, $this->nameColumn, 'id');
481
    }
482
483
    /**
484
     * Perform the query and get back the results in a list of arrays
485
     *
486
     * @param string|string[] The column(s) that should be returned
487
     * @param  string  $columns
488
     * @return array[]
489
     */
490 View Code Duplication
    public function getArray($columns)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
491
    {
492
        if (!is_array($columns)) {
493
            $columns = array($columns);
494
        }
495
496
        $db = Database::getInstance();
497
498
        return $db->query($this->createQuery($columns), $this->getTypes(), $this->getParameters());
499
    }
500
501
    /**
502
     * Perform the query and get the results as Models
503
     *
504
     * @return array
505
     */
506 4 View Code Duplication
    public function getModels()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
507
    {
508 4
        $db   = Database::getInstance();
509 4
        $type = $this->type;
510
511 4
        $results = $db->query($this->createQuery(), $this->getTypes(), $this->getParameters());
512
513 4
        return $type::arrayIdToModel(array_column($results, 'id'));
514
    }
515
516
    /**
517
     * Count the results
518
     *
519
     * @return int
520
     */
521
    public function count()
522
    {
523
        $table  = $this->getTable();
524
        $params = $this->createQueryParams(false);
525
        $db     = Database::getInstance();
526
        $query  = "SELECT COUNT(*) FROM $table $params";
527
528
        // We don't want pagination to affect our results so don't use the functions that combine
529
        // pagination results
530
        $results = $db->query($query, $this->types, $this->parameters);
531
532
        return $results[0]['COUNT(*)'];
533
    }
534
535
    /**
536
     * Count the number of pages that all the models could be separated into
537
     */
538
    public function countPages()
539
    {
540
        return ceil($this->count() / $this->getResultsPerPage());
541
    }
542
543
    /**
544
     * Find if there is any result
545
     *
546
     * @return bool
547
     */
548
    public function any()
549
    {
550
        // Make sure that we don't mess with the user's options
551
        $query = clone $this;
552
553
        $query->limit(1);
554
555
        return $query->count() > 0;
556
    }
557
558
    /**
559
     * Get the amount of results that are returned per page
560
     * @return int
561
     */
562
    public function getResultsPerPage()
563
    {
564
        return $this->resultsPerPage;
565
    }
566
567
    /**
568
     * Select a column to perform opeations on
569
     *
570
     * This is identical to the `where()` method, except that the column is
571
     * specified as a MySQL column and not as a column name given by the model
572
     *
573
     * @param  string $column The column to select
574
     * @return self
575
     */
576 4
    protected function column($column)
577
    {
578 4
        if (strpos($column, '.') === false) {
579
            // Add the table name to the column if it isn't there already so that
580
            // MySQL knows what to do when handling multiple tables
581 4
            $table = $this->getTable();
582 4
            $this->currentColumn = "`$table`.`$column`";
583
        } else {
584
            $this->currentColumn = $column;
585
        }
586
587 4
        $this->currentColumnRaw = $column;
588
589 4
        return $this;
590
    }
591
592
    /**
593
     * Add a condition for the column
594
     * @param  string $condition The MySQL condition
595
     * @param  mixed  $value     Value(s) to pass to MySQL
596
     * @param  string $type      The type of the values
597
     * @return void
598
     */
599 4
    protected function addColumnCondition($condition, $value, $type)
600
    {
601 4
        if (!$this->currentColumn) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->currentColumn of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
602
            throw new Exception("You haven't selected a column!");
603
        }
604
605 4
        if (!is_array($value)) {
606 1
            $value = array($value);
607
        }
608
609 4
        $this->conditions[] = "{$this->currentColumn} $condition";
610 4
        $this->parameters   = array_merge($this->parameters, $value);
611 4
        $this->types       .= $type;
612
613 4
        $this->currentColumn = null;
614 4
        $this->currentColumnRaw = null;
615 4
    }
616
617
    /**
618
     * Get the MySQL extra parameters
619
     *
620
     * @param  bool $respectPagination Whether to respect pagination or not; useful for when pagination should be ignored such as count
621
     * @return string
622
     */
623 4
    protected function createQueryParams($respectPagination = true)
624
    {
625 4
        $extras     = $this->extras;
626 4
        $conditions = $this->createQueryConditions();
627 4
        $order      = $this->createQueryOrder();
628 4
        $pagination = "";
629
630 4
        if ($respectPagination) {
631 4
            $pagination = $this->createQueryPagination();
632
        }
633
634 4
        return "$extras $conditions $order $pagination";
635
    }
636
637
    /**
638
     * Get the query parameters
639
     *
640
     * @return array
641
     */
642 4
    protected function getParameters()
643
    {
644 4
        return array_merge($this->parameters, $this->paginationParameters);
645
    }
646
647
    /**
648
     * Get the query types
649
     *
650
     * @return string
651
     */
652 4
    protected function getTypes()
653
    {
654 4
        return $this->types . $this->paginationTypes;
655
    }
656
657
    /**
658
     * Get the table of the model
659
     *
660
     * @return string
661
     */
662 4
    protected function getTable()
663
    {
664 4
        $type = $this->type;
665
666 4
        return $type::TABLE;
667
    }
668
669
    /**
670
     * Get a MySQL query string in the requested format
671
     * @param  string[] $columns The columns that should be included (without the ID)
672
     * @return string   The query
673
     */
674 4
    protected function createQuery($columns = array())
675
    {
676 4
        $type     = $this->type;
677 4
        $table    = $type::TABLE;
678 4
        $columns  = $this->createQueryColumns($columns);
679 4
        $params   = $this->createQueryParams();
680
681 4
        return "SELECT $columns FROM $table $params";
682
    }
683
684
    /**
685
     * Generate the columns for the query
686
     * @param  string[] $columns The columns that should be included (without the ID)
687
     * @return string
688
     */
689 4
    private function createQueryColumns($columns = array())
690
    {
691 4
        $type = $this->type;
692 4
        $table = $type::TABLE;
693 4
        $columnStrings = array("`$table`.id");
694
695 4
        foreach ($columns as $returnName) {
696
            if (strpos($returnName, ' ') === false) {
697
                $dbName = $this->columns[$returnName];
698
                $columnStrings[] = "`$table`.`$dbName` as `$returnName`";
699
            } else {
700
                // "Column" contains a space, pass it as is
701
                $columnStrings[] = $returnName;
702
            }
703
        }
704
705 4
        return implode(',', $columnStrings);
706
    }
707
708
    /**
709
     * Generates all the WHERE conditions for the query
710
     * @return string
711
     */
712 4
    private function createQueryConditions()
713
    {
714 4
        if ($this->conditions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->conditions of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
715
            // Add parentheses around the conditions to prevent conflicts due
716
            // to the order of operations
717
            $conditions = array_map(function ($value) { return "($value)"; }, $this->conditions);
718
719 4
            return 'WHERE ' . implode(' AND ', $conditions);
720
        }
721
722
        return '';
723
    }
724
725
    /**
726
     * Generates the sorting instructions for the query
727
     * @return string
728
     */
729 4
    private function createQueryOrder()
730
    {
731 4
        if ($this->sortBy) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->sortBy of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
732 2
            $order = 'ORDER BY ' . $this->sortBy;
733 2
            if ($this->reverseSort) {
734 2
                $order .= ' DESC';
735
            }
736
        } else {
737 2
            $order = '';
738
        }
739
740 4
        return $order;
741
    }
742
743
    /**
744
     * Generates the pagination instructions for the query
745
     * @return string
746
     */
747 4
    private function createQueryPagination()
748
    {
749
        // Reset mysqli params and types just in case createQueryParagination()
750
        // had been called earlier
751 4
        $this->paginationParameters = array();
752 4
        $this->paginationTypes = "";
753
754 4
        if (!$this->page && !$this->limited) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->page of type integer|null is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
755 2
            return '';
756
        }
757
758 2
        $offset = '';
759 2
        if ($this->page) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->page of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
760 2
            $firstElement = ($this->page - 1) * $this->resultsPerPage;
761 2
            $this->paginationParameters[] = $firstElement;
762 2
            $this->paginationTypes       .= 'i';
763
764 2
            $offset = '?,';
765
        }
766
767 2
        $this->paginationParameters[] = $this->resultsPerPage;
768 2
        $this->paginationTypes       .= 'i';
769
770 2
        return "LIMIT $offset ?";
771
    }
772
}
773