DQLQueryBuilder::buildLimit()   B
last analyzed

Complexity

Conditions 7
Paths 9

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 10
c 3
b 0
f 0
dl 0
loc 23
ccs 10
cts 10
cp 1
rs 8.8333
cc 7
nc 9
nop 2
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Mysql;
6
7
use Yiisoft\Db\Expression\Expression;
8
use Yiisoft\Db\Expression\ExpressionInterface;
9
use Yiisoft\Db\Expression\JsonExpression;
10
use Yiisoft\Db\Mysql\Builder\ExpressionBuilder;
11
use Yiisoft\Db\Mysql\Builder\JsonExpressionBuilder;
12
use Yiisoft\Db\QueryBuilder\AbstractDQLQueryBuilder;
13
14
use function array_merge;
15
use function ctype_digit;
16
17
/**
18
 * Implements a DQL (Data Query Language) SQL statements for MySQL, MariaDB.
19
 */
20
final class DQLQueryBuilder extends AbstractDQLQueryBuilder
21 258
{
22
    public function buildLimit(ExpressionInterface|int|null $limit, ExpressionInterface|int|null $offset): string
23 258
    {
24
        $sql = '';
25 258
26 17
        if ($this->hasLimit($limit)) {
27
            $sql = 'LIMIT ' . ($limit instanceof ExpressionInterface ? $this->buildExpression($limit) : (string)$limit);
28 17
29 17
            if ($this->hasOffset($offset)) {
30
                $sql .= ' OFFSET ' . ($offset instanceof ExpressionInterface ? $this->buildExpression($offset) : (string)$offset);
31 247
            }
32
        } elseif ($this->hasOffset($offset)) {
33
            /**
34
             * Limit isn't optional in MySQL.
35
             *
36
             * @link https://stackoverflow.com/a/271650/1106908
37
             * @link https://dev.mysql.com/doc/refman/5.0/en/select.html#idm47619502796240
38 1
             */
39 1
            $sql = 'LIMIT ' .
40 1
                ($offset instanceof ExpressionInterface ? $this->buildExpression($offset) : (string)$offset) .
41
                ', 18446744073709551615'; // 2^64-1
42
        }
43 258
44
        return $sql;
45
    }
46
47
    /**
48
     * Checks to see if the given limit is effective.
49
     *
50
     * @param mixed $limit The given limit.
51
     *
52
     * @return bool Whether the limit is effective.
53 258
     */
54
    protected function hasLimit(mixed $limit): bool
55
    {
56 258
        /** In MySQL limit argument must be a non-negative integer constant */
57
        return ctype_digit((string) $limit);
58
    }
59
60
    /**
61
     * Checks to see if the given offset is effective.
62
     *
63
     * @param mixed $offset The given offset.
64
     *
65
     * @return bool Whether the offset is effective.
66 258
     */
67
    protected function hasOffset(mixed $offset): bool
68
    {
69 258
        /** In MySQL offset argument must be a non-negative integer constant */
70 258
        $offset = (string) $offset;
71
        return ctype_digit($offset) && $offset !== '0';
72
    }
73
74
    /**
75
     * Has an array of default expression builders.
76
     *
77
     * Extend this method and override it if you want to change default expression builders for this query builder.
78
     *
79
     * {@see ExpressionBuilder} docs for details.
80 549
     */
81
    protected function defaultExpressionBuilders(): array
82 549
    {
83 549
        return array_merge(
84 549
            parent::defaultExpressionBuilders(),
85 549
            [
86 549
                JsonExpression::class => JsonExpressionBuilder::class,
87 549
                Expression::class => ExpressionBuilder::class,
88
            ]
89
        );
90
    }
91
}
92