Failed Conditions
Push — refactor/improve-static-analys... ( 8065ea...92b34c )
by Bas
05:43
created

Grammar::compileRandom()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 1
cts 1
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent\Query;
6
7
use Illuminate\Database\Query\Builder as IlluminateQueryBuilder;
8
use Illuminate\Database\Query\Expression;
9
use Illuminate\Database\Query\Grammars\Grammar as IlluminateQueryGrammar;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Traits\Macroable;
12
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesAggregates;
13
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesColumns;
14
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesFilters;
15
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesGroups;
16
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesDataManipulations;
17
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesJoins;
18
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesUnions;
19
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesWheres;
20
use LaravelFreelancerNL\Aranguent\Query\Concerns\ConvertsIdToKey;
21
use LaravelFreelancerNL\Aranguent\Query\Concerns\HandlesAqlGrammar;
22
23
class Grammar extends IlluminateQueryGrammar
24
{
25
    use CompilesAggregates;
0 ignored issues
show
Bug introduced by
The trait LaravelFreelancerNL\Aran...erns\CompilesAggregates requires the property $from which is not provided by LaravelFreelancerNL\Aranguent\Query\Grammar.
Loading history...
26
    use CompilesColumns;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...oncerns\CompilesColumns requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $groups, $returnSingleValue, $distinct, $from, $joins, $table, $tableAliases
Loading history...
27
    use CompilesFilters;
0 ignored issues
show
Bug introduced by
The trait LaravelFreelancerNL\Aran...oncerns\CompilesFilters requires the property $havings which is not provided by LaravelFreelancerNL\Aranguent\Query\Grammar.
Loading history...
28
    use CompilesDataManipulations;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...mpilesDataManipulations requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $from, $joins
Loading history...
29
    use CompilesJoins;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...\Concerns\CompilesJoins requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $type, $table, $grammar
Loading history...
30
    use CompilesGroups;
31
    use CompilesUnions;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...Concerns\CompilesUnions requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $unions, $unionOrders, $unionOffset, $unionLimit
Loading history...
32
    use CompilesWheres;
33
    use ConvertsIdToKey;
34
    use HandlesAqlGrammar;
35
    use Macroable;
36
37
    public $name;
38
39
    /**
40
     * The grammar table prefix.
41
     *
42
     * @var string
43
     */
44
    protected $tablePrefix = '';
45
46
    /**
47
     * The grammar table prefix.
48
     *
49
     * @var null|int
50
     */
51
    protected $offset = null;
52
53
    /**
54
     * The grammar specific operators.
55
     *
56
     * @var array
57
     */
58
    protected $operators = [
59
        '==', '!=', '<', '>', '<=', '>=',
60
        'LIKE', '~', '!~',
61
        'IN', 'NOT IN',
62
        'ALL ==', 'ALL !=', 'ALL <', 'ALL >', 'ALL <=', 'ALL >=', 'ALL IN',
63
        'ANY ==', 'ANY !=', 'ANY <', 'ANY >', 'ANY <=', 'ANY >=', 'ANY IN',
64
        'NONE ==', 'NONE !=', 'NONE <', 'NONE >', 'NONE <=', 'NONE >=', 'NONE IN',
65
    ];
66
67
    /**
68
     * The components that make up a select clause.
69
     *
70
     * @var array<string>
71
     */
72
    protected $selectComponents = [
73
        'preIterationVariables',
74
        'from',
75
        'search',
76
        'joins',
77
        'postIterationVariables',
78
        'wheres',
79
        'groups',
80
        'aggregate',
81
        'havings',
82
        'orders',
83
        'offset',
84
        'limit',
85
        'columns',
86 49
    ];
87
88 49
    protected $operatorTranslations = [
89
        '='          => '==',
90
        '<>'         => '!=',
91
        '<=>'        => '==',
92
        'rlike'      => '=~',
93
        'not rlike'  => '!~',
94
        'regexp'     => '=~',
95
        'not regexp' => '!~',
96 12
    ];
97
98 12
    protected $whereTypeOperators = [
99
        'In'    => 'IN',
100
        'NotIn' => 'NOT IN',
101 162
    ];
102
103 162
    /**
104
     * The grammar specific bitwise operators.
105
     *
106
     * @var array
107
     */
108
    public $bitwiseOperators = [
109
        '&', '|', '^', '<<', '>>', '~',
110
    ];
111
112
    /**
113
     * Get the format for database stored dates.
114
     *
115
     * @return string
116 44
     */
117
    public function getDateFormat()
118 44
    {
119 1
        return 'Y-m-d\TH:i:s.vp';
120
    }
121 44
122
    /**
123 44
     * Get the grammar specific operators.
124
     *
125
     * @return array
126
     */
127
    public function getOperators()
128
    {
129
        return $this->operators;
130 44
    }
131 44
132
133
    public function translateOperator(string $operator): string
134 44
    {
135 44
        if (array_key_exists($operator, $this->operatorTranslations)) {
136 44
            return $this->operatorTranslations[$operator];
137 44
        }
138
139 44
        return $operator;
140
    }
141
142
    protected function prefixTable($table)
143
    {
144
        return $this->tablePrefix . $table;
145
    }
146
147 10
148
    /**
149 10
     * Get the appropriate query parameter place-holder for a value.
150 10
     *
151
     * @param  mixed  $value
152 10
     * @return string
153
     */
154 10
    public function parameter($value)
155 9
    {
156
157
        return $this->isExpression($value) ? $this->getValue($value) : $value;
158 10
    }
159
160
    /**
161
     * Compile the components necessary for a select clause.
162
     *
163
     * @param  IlluminateQueryBuilder  $query
164
     * @return array
165
     */
166 10
    protected function compileComponents(IlluminateQueryBuilder $query)
167 10
    {
168
        $aql = [];
169
170 10
        foreach ($this->selectComponents as $component) {
171 10
            if ($component === 'unions') {
172 10
                continue;
173 10
            }
174
175 10
            if (isset($query->$component)) {
176
                $method = 'compile' . ucfirst($component);
177
178
                $aql[$component] = $this->$method($query, $query->$component);
179
            }
180
        }
181
182
        return $aql;
183
    }
184
185 98
186
187 98
    /**
188 98
     * Compile a select query into SQL.
189
     *
190 98
     * @param IlluminateQueryBuilder $query
191
     * @return string
192 98
     */
193
    public function compileSelect(IlluminateQueryBuilder $query)
194
    {
195
        assert($query instanceof Builder);
196
197
        // If the query does not have any columns set, we'll set the columns to the
198
        // * character to just get all of the columns from the database. Then we
199 98
        // can build the query and concatenate all the pieces together as one.
200 98
        $original = $query->columns;
201
202
        if (empty($query->columns)) {
203 98
            $query->columns = ['*'];
204 98
        }
205 98
206 98
        // To compile the query, we'll spin through each component of the query and
207 98
        // see if that component exists. If it does we'll just call the compiler
208
        // function for the component which is responsible for making the SQL.
209 98
210
        $aql = trim(
211
            $this->concatenate(
212
                $this->compileComponents($query)
213
            )
214
        );
215
216
        //        if ($query->unions && $query->aggregate) {
217
        //            return $this->compileUnionAggregate($query);
218
        //        }
219
        if ($query->unions) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $query->unions of type array 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...
220 146
            return $this->compileUnions($query, $aql);
221
        }
222
223
        $query->columns = $original;
224
225
        if ($query->groupVariables !== null) {
226
            $query->cleanGroupVariables();
227
        }
228
229
        return $aql;
230 146
    }
231
232
    /**
233
     * Compile the "from" portion of the query -> FOR in AQL.
234
     *
235
     * @param IlluminateQueryBuilder $query
236 146
     * @param string  $table
237
     *
238
     * @return string
239
     */
240
    protected function compileFrom(IlluminateQueryBuilder $query, $table)
241
    {
242
        assert($query instanceof Builder);
243
244
        // FIXME: wrapping/quoting
245 1
        $table = $this->prefixTable($table);
246
247
        //FIXME: register given alias (x AS y in SQL)
248 1
        $alias = $query->registerTableAlias($table);
249 1
250 1
251
        return "FOR $alias IN $table";
252
    }
253
254
    /**
255
     * @param IlluminateQueryBuilder $query
256
     * @param array $variables
257
     * @return string
258
     */
259
    protected function compilePreIterationVariables(IlluminateQueryBuilder $query, array $variables): string
260 146
    {
261
        return $this->compileVariables($query, $variables);
262 146
    }
263
264
    /**
265
     * @param IlluminateQueryBuilder $query
266
     * @param array $variables
267 146
     * @return string
268 146
     */
269
    protected function compilePostIterationVariables(IlluminateQueryBuilder $query, array $variables): string
270 146
    {
271
        return $this->compileVariables($query, $variables);
272
    }
273
274 146
275
    /**
276
     * @param IlluminateQueryBuilder $query
277
     * @param array $variables
278
     * @return string
279
     *
280
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
281
     */
282
    protected function compileVariables(IlluminateQueryBuilder $query, array $variables): string
283
    {
284
        $aql = '';
285 146
286
        foreach ($variables as $variable => $value) {
287 146
            if ($value instanceof Expression) {
288 146
                $value = $value->getValue($this);
289
            }
290 146
291
            $aql .= ' LET ' . $variable . ' = ' . $value;
292 146
        }
293
294
        return trim($aql);
295
    }
296
297
    /**
298
     * Compile the "order by" portions of the query.
299
     *
300 146
     * @param  \Illuminate\Database\Query\Builder  $query
301
     * @param  array  $orders
302 146
     * @return string
303 1
     */
304 1
    protected function compileOrders(IlluminateQueryBuilder $query, $orders, $table = null)
305
    {
306
        if (!empty($orders)) {
307
            return 'SORT ' . implode(', ', $this->compileOrdersToArray($query, $orders, $table));
308 146
        }
309
310
        return '';
311
    }
312
313
    /**
314
     * Compile the query orders to an array.
315
     *
316
     * @param  \Illuminate\Database\Query\Builder  $query
317
     * @param  array  $orders
318
     * @return array
319 3
     */
320
    protected function compileOrdersToArray(IlluminateQueryBuilder $query, $orders, $table = null)
321 3
    {
322 3
        return array_map(function ($order) use ($query, $table) {
323 3
            $key = 'column';
324
            if (array_key_exists('sql', $order)) {
325 3
                $key = 'sql';
326
            }
327
328
            if ($order[$key] instanceof Expression) {
329
                $order[$key] = $order[$key]->getValue($this);
330
            } else {
331
                $order[$key] = $this->normalizeColumn($query, $order[$key], $table);
332
            }
333
334
            return array_key_exists('direction', $order) ? $order[$key] . ' ' . $order['direction'] : $order[$key];
335
        }, $orders);
336
    }
337
338
    /**
339 3
     * Compile the "offset" portions of the query.
340
     *
341 3
     * @param  \Illuminate\Database\Query\Builder  $query
342
     * @param  int  $offset
343 3
     * @return string
344 3
     *
345 2
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
346
     */
347
    protected function compileOffset(IlluminateQueryBuilder $query, $offset)
348 3
    {
349
        $this->offset = (int) $offset;
350 3
351 2
        return "";
352
    }
353
354
    /**
355 3
     * Compile the "limit" portions of the query.
356
     *
357
     * @param  \Illuminate\Database\Query\Builder  $query
358
     * @param  int  $limit
359
     * @return string
360
     *
361
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
362
     */
363
    protected function compileLimit(IlluminateQueryBuilder $query, $limit)
364
    {
365
        if ($this->offset !== null) {
366
            return "LIMIT " . (int) $this->offset . ", " . (int) $limit;
367 4
        }
368
369 4
        return "LIMIT " . (int) $limit;
370
    }
371 4
372
    /**
373
     * Compile the random statement into SQL.
374
     *
375
     * @param  string|int|null  $seed
376
     * @return string
377
     */
378
    public function compileRandom($seed = null)
379
    {
380
        unset($seed);
381
382 72
        return "RAND()";
383
    }
384 72
385 4
    /**
386
     * @param IlluminateQueryBuilder $query
387 4
     * @return string
388
     * @throws \Exception
389 68
     */
390
    public function compileSearch(IlluminateQueryBuilder $query, array $search)
391 68
    {
392
        $predicates = [];
393
        foreach($search['fields'] as $field) {
394
            $predicates[] = $this->normalizeColumn($query, $field)
395
                . ' IN TOKENS(' . $search['searchText'] . ', "text_en")';
396
        }
397
398
        return 'SEARCH ANALYZER('
399
            . implode(' OR ', $predicates)
400
            . ', "text_en")';
401
    }
402
403 23
    /**
404
     * Get the value of a raw expression.
405
     *
406 23
     * @param Expression $expression
407 23
     * @return string
408
     */
409 23
    public function getValue($expression)
410
    {
411
        if (!$expression instanceof Expression) {
0 ignored issues
show
introduced by
$expression is always a sub-type of Illuminate\Database\Query\Expression.
Loading history...
412 23
            return $expression;
413
        }
414 23
415
        return $expression->getValue($this);
416 23
    }
417
418
    /**
419
     * Get the grammar specific bit operators.
420
     *
421
     * @return array
422
     */
423
    public function getBitwiseOperators()
424
    {
425
        return $this->bitwiseOperators;
426
    }
427
428
    /**
429
     * Prepare the bindings for a delete statement.
430 1
     *
431
     * @param  array  $bindings
432
     * @return array
433 1
     */
434 1
    public function prepareBindingsForDelete(array $bindings)
435
    {
436
        return Arr::collapse(
437 1
            Arr::except($bindings, 'select')
438 1
        );
439
    }
440
}
441