Conditions::orSprintf()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
crap 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Sirius\Sql\Component;
5
6
use Sirius\Sql\Bindings;
7
use Sirius\Sql\ConditionsEnum;
8
use Sirius\Sql\Raw;
9
use Sirius\Sql\Select;
10
11
class Conditions extends Component
12
{
13
    protected $bindings;
14
15
    protected $type;
16
17
    protected $list = [];
18
19
    protected $openedGroups = 0;
20
21 19
    public function __construct(Bindings $bindings, string $type)
22
    {
23 19
        $this->bindings = $bindings;
24 19
        $this->type     = $type;
25 19
    }
26
27 1
    public function groupCurrent()
28
    {
29 1
        if (! empty($this->list)) {
30 1
            array_unshift($this->list, '(');
31 1
            $this->list[] = ')';
32
        }
33 1
    }
34
35 16
    public function and(string $column, $value = null, $condition = '='): void
36
    {
37 16
        $this->append('AND ', $this->buildExpression($column, $value, $condition));
38 16
    }
39
40 2
    public function andSprintf(string $format, ...$bindInline): void
41
    {
42 2
        $this->and($this->bindings->sprintf($format, ...$bindInline), null, null);
43 2
    }
44
45 6
    public function or(string $column, $value = null, $condition = '='): void
46
    {
47 6
        $this->append('OR ', $this->buildExpression($column, $value, $condition));
48 6
    }
49
50 2
    public function orSprintf(string $format, ...$bindInline): void
51
    {
52 2
        $this->or($this->bindings->sprintf($format, ...$bindInline), null, null);
53 2
    }
54
55 4
    public function openGroup($type = 'AND')
56
    {
57 4
        $this->append($type . ' ', '(');
58 4
        $this->openedGroups++;
59 4
    }
60
61 3
    public function closeGroup()
62
    {
63 3
        if ($this->openedGroups > 0) {
64 3
            $this->list[] = ')';
65 3
            $this->openedGroups--;
66
        }
67 3
    }
68
69 16
    protected function append(string $andor, string $expr): void
70
    {
71 16
        if (empty($this->list)) {
72 16
            $andor = '';
73
        }
74
75 16
        if (end($this->list) == 'AND (' || end($this->list) == 'OR (' || end($this->list) == '(') {
76 4
            $andor = '';
77
        }
78
79 16
        if (empty($this->list) && substr($andor, 0, 4) == 'AND ') {
80
            $andor = substr($andor, 4);
81
        }
82
83 16
        if (empty($this->list) && substr($andor, 0, 3) == 'OR ') {
84
            $andor = substr($andor, 3);
85
        }
86
87 16
        $this->list[] = $andor . $expr;
88 16
    }
89
90 16
    protected function buildExpression(string $column, $value = null, $condition = '='): string
91
    {
92 16
        if ($condition === null) {
93 6
            return $column;
94
        }
95
96 11
        if ($value === null) {
97 1
            return $column . ($condition == '=' ? ' IS NULL' : ' IS NOT NULL');
98
        }
99
100 11
        if ($value instanceof Raw) {
101 2
            $value = (string)$value;
102
103 2
            return "{$column} {$condition} {$value}";
104
        }
105
106 11
        if ($value instanceof Select) {
107
            $inNotIn = $condition == '=' ? 'IN' : 'NOT IN';
108
109
            return "{$column} {$inNotIn} (" . $value->getStatement() . ")";
110
        }
111
112 11
        if (is_array($value) && in_array($condition, [ConditionsEnum::EQUALS, ConditionsEnum::NOT_EQUALS])) {
113
            // do this for situations where the value is an empty array because it's the result of a previous
114
            // query that returned an empty collection (eg: select countries belonging to an empty collection of users)
115 3
            if (empty($value)) {
116 1
                $value = [-PHP_INT_MAX];
117
            }
118 3
            $bindings = $this->bindings->inline($value);
119
120 3
            $inNotIn = $condition == ConditionsEnum::EQUALS ? 'IN' : 'NOT IN';
121
122 3
            return "{$column} {$inNotIn} {$bindings}";
123
        }
124
125 11
        switch (strtolower(trim($condition))) {
126 11
            case ConditionsEnum::BETWEEN:
127 1
                $start = $this->bindings->inline($value[0]);
128 1
                $end   = $this->bindings->inline($value[1]);
129
130 1
                return "$column BETWEEN $start AND $end";
131 11
            case ConditionsEnum::STARTS_WITH:
132 2
                if (substr($value, -1) != '%') {
133 2
                    $value .= '%';
134
                }
135 2
                $condition = 'LIKE';
136 2
                break;
137 10
            case ConditionsEnum::ENDS_WITH:
138 1
                if (substr($value, 0, 1) != '%') {
139 1
                    $value = '%' . $value;
140
                }
141 1
                $condition = 'LIKE';
142 1
                break;
143 10
            case ConditionsEnum::CONTAINS:
144 2
                if (substr($value, 0, 1) != '%') {
145 2
                    $value = '%' . $value;
146
                }
147 2
                if (substr($value, -1) != '%') {
148 2
                    $value .= '%';
149
                }
150 2
                $condition = 'LIKE';
151 2
                break;
152 9
            case ConditionsEnum::DOES_NOT_START_WITH:
153 1
                if (substr($value, -1) != '%') {
154 1
                    $value .= '%';
155
                }
156 1
                $condition = 'NOT LIKE';
157 1
                break;
158 9
            case ConditionsEnum::DOES_NOT_END_WITH:
159 1
                if (substr($value, 0, 1) != '%') {
160 1
                    $value = '%' . $value;
161
                }
162 1
                $condition = 'NOT LIKE';
163 1
                break;
164 9
            case ConditionsEnum::DOES_NOT_CONTAIN:
165 1
                if (substr($value, 0, 1) != '%') {
166 1
                    $value = '%' . $value;
167
                }
168 1
                if (substr($value, -1) != '%') {
169 1
                    $value .= '%';
170
                }
171 1
                $condition = 'NOT LIKE';
172 1
                break;
173
        }
174 11
        $bind = $this->bindings->inline($value);
175
176 11
        return "$column $condition $bind";
177
    }
178
179 15
    protected function ensureGroupsAreClosed()
180
    {
181 15
        if ($this->openedGroups > 0) {
182 1
            $this->list[] = str_repeat(')', $this->openedGroups);
183 1
            $this->openedGroups = 0;
184
        }
185 15
    }
186
187 18
    public function build(): string
188
    {
189 18
        if (empty($this->list)) {
190 16
            return '';
191
        }
192 15
        $this->ensureGroupsAreClosed();
193
194 15
        return PHP_EOL . $this->type . $this->indent($this->list);
195
    }
196
}
197