Passed
Push — feature-FRAM-87-replace-where-... ( 9ff6e0 )
by Vincent
29:09
created

Clause   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Test Coverage

Coverage 95.35%

Importance

Changes 0
Metric Value
wmc 31
eloc 105
c 0
b 0
f 0
dl 0
loc 237
ccs 82
cts 86
cp 0.9535
rs 9.92

10 Methods

Rating   Name   Duplication   Size   Complexity  
A setCustomFilters() 0 5 1
A getCustomFilters() 0 3 1
A addStatement() 0 3 1
A addCustomFilter() 0 5 1
A statement() 0 3 1
C buildClause() 0 57 13
A buildRaw() 0 8 1
A buildNested() 0 17 2
A addCommand() 0 5 1
B replaceClause() 0 31 9
1
<?php
2
3
namespace Bdf\Prime\Query;
4
5
use Doctrine\DBAL\Query\Expression\CompositeExpression;
6
7
/**
8
 * Clause
9
 *
10
 * @author seb
11
 */
12
class Clause implements ClauseInterface
13
{
14
    /**
15
     * The collection of custom filter.
16
     *
17
     * @var array<string,callable(static,mixed):void>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string,callable(static,mixed):void> at position 4 could not be parsed: Expected '>' at position 4, but found 'callable'.
Loading history...
18
     */
19
    protected $customFilters = [];
20
21
    /**
22
     * The clause statements
23
     *
24
     * @var array<string,mixed>
25
     */
26
    public $statements = [];
27
28
    /**
29
     * Available operators
30
     *
31
     * @var array<string, true>
32
     */
33
    protected $operators = [
34
        '<'             => true,
35
        ':lt'           => true,
36
        '<='            => true,
37
        ':lte'          => true,
38
        '>'             => true,
39
        ':gt'           => true,
40
        '>='            => true,
41
        ':gte'          => true,
42
        '~='            => true,
43
        '=~'            => true,
44
        ':regex'        => true,
45
        ':like'         => true,
46
        'in'            => true,
47
        ':in'           => true,
48
        'notin'         => true,
49
        '!in'           => true,
50
        ':notin'        => true,
51
        'between'       => true,
52
        ':between'      => true,
53
        '!between'      => true,
54
        ':notbetween'   => true,
55
        '<>'            => true,
56
        '!='            => true,
57
        ':ne'           => true,
58
        ':not'          => true,
59
        '='             => true,
60
        ':eq'           => true,
61
    ];
62
63
    /**
64
     * {@inheritdoc}
65
     */
66 710
    public function setCustomFilters(array $filters)
67
    {
68 710
        $this->customFilters = $filters;
69
70 710
        return $this;
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 2
    public function addCustomFilter(string $name, callable $callback)
77
    {
78 2
        $this->customFilters[$name] = $callback;
79
80 2
        return $this;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function getCustomFilters(): array
87
    {
88
        return $this->customFilters;
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94 122
    public function statement(string $statement): array
95
    {
96 122
        return $this->statements[$statement] ?? [];
97
    }
98
99
    /**
100
     * {@inheritdoc}
101
     */
102 112
    public function addStatement(string $name, $values): void
103
    {
104 112
        $this->statements[$name][] = $values;
105
    }
106
107
    /**
108
     * {@inheritdoc}
109
     */
110 677
    public function buildClause(string $statement, $expression, $operator = null, $value = null, string $type = CompositeExpression::TYPE_AND)
111
    {
112 677
        if (is_array($expression)) {
113
            //nested expression
114 619
            $glue = ($operator ?: CompositeExpression::TYPE_AND);
115 619
            $parts = [];
116
117 619
            foreach ($expression as $key => $value) {
118 295
                if (isset($this->customFilters[$key])) {
119
                    // Custom filter
120 2
                    $this->customFilters[$key]($this, $value);
121 294
                } elseif (is_int($key)) {
122
                    // Raw value
123 3
                    $this->buildRaw($statement, $value, $glue);
124 291
                } elseif ($key[0] === ':') {
125
                    // Special command
126 6
                    $this->addCommand($key, $value);
127
                } else {
128
                    // Column with operator
129 288
                    $key  = explode(' ', trim($key), 2);
130 288
                    $parts[] = [
131 288
                        'column'    => $key[0],
132 288
                        'operator'  => isset($key[1]) ? $key[1] : '=',
133 288
                        'value'     => $value,
134 288
                        'glue'      => $glue,
135 288
                    ];
136
                }
137
            }
138
139 619
            if ($parts) {
140 619
                $this->statements[$statement][] = [
141 619
                    'nested'  => $parts,
142 619
                    'glue'    => $type,
143 619
                ];
144
            }
145
        } else {
146
            //if no value. Check if operator is a value. Otherwise we assume it is a 'is null' request
147 406
            if ($value === null && (!is_string($operator) || !isset($this->operators[$operator]))) {
148 331
                $value = $operator;
149 331
                $operator = '=';
150
            }
151
152 406
            if (isset($this->customFilters[$expression])) {
153
                // Custom filter
154 3
                $this->customFilters[$expression]($this, $value);
155
            } else {
156
                // Column with operator
157 404
                $this->statements[$statement][] = [
158 404
                    'column'    => $expression,
159 404
                    'operator'  => $operator,
160 404
                    'value'     => $value,
161 404
                    'glue'      => $type,
162 404
                ];
163
            }
164
        }
165
166 677
        return $this;
167
    }
168
169
    /**
170
     * {@inheritdoc}
171
     */
172 12
    public function replaceClause(string $statement, string $expression, $operator = null, $value = null)
173
    {
174 12
        if ($value === null && (!is_string($operator) || !isset($this->operators[$operator]))) {
175 1
            $value = $operator;
176 1
            $operator = '=';
177
        }
178
179 12
        $found = false;
180
181 12
        foreach ($this->statements[$statement] ?? [] as $key => $clause) {
182
            if (
183 11
                isset($clause['column'], $clause['operator'], $clause['value'])
184 11
                && $clause['column'] === $expression
185 11
                && $clause['operator'] === $operator
186
            ) {
187 11
                $this->statements[$statement][$key]['value'] = $value;
188 11
                $found = true;
189 11
                break;
190
            }
191
        }
192
193 12
        if (!$found) {
194 12
            $this->statements[$statement][] = [
195 12
                'column'    => $expression,
196 12
                'operator'  => $operator,
197 12
                'value'     => $value,
198 12
                'glue'      => CompositeExpression::TYPE_AND,
199 12
            ];
200
        }
201
202 12
        return $this;
203
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208 14
    public function buildRaw(string $statement, $expression, string $type = CompositeExpression::TYPE_AND)
209
    {
210 14
        $this->statements[$statement][] = [
211 14
            'raw'  => $expression,
212 14
            'glue' => $type,
213 14
        ];
214
215 14
        return $this;
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221 4
    public function buildNested(string $statement, callable $callback, string $type = CompositeExpression::TYPE_AND)
222
    {
223 4
        $statements = $this->statements;
224 4
        $this->statements = [];
225
226 4
        $callback($this);
227
228 4
        if (!empty($this->statements[$statement])) {
229 4
            $statements[$statement][] = [
230 4
                'nested' => $this->statements[$statement],
231 4
                'glue'   => $type,
232 4
            ];
233
        }
234
235 4
        $this->statements = $statements;
236
237 4
        return $this;
238
    }
239
240
    /**
241
     * @todo Revoir cette gestion des commandes
242
     * {@inheritdoc}
243
     */
244
    public function addCommand(string $command, $value)
245
    {
246
        // TO overload
247
248
        return $this;
249
    }
250
}
251