Passed
Pull Request — master (#20)
by Teye
07:52
created

HasFilter::whereFlags()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 20
ccs 4
cts 4
cp 1
rs 10
cc 1
nc 1
nop 3
crap 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A HasFilter::whereNotColumn() 0 8 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Level23\Druid\Concerns;
5
6
use Closure;
7
use InvalidArgumentException;
8
use Level23\Druid\Filters\InFilter;
9
use Level23\Druid\Filters\OrFilter;
10
use Level23\Druid\Filters\AndFilter;
11
use Level23\Druid\Filters\NotFilter;
12
use Level23\Druid\Interval\Interval;
13
use Level23\Druid\Filters\LikeFilter;
14
use Level23\Druid\Filters\BoundFilter;
15
use Level23\Druid\Filters\RegexFilter;
16
use Level23\Druid\Filters\SearchFilter;
17
use Level23\Druid\Dimensions\Dimension;
18
use Level23\Druid\Filters\FilterBuilder;
19
use Level23\Druid\Filters\BetweenFilter;
20
use Level23\Druid\Filters\IntervalFilter;
21
use Level23\Druid\Filters\SelectorFilter;
22
use Level23\Druid\Filters\FilterInterface;
23
use Level23\Druid\Filters\JavascriptFilter;
24
use Level23\Druid\Interval\IntervalInterface;
25
use Level23\Druid\Dimensions\DimensionBuilder;
26
use Level23\Druid\Extractions\ExtractionBuilder;
27
use Level23\Druid\Dimensions\DimensionInterface;
28
use Level23\Druid\Filters\ColumnComparisonFilter;
29
use Level23\Druid\Extractions\ExtractionInterface;
30
31
trait HasFilter
32
{
33
    /**
34
     * @var \Level23\Druid\Filters\FilterInterface|null
35
     */
36
    protected $filter;
37
38
    /**
39
     * Filter our results where the given dimension matches the value based on the operator.
40
     * The operator can be '=', '>', '>=', '<', '<=', '<>', '!=', 'like', 'not like', 'regex', 'not regex',
41
     * 'javascript', 'not javascript', 'search' and 'not search'
42
     *
43
     * @param string|FilterInterface|\Closure $filterOrDimensionOrClosure The dimension which you want to filter.
44
     * @param string|null                     $operator                   The operator which you want to use to filter.
45
     *                                                                    See below for a complete list of supported
46
     *                                                                    operators.
47
     * @param mixed                           $value                      The value which you want to use in your
48
     *                                                                    filter comparison
49
     * @param \Closure|null                   $extraction                 A closure which builds one or more extraction
50
     *                                                                    function. These are applied before the filter
51
     *                                                                    will be applied. So the filter will use the
52
     *                                                                    value returned by the extraction function(s).
53
     * @param string                          $boolean                    This influences how this filter will be
54
     *                                                                    joined with previous added filters. Should
55
     *                                                                    both filters apply ("and") or one or the
56
     *                                                                    other ("or") ? Default is "and".
57
     *
58
     * @return $this
59
     */
60 50
    public function where(
61
        $filterOrDimensionOrClosure,
62
        $operator = null,
63
        $value = null,
64
        Closure $extraction = null,
65
        string $boolean = 'and'
66
    ) {
67 50
        $filter = null;
68 50
        if (is_string($filterOrDimensionOrClosure)) {
69 34
            if ($value === null && $operator !== null) {
70 2
                $value    = $operator;
71 2
                $operator = '=';
72
            }
73
74 34
            if ($operator === null || $value === null) {
75 2
                throw new InvalidArgumentException('You have to supply an operator and an compare value when you supply a dimension as string');
76
            }
77
78 32
            $operator = strtolower($operator);
79
80 32
            if ($operator == '=') {
81 12
                $filter = new SelectorFilter(
82 12
                    $filterOrDimensionOrClosure,
83 12
                    (string)$value,
84 12
                    $this->getExtraction($extraction)
85
                );
86 20
            } elseif ($operator == '<>' || $operator == '!=') {
87 5
                $filter = new NotFilter(
88 5
                    new SelectorFilter($filterOrDimensionOrClosure, (string)$value, $this->getExtraction($extraction))
89
                );
90 15
            } elseif (in_array($operator, ['>', '>=', '<', '<='])) {
91 4
                $filter = new BoundFilter(
92 4
                    $filterOrDimensionOrClosure,
93 4
                    $operator,
94 4
                    (string)$value,
95 4
                    null,
96 4
                    $this->getExtraction($extraction)
97
                );
98 11
            } elseif ($operator == 'like') {
99 1
                $filter = new LikeFilter(
100 1
                    $filterOrDimensionOrClosure, $value, '\\', $this->getExtraction($extraction)
101
                );
102 10
            } elseif ($operator == 'not like') {
103 1
                $filter = new NotFilter(
104 1
                    new LikeFilter($filterOrDimensionOrClosure, $value, '\\', $this->getExtraction($extraction))
105
                );
106 9
            } elseif ($operator == 'javascript') {
107 1
                $filter = new JavascriptFilter($filterOrDimensionOrClosure, $value, $this->getExtraction($extraction));
108 8
            } elseif ($operator == 'not javascript') {
109 1
                $filter = new NotFilter(
110 1
                    new JavascriptFilter($filterOrDimensionOrClosure, $value, $this->getExtraction($extraction))
111
                );
112 7
            } elseif ($operator == 'regex' || $operator == 'regexp') {
113 2
                $filter = new RegexFilter($filterOrDimensionOrClosure, $value, $this->getExtraction($extraction));
114 5
            } elseif ($operator == 'not regex' || $operator == 'not regexp') {
115 2
                $filter = new NotFilter(
116 2
                    new RegexFilter($filterOrDimensionOrClosure, $value, $this->getExtraction($extraction))
117
                );
118 3
            } elseif ($operator == 'search') {
119 1
                $filter = new SearchFilter(
120 1
                    $filterOrDimensionOrClosure, $value, false, $this->getExtraction($extraction)
121
                );
122 2
            } elseif ($operator == 'not search') {
123 1
                $filter = new NotFilter(new SearchFilter(
124 1
                    $filterOrDimensionOrClosure, $value, false, $this->getExtraction($extraction)
125
                ));
126
            } else {
127 32
                $filter = null;
128
            }
129 17
        } elseif ($filterOrDimensionOrClosure instanceof FilterInterface) {
130 12
            $filter = $filterOrDimensionOrClosure;
131 6
        } elseif ($filterOrDimensionOrClosure instanceof Closure) {
132
133
            // lets create a bew builder object where the user can mess around with
134 2
            $builder = new FilterBuilder();
135
136
            // call the user function
137 2
            call_user_func($filterOrDimensionOrClosure, $builder);
138
139
            // Now retrieve the filter which was created and add it to our current filter set.
140 2
            $filter = $builder->getFilter();
141
        }
142
143 48
        if ($filter === null) {
144 5
            throw new InvalidArgumentException('The arguments which you have supplied cannot be parsed.');
145
        }
146
147 43
        strtolower($boolean) == 'and' ? $this->addAndFilter($filter) : $this->addOrFilter($filter);
148
149 43
        return $this;
150
    }
151
152
    /**
153
     * Build a where selection which is inverted
154
     *
155
     * @param \Closure $filterBuilder A closure which will receive a FilterBuilder instance.
156
     * @param string   $boolean       This influences how this filter will be joined with previous added filters.
157
     *                                Should both filters apply ("and") or one or the other ("or") ? Default is "and".
158
     *
159
     * @return $this
160
     */
161 1
    public function whereNot(Closure $filterBuilder, $boolean = 'and')
162
    {
163
        // lets create a bew builder object where the user can mess around with
164 1
        $builder = new FilterBuilder();
165
166
        // call the user function
167 1
        call_user_func($filterBuilder, $builder);
168
169
        // Now retrieve the filter which was created and add it to our current filter set.
170 1
        $filter = $builder->getFilter();
171 1
        if ($filter) {
172 1
            return $this->where(new NotFilter($filter), null, null, null, $boolean);
173
        }
174
175
        // Whe no filter was given, just return.
176
        return $this;
177
    }
178
179
    /**
180
     * Build a where selection which is inverted
181
     *
182
     * @param \Closure $filterBuilder A closure which will receive a FilterBuilder instance.
183
     *
184
     * @return $this
185
     */
186 1
    public function orWhereNot(Closure $filterBuilder)
187
    {
188 1
        return $this->whereNot($filterBuilder, 'or');
189
    }
190
191
    /**
192
     * This applies a filter, only it will join previous added filters with an "or" instead of an "and".
193
     * See the documentation of the "where" method for more information
194
     *
195
     * @param string|FilterInterface $filterOrDimension
196
     * @param string|null            $operator
197
     * @param mixed|null             $value
198
     * @param \Closure|null          $extraction
199
     *
200
     * @return $this
201
     * @see \Level23\Druid\Concerns\HasFilter::where()
202
     */
203 2
    public function orWhere($filterOrDimension, $operator = null, $value = null, Closure $extraction = null)
204
    {
205 2
        return $this->where($filterOrDimension, $operator, $value, $extraction, 'or');
206
    }
207
208
    /**
209
     * Filter records where the given dimension exists in the given list of items
210
     *
211
     * @param string        $dimension  The dimension which you want to filte
212
     * @param array         $items      A list of values. We will return records where the dimension is in this list.
213
     * @param \Closure|null $extraction An extraction function to extract a different value from the dimension.
214
     * @param string        $boolean    This influences how this filter will be joined with previous added filters.
215
     *                                  Should both filters apply ("and") or one or the other ("or") ? Default is
216
     *                                  "and".
217
     *
218
     * @return $this
219
     */
220 3
    public function whereIn(string $dimension, array $items, Closure $extraction = null, $boolean = 'and')
221
    {
222 3
        $filter = new InFilter($dimension, $items, $this->getExtraction($extraction));
223
224 3
        return $this->where($filter, null, null, null, $boolean);
225
    }
226
227
    /**
228
     * Filter records where the given dimension exists in the given list of items.
229
     *
230
     * If there are previously defined filters, this filter will be joined with an "or".
231
     *
232
     * @param string        $dimension  The dimension which you want to filte
233
     * @param array         $items      A list of values. We will return records where the dimension is in this list.
234
     * @param \Closure|null $extraction An extraction function to extract a different value from the dimension.
235
     *
236
     * @return $this
237
     */
238 1
    public function orWhereIn(string $dimension, array $items, Closure $extraction = null)
239
    {
240 1
        return $this->whereIn($dimension, $items, $extraction, 'or');
241
    }
242
243
    /**
244
     * Filter records where dimensionA is equal to dimensionB.
245
     * You can either supply a string or a Closure. The Closure will receive a DimensionBuilder object, which allows
246
     * you to select a dimension and apply extraction functions if needed.
247
     *
248
     * Example:
249
     * ```php
250
     * $builder->whereColumn('initials', function(DimensionBuilder $dimensionBuilder) {
251
     *   $dimensionBuilder->select('first_name', function(ExtractionBuilder $extractionBuilder) {
252
     *     $extractionBuilder->substring(0, 1);
253
     *   });
254
     * });
255
     * ```
256
     *
257
     * @param string|Closure $dimensionA The dimension which you want to compare, or a Closure which will receive a
258
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
259
     * @param string|Closure $dimensionB The dimension which you want to compare, or a Closure which will receive a
260
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
261
     * @param string         $boolean    This influences how this filter will be joined with previous added filters.
262
     *                                   Should both filters apply ("and") or one or the other ("or") ? Default is
263
     *                                   "and".
264
     *
265
     * @return $this
266
     */
267 1
    public function whereColumn($dimensionA, $dimensionB, string $boolean = 'and')
268
    {
269 1
        $filter = new ColumnComparisonFilter(
270 1
            $this->columnCompareDimension($dimensionA),
271 1
            $this->columnCompareDimension($dimensionB)
272
        );
273
274 1
        return $this->where($filter, null, null, null, $boolean);
275
    }
276
277
    /**
278
     * Filter records where dimensionA is equal to dimensionB.
279
     * You can either supply a string or a Closure. The Closure will receive a DimensionBuilder object, which allows
280
     * you to select a dimension and apply extraction functions if needed.
281
     *
282
     * Example:
283
     * ```php
284
     * $builder->orWhereColumn('initials', function(DimensionBuilder $dimensionBuilder) {
285
     *   $dimensionBuilder->select('first_name', function(ExtractionBuilder $extractionBuilder) {
286
     *     $extractionBuilder->substring(0, 1);
287
     *   });
288
     * });
289
     * ```
290
     *
291
     * @param string|Closure $dimensionA The dimension which you want to compare, or a Closure which will receive a
292
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
293
     * @param string|Closure $dimensionB The dimension which you want to compare, or a Closure which will receive a
294
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
295
     *
296
     * @return $this
297
     */
298 1
    public function orWhereColumn($dimensionA, $dimensionB)
299
    {
300 1
        return $this->whereColumn($dimensionA, $dimensionB, 'or');
301
    }
302
303
304
305
    /**
306
     * Filter records where dimensionA is NOT equal to dimensionB.
307
     * You can either supply a string or a Closure. The Closure will receive a DimensionBuilder object, which allows
308
     * you to select a dimension and apply extraction functions if needed.
309
     *
310
     * Example:
311
     * ```php
312
     * $builder->whereNotColumn('initials', function(DimensionBuilder $dimensionBuilder) {
313
     *   $dimensionBuilder->select('first_name', function(ExtractionBuilder $extractionBuilder) {
314
     *     $extractionBuilder->substring(0, 1);
315
     *   });
316
     * });
317
     * ```
318
     *
319
     * @param string|Closure $dimensionA The dimension which you want to compare, or a Closure which will receive a
320
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
321
     * @param string|Closure $dimensionB The dimension which you want to compare, or a Closure which will receive a
322
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
323
     * @param string         $boolean    This influences how this filter will be joined with previous added filters.
324
     *                                   Should both filters apply ("and") or one or the other ("or") ? Default is
325
     *                                   "and".
326
     *
327
     * @return $this
328
     * @deprecated Use the whereNot() method combined with a whereColumn instead.
329
     */
330 1
    public function whereNotColumn($dimensionA, $dimensionB, string $boolean = 'and')
331
    {
332 1
        $filter = new ColumnComparisonFilter(
333 1
            $this->columnCompareDimension($dimensionA),
334 1
            $this->columnCompareDimension($dimensionB)
335
        );
336
337 1
        return $this->where(new NotFilter($filter), null, null, null, $boolean);
338
    }
339
340
    /**
341
     * Filter records where dimensionA is NOT equal to dimensionB.
342
     * You can either supply a string or a Closure. The Closure will receive a DimensionBuilder object, which allows
343
     * you to select a dimension and apply extraction functions if needed.
344
     *
345
     * Example:
346
     * ```php
347
     * $builder->orWhereNotColumn('initials', function(DimensionBuilder $dimensionBuilder) {
348
     *   $dimensionBuilder->select('first_name', function(ExtractionBuilder $extractionBuilder) {
349
     *     $extractionBuilder->substring(0, 1);
350
     *   });
351
     * });
352
     * ```
353
     *
354
     * @param string|Closure $dimensionA The dimension which you want to compare, or a Closure which will receive a
355
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
356
     * @param string|Closure $dimensionB The dimension which you want to compare, or a Closure which will receive a
357
     *                                   DimensionBuilder which allows you to select a dimension in a more advance way.
358
     *
359
     * @return $this
360
     */
361 1
    public function orWhereNotColumn($dimensionA, $dimensionB)
362
    {
363 1
        return $this->whereNotColumn($dimensionA, $dimensionB, 'or');
0 ignored issues
show
Deprecated Code introduced by
The function Level23\Druid\Concerns\HasFilter::whereNotColumn() has been deprecated: Use the whereNot() method combined with a whereColumn instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

363
        return /** @scrutinizer ignore-deprecated */ $this->whereNotColumn($dimensionA, $dimensionB, 'or');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
364
    }
365
366
    /**
367
     * This filter will select records where the given dimension is greater than or equal to the given minValue, and
368
     * less than or equal to the given $maxValue.
369
     *
370
     * So in SQL syntax, this would be:
371
     * ```
372
     * WHERE dimension => $minValue AND dimension <= $maxValue
373
     * ```
374
     *
375
     * @param string        $dimension   The dimension which you want to filter
376
     * @param string|int    $minValue    The minimum value where the dimension should match. It should be equal or
377
     *                                   greater than this value.
378
     * @param string|int    $maxValue    The maximum value where the dimension should match. It should be less than
379
     *                                   this value.
380
     * @param \Closure|null $extraction  Extraction function to extract a different value from the dimension.
381
     * @param null|string   $ordering    Specifies the sorting order to use when comparing values against the
382
     *                                   between filter. Can be one of the following values: "lexicographic",
383
     *                                   "alphanumeric", "numeric", "strlen", "version". See Sorting Orders for
384
     *                                   more details. By default it will be "numeric" if the values are
385
     *                                   numeric, otherwise it will be "lexicographic"
386
     * @param string        $boolean     This influences how this filter will be joined with previous added filters.
387
     *                                   Should both filters apply ("and") or one or the other ("or") ? Default is
388
     *                                   "and".
389
     *
390
     * @return $this
391
     */
392 1
    public function whereBetween(
393
        string $dimension,
394
        $minValue,
395
        $maxValue,
396
        Closure $extraction = null,
397
        string $ordering = null,
398
        string $boolean = 'and'
399
    ) {
400 1
        $filter = new BetweenFilter($dimension, $minValue, $maxValue, $ordering, $this->getExtraction($extraction));
401
402 1
        return $this->where($filter, null, null, null, $boolean);
403
    }
404
405
    /**
406
     * This filter will select records where the given dimension is greater than or equal to the given minValue, and
407
     * less than or equal to the given $maxValue.
408
     *
409
     * This method will join previous added filters with an "or" instead of an "and".
410
     *
411
     * So in SQL syntax, this would be:
412
     * ```
413
     * WHERE (dimension => $minValue AND dimension <= $maxValue) or .... (other filters here)
414
     * ```
415
     *
416
     * @param string        $dimension   The dimension which you want to filter
417
     * @param string|int    $minValue    The minimum value where the dimension should match. It should be equal or
418
     *                                   greater than this value.
419
     * @param string|int    $maxValue    The maximum value where the dimension should match. It should be less than
420
     *                                   this value.
421
     * @param \Closure|null $extraction  Extraction function to extract a different value from the dimension.
422
     * @param null|string   $ordering    Specifies the sorting order to use when comparing values against the
423
     *                                   between filter. Can be one of the following values: "lexicographic",
424
     *                                   "alphanumeric", "numeric", "strlen", "version". See Sorting Orders for
425
     *                                   more details. By default it will be "numeric" if the values are
426
     *                                   numeric, otherwise it will be "lexicographic"
427
     *
428
     * @return $this
429
     */
430 1
    public function orWhereBetween(
431
        string $dimension,
432
        $minValue,
433
        $maxValue,
434
        Closure $extraction = null,
435
        string $ordering = null
436
    ) {
437 1
        return $this->whereBetween($dimension, $minValue, $maxValue, $extraction, $ordering, 'or');
438
    }
439
440
    /**
441
     * This filter will select records where the given dimension is NOT between the given min and max value.
442
     *
443
     * So in SQL syntax, this would be:
444
     * ```
445
     * WHERE dimension < $minValue AND dimension > $maxValue
446
     * ```
447
     *
448
     * @param string        $dimension   The dimension which you want to filter
449
     * @param string|int    $minValue    The minimum value where the dimension should NOT match. It should be equal or
450
     *                                   greater than this value.
451
     * @param string|int    $maxValue    The maximum value where the dimension should NOT match. It should be less than
452
     *                                   this value.
453
     * @param \Closure|null $extraction  Extraction function to extract a different value from the dimension.
454
     * @param null|string   $ordering    Specifies the sorting order to use when comparing values against the
455
     *                                   between filter. Can be one of the following values: "lexicographic",
456
     *                                   "alphanumeric", "numeric", "strlen", "version". See Sorting Orders for
457
     *                                   more details. By default it will be "numeric" if the values are
458
     *                                   numeric, otherwise it will be "lexicographic"
459
     * @param string        $boolean     This influences how this filter will be joined with previous added filters.
460
     *                                   Should both filters apply ("and") or one or the other ("or") ? Default is
461
     *                                   "and".
462
     *
463
     * @return $this
464
     * @deprecated Use the whereNot() method combined with a whereBetween instead.
465
     */
466 1
    public function whereNotBetween(
467
        string $dimension,
468
        $minValue,
469
        $maxValue,
470
        Closure $extraction = null,
471
        string $ordering = null,
472
        string $boolean = 'and'
473
    ) {
474 1
        $filter = new BetweenFilter($dimension, $minValue, $maxValue, $ordering, $this->getExtraction($extraction));
475
476 1
        return $this->where(new NotFilter($filter), null, null, null, $boolean);
477
    }
478
479
    /**
480
     * This filter will select records where the given dimension is NOT between the given min and max value.
481
     *
482
     * So in SQL syntax, this would be:
483
     * ```
484
     * WHERE (dimension < $minValue AND dimension > $maxValue) or  .... (other filters here)
485
     * ```
486
     *
487
     * @param string        $dimension   The dimension which you want to filter
488
     * @param string|int    $minValue    The minimum value where the dimension should NOT match. It should be equal or
489
     *                                   greater than this value.
490
     * @param string|int    $maxValue    The maximum value where the dimension should NOT match. It should be less than
491
     *                                   this value.
492
     * @param \Closure|null $extraction  Extraction function to extract a different value from the dimension.
493
     * @param null|string   $ordering    Specifies the sorting order to use when comparing values against the
494
     *                                   between filter. Can be one of the following values: "lexicographic",
495
     *                                   "alphanumeric", "numeric", "strlen", "version". See Sorting Orders for
496
     *                                   more details. By default it will be "numeric" if the values are
497
     *                                   numeric, otherwise it will be "lexicographic"
498
     *
499
     * @return $this
500
     * @deprecated Use the whereNot() method combined with a whereBetween instead.
501
     */
502 1
    public function orWhereNotBetween(
503
        string $dimension,
504
        $minValue,
505
        $maxValue,
506
        Closure $extraction = null,
507
        string $ordering = null
508
    ) {
509 1
        return $this->whereNotBetween($dimension, $minValue, $maxValue, $extraction, $ordering, 'or');
0 ignored issues
show
Deprecated Code introduced by
The function Level23\Druid\Concerns\H...lter::whereNotBetween() has been deprecated: Use the whereNot() method combined with a whereBetween instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

509
        return /** @scrutinizer ignore-deprecated */ $this->whereNotBetween($dimension, $minValue, $maxValue, $extraction, $ordering, 'or');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
510
    }
511
512
    /**
513
     * Filter records where the given dimension NOT exists in the given list of items
514
     *
515
     * @param string        $dimension  The dimension which you want to filter
516
     * @param array         $items      A list of values. We will return records where the dimension is NOT in this
517
     *                                  list.
518
     * @param \Closure|null $extraction An extraction function to extract a different value from the dimension.
519
     * @param string        $boolean    This influences how this filter will be joined with previous added filters.
520
     *                                  Should both filters apply ("and") or one or the other ("or") ? Default is
521
     *                                  "and".
522
     *
523
     * @return $this
524
     * @deprecated Use the whereNot() method combined with a whereIn instead.
525
     */
526 1
    public function whereNotIn(string $dimension, array $items, Closure $extraction = null, string $boolean = 'and')
527
    {
528 1
        $filter = new NotFilter(new InFilter($dimension, $items, $this->getExtraction($extraction)));
529
530 1
        return $this->where($filter, null, null, null, $boolean);
531
    }
532
533
    /**
534
     * Filter records where the given dimension NOT exists in the given list of items
535
     *
536
     * @param string        $dimension  The dimension which you want to filter
537
     * @param array         $items      A list of values. We will return records where the dimension is NOT in this
538
     *                                  list.
539
     * @param \Closure|null $extraction An extraction function to extract a different value from the dimension.
540
     *
541
     * @return $this
542
     * @deprecated Use the orWhereNot() method combined with a whereIn instead.
543
     */
544 1
    public function orWhereNotIn(string $dimension, array $items, Closure $extraction = null)
545
    {
546 1
        return $this->whereNotIn($dimension, $items, $extraction, 'or');
0 ignored issues
show
Deprecated Code introduced by
The function Level23\Druid\Concerns\HasFilter::whereNotIn() has been deprecated: Use the whereNot() method combined with a whereIn instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

546
        return /** @scrutinizer ignore-deprecated */ $this->whereNotIn($dimension, $items, $extraction, 'or');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
547
    }
548
549
    /**
550
     * Filter on an dimension where the value does NOT exists in the given intervals array.
551
     *
552
     * The intervals array can contain the following:
553
     * - Only 2 elements, start and stop.
554
     * - an Interval object
555
     * - an raw interval string as used in druid. For example: 2019-04-15T08:00:00.000Z/2019-04-15T09:00:00.000Z
556
     * - an array which each contain 2 elements, a start and stop date. These can be an DateTime object, a unix
557
     * timestamp or anything which can be parsed by DateTime::__construct
558
     *
559
     * So valid are:
560
     * ['now', 'tomorrow']
561
     * [['now', 'now + 1 hour'], ['tomorrow', 'tomorrow + 1 hour']]
562
     * ['2019-04-15T08:00:00.000Z/2019-04-15T09:00:00.000Z']
563
     *
564
     * @param string        $dimension  The dimension which you want to filter
565
     * @param array         $intervals  The interval which you do not want to match. See above for more info.
566
     * @param \Closure|null $extraction Extraction function to extract a different value from the dimension.
567
     * @param string        $boolean    This influences how this filter will be joined with previous added filters.
568
     *                                  Should both filters apply ("and") or one or the other ("or") ? Default is
569
     *                                  "and".
570
     *
571
     * @return $this
572
     * @deprecated Use the whereNot() method combined with a whereInterval instead.
573
     */
574 1
    public function whereNotInterval(
575
        string $dimension,
576
        array $intervals,
577
        Closure $extraction = null,
578
        string $boolean = 'and'
579
    ) {
580 1
        $filter = new IntervalFilter(
581 1
            $dimension,
582 1
            $this->normalizeIntervals($intervals),
583 1
            $this->getExtraction($extraction)
584
        );
585
586 1
        return $this->where(new NotFilter($filter), null, null, null, $boolean);
587
    }
588
589
    /**
590
     * Filter on an dimension where the value does NOT exists in the given intervals array.
591
     *
592
     * The intervals array can contain the following:
593
     * - Only 2 elements, start and stop.
594
     * - an Interval object
595
     * - an raw interval string as used in druid. For example: 2019-04-15T08:00:00.000Z/2019-04-15T09:00:00.000Z
596
     * - an array which each contain 2 elements, a start and stop date. These can be an DateTime object, a unix
597
     * timestamp or anything which can be parsed by DateTime::__construct
598
     *
599
     * So valid are:
600
     * ['now', 'tomorrow']
601
     * [['now', 'now + 1 hour'], ['tomorrow', 'tomorrow + 1 hour']]
602
     * ['2019-04-15T08:00:00.000Z/2019-04-15T09:00:00.000Z']
603
     *
604
     * @param string        $dimension  The dimension which you want to filter
605
     * @param array         $intervals  The interval which you do not want to match. See above for more info.
606
     * @param \Closure|null $extraction Extraction function to extract a different value from the dimension.
607
     *
608
     * @return $this
609
     * @deprecated Use the orWhereNot() method combined with a whereInterval instead.
610
     */
611 1
    public function orWhereNotInterval(string $dimension, array $intervals, Closure $extraction = null)
612
    {
613 1
        return $this->whereNotInterval($dimension, $intervals, $extraction, 'or');
0 ignored issues
show
Deprecated Code introduced by
The function Level23\Druid\Concerns\H...ter::whereNotInterval() has been deprecated: Use the whereNot() method combined with a whereInterval instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

613
        return /** @scrutinizer ignore-deprecated */ $this->whereNotInterval($dimension, $intervals, $extraction, 'or');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
614
    }
615
616
    /**
617
     * Filter on an dimension where the value exists in the given intervals array.
618
     *
619
     * The intervals array can contain the following:
620
     * - an Interval object
621
     * - an raw interval string as used in druid. For example: 2019-04-15T08:00:00.000Z/2019-04-15T09:00:00.000Z
622
     * - an array which contains 2 elements, a start and stop date. These can be an DateTime object, a unix timestamp
623
     *   or anything which can be parsed by DateTime::__construct
624
     *
625
     * @param string        $dimension  The dimension which you want to filter
626
     * @param array         $intervals  The interval which you want to match. See above for more info.
627
     * @param \Closure|null $extraction Extraction function to extract a different value from the dimension.
628
     * @param string        $boolean    This influences how this filter will be joined with previous added filters.
629
     *                                  Should both filters apply ("and") or one or the other ("or") ? Default is
630
     *                                  "and".
631
     *
632
     * @return $this
633
     */
634 1
    public function whereInterval(
635
        string $dimension,
636
        array $intervals,
637
        Closure $extraction = null,
638
        string $boolean = 'and'
639
    ) {
640 1
        $filter = new IntervalFilter(
641 1
            $dimension,
642 1
            $this->normalizeIntervals($intervals),
643 1
            $this->getExtraction($extraction)
644
        );
645
646 1
        return $this->where($filter, null, null, null, $boolean);
647
    }
648
649
    /**
650
     * Filter on an dimension where the value exists in the given intervals array.
651
     *
652
     * The intervals array can contain the following:
653
     * - an Interval object
654
     * - an raw interval string as used in druid. For example: 2019-04-15T08:00:00.000Z/2019-04-15T09:00:00.000Z
655
     * - an array which contains 2 elements, a start and stop date. These can be an DateTime object, a unix timestamp
656
     *   or anything which can be parsed by DateTime::__construct
657
     *
658
     * @param string        $dimension  The dimension which you want to filter
659
     * @param array         $intervals  The interval which you want to match. See above for more info.
660
     * @param \Closure|null $extraction Extraction function to extract a different value from the dimension.
661
     *
662
     * @return $this
663
     */
664 1
    public function orWhereInterval(string $dimension, array $intervals, Closure $extraction = null)
665
    {
666 1
        return $this->whereInterval($dimension, $intervals, $extraction, 'or');
667
    }
668
669
    /**
670
     * Normalize the given dimension to a DimensionInterface object.
671
     *
672
     * @param string|Closure $dimension
673
     *
674
     * @return \Level23\Druid\Dimensions\DimensionInterface
675
     * @throws InvalidArgumentException
676
     */
677 5
    protected function columnCompareDimension($dimension): DimensionInterface
678
    {
679 5
        if ($dimension instanceof Closure) {
680 2
            $builder = new DimensionBuilder();
681 2
            call_user_func($dimension, $builder);
682 2
            $dimensions = $builder->getDimensions();
683
684 2
            if (count($dimensions) != 1) {
685 1
                throw new InvalidArgumentException('Your dimension builder should select 1 dimension');
686
            }
687
688 1
            return $dimensions[0];
689
        }
690
691 3
        return new Dimension($dimension);
692
    }
693
694
    /**
695
     * Normalize the given intervals into Interval objects.
696
     *
697
     * @param array $intervals
698
     *
699
     * @return array
700
     */
701 11
    protected function normalizeIntervals(array $intervals): array
702
    {
703 11
        $first = reset($intervals);
704
705
        // If first is an array or already a druid interval string or object we do not wrap it in an array
706 11
        if (!is_array($first) && !$this->isDruidInterval($first)) {
707 8
            $intervals = [$intervals];
708
        }
709
710
        return array_map(function ($interval) {
711
712 11
            if ($interval instanceof IntervalInterface) {
713 1
                return $interval;
714
            }
715
716
            // If it is a string we explode it into to elements
717 10
            if (is_string($interval)) {
718 1
                $interval = explode('/', $interval);
719
            }
720
721
            // If the value is an array and is not empty and has either one or 2 values its an interval array
722 10
            if (is_array($interval) && !empty(array_filter($interval)) && count($interval) < 3) {
723
                /** @scrutinizer ignore-type */
724 7
                return new Interval(...$interval);
725
            }
726
727 3
            throw new InvalidArgumentException(
728
                'Invalid type given in the interval array. We cannot process ' .
729 3
                var_export($interval, true)
730
            );
731 11
        }, $intervals);
732
    }
733
734
    /**
735
     * Returns true if the argument provided is a druid interval string or interface
736
     *
737
     * @param string|IntervalInterface $interval
738
     *
739
     * @return bool
740
     */
741 10
    protected function isDruidInterval($interval)
742
    {
743 10
        if ($interval instanceof IntervalInterface) {
744 1
            return true;
745
        }
746
747 9
        return is_string($interval) && strpos($interval, '/') !== false;
748
    }
749
750
    /**
751
     * Helper method to add an OR filter
752
     *
753
     * @param FilterInterface $filter
754
     */
755 5
    protected function addOrFilter(FilterInterface $filter): void
756
    {
757 5
        if (!$this->filter instanceof FilterInterface) {
758 5
            $this->filter = $filter;
759
760 5
            return;
761
        }
762
763 5
        if ($this->filter instanceof OrFilter) {
764 1
            $this->filter->addFilter($filter);
765
766 1
            return;
767
        }
768
769 5
        $this->filter = new OrFilter([$this->filter, $filter]);
770 5
    }
771
772
    /**
773
     * Helper method to add an AND filter
774
     *
775
     * @param FilterInterface $filter
776
     */
777 39
    protected function addAndFilter(FilterInterface $filter): void
778
    {
779 39
        if (!$this->filter instanceof FilterInterface) {
780 39
            $this->filter = $filter;
781
782 39
            return;
783
        }
784
785 21
        if ($this->filter instanceof AndFilter) {
786 2
            $this->filter->addFilter($filter);
787
788 2
            return;
789
        }
790
791 21
        $this->filter = new AndFilter([$this->filter, $filter]);
792 21
    }
793
794
    /**
795
     * @return \Level23\Druid\Filters\FilterInterface|null
796
     */
797 30
    public function getFilter(): ?FilterInterface
798
    {
799 30
        return $this->filter;
800
    }
801
802
    /**
803
     * @param \Closure|null $extraction
804
     *
805
     * @return \Level23\Druid\Extractions\ExtractionInterface|null
806
     */
807 39
    private function getExtraction(?Closure $extraction): ?ExtractionInterface
808
    {
809 39
        if (empty($extraction)) {
810 38
            return null;
811
        }
812
813 1
        $builder = new ExtractionBuilder();
814 1
        call_user_func($extraction, $builder);
815
816 1
        return $builder->getExtraction();
817
    }
818
}