Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

CrudFilter::label()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Backpack\CRUD\app\Library\CrudPanel;
4
5
use Backpack\CRUD\app\Exceptions\BackpackProRequiredException;
6
use Backpack\CRUD\ViewNamespaces;
7
use Closure;
8
use Illuminate\Support\Str;
9
use Illuminate\Support\Traits\Conditionable;
10
use Symfony\Component\HttpFoundation\ParameterBag;
11
12
class CrudFilter
13
{
14
    use Conditionable;
15
16
    public $name; // the name of the filtered variable (db column name)
17
18
    public $type = 'select2'; // the name of the filter view that will be loaded
19
20
    public $key; //camelCased version of filter name to use in internal ids, js functions and css classes.
21
22
    public $label;
23
24
    public $placeholder;
25
26
    public $values;
27
28
    public $options;
29
30
    public $logic;
31
32
    public $fallbackLogic;
33
34
    public $currentValue;
35
36
    public $view;
37
38
    public $viewNamespace = 'crud::filters';
39
40
    public $applied = false;
41
42
    public function __construct($options, $values, $logic, $fallbackLogic)
43
    {
44
        if (! backpack_pro()) {
45
            throw new BackpackProRequiredException('Filter');
46
        }
47
        // if filter exists
48
        if ($this->crud()->hasFilterWhere('name', $options['name'])) {
49
            $properties = get_object_vars($this->crud()->firstFilterWhere('name', $options['name']));
50
            foreach ($properties as $property => $value) {
51
                $this->{$property} = $value;
52
            }
53
        } else {
54
            // it means we're creating the filter now,
55
            $this->name = $options['name'];
56
            $this->key = Str::camel($options['name']);
57
            $this->type = $options['type'] ?? $this->type;
58
            $this->label = $options['label'] ?? $this->crud()->makeLabel($this->name);
59
            $this->viewNamespace = $options['viewNamespace'] ?? $options['view_namespace'] ?? $this->viewNamespace;
60
            $this->view = $this->type;
61
            $this->placeholder = $options['placeholder'] ?? '';
62
63
            $this->values = is_callable($values) ? $values() : $values;
64
            $this->options = $options;
65
            $this->logic = $logic;
66
            $this->fallbackLogic = $fallbackLogic;
67
        }
68
69
        if ($this->crud()->getRequest()->has($this->name)) {
70
            $this->currentValue = $this->crud()->getRequest()->input($this->name);
71
        }
72
    }
73
74
    /**
75
     * Check if the field is currently active. This happens when there's a GET parameter
76
     * in the current request with the same name as the name of the field.
77
     *
78
     * @return bool
79
     */
80
    public function isActive()
81
    {
82
        if ($this->crud()->getRequest()->has($this->name)) {
83
            return true;
84
        }
85
86
        return false;
87
    }
88
89
    /**
90
     * Check if the filter has already had the apply method called on it.
91
     *
92
     * @return bool
93
     */
94
    public function wasApplied()
95
    {
96
        return $this->applied;
97
    }
98
99
    /**
100
     * Check if the filter has not had the apply method called on it yet.
101
     * This is the inverse of the wasApplied() method.
102
     *
103
     * @return bool
104
     */
105
    public function wasNotApplied()
106
    {
107
        return ! $this->applied;
108
    }
109
110
    /**
111
     * Run the filter logic, default logic and/or fallback logic so that from this point on
112
     * the CRUD query has its results filtered, according to the Request.
113
     *
114
     * @param  array  $input  The GET parameters for which the filter should be applied.
115
     * @return void
116
     */
117
    public function apply($input = null)
118
    {
119
        // mark the field as already applied
120
        $this->applied(true);
121
122
        if (is_array($input)) {
123
            $input = new ParameterBag($input);
124
        }
125
126
        $input = $input ?? new ParameterBag($this->crud()->getRequest()->all());
127
128
        if (! $input->has($this->name)) {
129
            // if fallback logic was supplied and is a closure
130
            if (is_callable($this->fallbackLogic)) {
131
                return ($this->fallbackLogic)();
132
            }
133
134
            return;
135
        }
136
137
        // if a closure was passed as "filterLogic"
138
        if (is_callable($this->logic)) {
139
            return ($this->logic)($input->get($this->name));
140
        } else {
141
            return $this->applyDefaultLogic($this->name, false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $operator of Backpack\CRUD\app\Librar...er::applyDefaultLogic(). ( Ignorable by Annotation )

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

141
            return $this->applyDefaultLogic($this->name, /** @scrutinizer ignore-type */ false);
Loading history...
Bug introduced by
Are you sure the usage of $this->applyDefaultLogic($this->name, false) targeting Backpack\CRUD\app\Librar...er::applyDefaultLogic() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
142
        }
143
    }
144
145
    /**
146
     * Get the full path of the filter view, including the view namespace.
147
     *
148
     * @return string
149
     */
150
    public function getViewWithNamespace()
151
    {
152
        return $this->viewNamespace.'.'.$this->view;
153
    }
154
155
    /**
156
     * Get an array of full paths to the filter view, including fallbacks
157
     * as configured in the backpack/config/crud.php file.
158
     *
159
     * @return array
160
     */
161
    public function getNamespacedViewWithFallbacks()
162
    {
163
        $type = $this->type;
164
        $namespaces = ViewNamespaces::getFor('filters');
165
166
        if ($this->viewNamespace != 'crud::filters') {
167
            $namespaces = array_merge([$this->viewNamespace], $namespaces);
168
        }
169
170
        return array_map(function ($item) use ($type) {
171
            return $item.'.'.$type;
172
        }, $namespaces);
173
    }
174
175
    // ---------------------
176
    // FLUENT SYNTAX METHODS
177
    // ---------------------
178
179
    /**
180
     * Create a CrudFilter object with the parameter as its name.
181
     *
182
     * @param  string  $name  Name of the column in the db, or model attribute.
183
     * @return CrudPanel
184
     */
185
    public static function name($name)
186
    {
187
        $filter = new static(compact('name'), null, null, null);
188
189
        return $filter->save();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $filter->save() returns the type Backpack\CRUD\app\Library\CrudPanel\CrudFilter which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudPanel.
Loading history...
190
    }
191
192
    /**
193
     * Remove the current filter from the current operation.
194
     *
195
     * @return void
196
     */
197
    public function remove()
198
    {
199
        $this->crud()->removeFilter($this->name);
200
    }
201
202
    /**
203
     * Remove an attribute from the current filter definition array.
204
     *
205
     * @param  string  $attribute  Name of the attribute being removed.
206
     * @return CrudFilter
207
     */
208
    public function forget($attribute)
209
    {
210
        if (property_exists($this, $attribute)) {
211
            $this->{$attribute} = false;
212
        }
213
214
        if (isset($this->options[$attribute])) {
215
            unset($this->options[$attribute]);
216
        }
217
218
        $this->crud()->replaceFilter($this->name, $this);
219
220
        return $this;
221
    }
222
223
    /**
224
     * Remove an attribute from one field's definition array.
225
     * (unused function).
226
     *
227
     * @param  string  $field  The name of the field.
228
     * @param  string  $attribute  The name of the attribute being removed.
229
     *
230
     * @codeCoverageIgnore
231
     *
232
     * @deprecated
233
     */
234
    public function removeFilterAttribute($filter, $attribute)
0 ignored issues
show
Unused Code introduced by
The parameter $filter is not used and could be removed. ( Ignorable by Annotation )

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

234
    public function removeFilterAttribute(/** @scrutinizer ignore-unused */ $filter, $attribute)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
235
    {
236
        $fields = $this->fields();
0 ignored issues
show
Bug introduced by
The method fields() does not exist on Backpack\CRUD\app\Library\CrudPanel\CrudFilter. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

236
        /** @scrutinizer ignore-call */ 
237
        $fields = $this->fields();
Loading history...
237
238
        unset($fields[$field][$attribute]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $field does not exist. Did you maybe mean $fields?
Loading history...
239
240
        $this->setOperationSetting('fields', $fields);
0 ignored issues
show
Bug introduced by
The method setOperationSetting() does not exist on Backpack\CRUD\app\Library\CrudPanel\CrudFilter. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

240
        $this->/** @scrutinizer ignore-call */ 
241
               setOperationSetting('fields', $fields);
Loading history...
241
    }
242
243
    /**
244
     * Move the current filter after another filter.
245
     *
246
     * @param  string  $destination  Name of the destination filter.
247
     * @return CrudFilter
248
     */
249
    public function after($destination)
250
    {
251
        $this->crud()->moveFilter($this->name, 'after', $destination);
252
253
        return $this;
254
    }
255
256
    /**
257
     * Move the current field before another field.
258
     *
259
     * @param  string  $destination  Name of the destination field.
260
     * @return CrudFilter
261
     */
262
    public function before($destination)
263
    {
264
        $this->crud()->moveFilter($this->name, 'before', $destination);
265
266
        return $this;
267
    }
268
269
    /**
270
     * Make the current field the first one in the fields list.
271
     *
272
     * @return CrudPanel
273
     */
274
    public function makeFirst()
275
    {
276
        $this->crud()->moveFilter($this->name, 'before', $this->crud()->filters()->first()->name);
277
278
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Backpack\CRUD\app\Library\CrudPanel\CrudFilter which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudPanel.
Loading history...
279
    }
280
281
    /**
282
     * Make the current field the last one in the fields list.
283
     *
284
     * @return CrudPanel
285
     */
286
    public function makeLast()
287
    {
288
        $this->crud()->removeFilter($this->name);
289
        $this->crud()->addCrudFilter($this);
290
291
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Backpack\CRUD\app\Library\CrudPanel\CrudFilter which is incompatible with the documented return type Backpack\CRUD\app\Library\CrudPanel\CrudPanel.
Loading history...
292
    }
293
294
    // -----------------------
295
    // FILTER-SPECIFIC SETTERS
296
    // -----------------------
297
298
    /**
299
     * Set the type of the filter.
300
     *
301
     * @param  string  $value  Name of blade view that shows the field.
302
     * @return CrudFilter
303
     */
304
    public function type($value)
305
    {
306
        $this->type = $value;
307
        $this->view = $value;
308
309
        return $this->save();
310
    }
311
312
    /**
313
     * Set the label of the filter - the element that the end-user can see and click
314
     * to activate the filter or an input that will activate the filter.
315
     *
316
     * @param  string  $value  A name for this filter that the end-user will understand.
317
     * @return CrudFilter
318
     */
319
    public function label($value)
320
    {
321
        $this->label = $value;
322
323
        return $this->save();
324
    }
325
326
    /**
327
     * Set the values for the current filter, for the filters who need values.
328
     * For example, the dropdown, select2 and select2 filters let the user select
329
     * pre-determined values to filter with. This is how to set those values that will be picked up.
330
     *
331
     * @param  array|string|function  $value  Key-value array with values for the user to pick from, or a function which also return a Key-value array.
0 ignored issues
show
Bug introduced by
The type Backpack\CRUD\app\Library\CrudPanel\function was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
332
     * @return CrudFilter
333
     */
334
    public function values($value)
335
    {
336
        $this->values = (! is_string($value) && is_callable($value)) ? $value() : $value;
337
338
        return $this->save();
339
    }
340
341
    /**
342
     * Set the values for the current filter, for the filters who need values. For example
343
     * the dropdown, select2 and select2 filters let the user select pre-determined
344
     * values to filter with.
345
     *
346
     * Alias of the values() method.
347
     *
348
     * @param  array|string|function  $value  Key-value array with values for the user to pick from, or a function which also return a Key-value array.
349
     * @return CrudFilter
350
     */
351
    public function options($value)
352
    {
353
        return $this->values($value);
354
    }
355
356
    /**
357
     * Set the blade view that will be used by the filter.
358
     * Should NOT include the namespace, that's defined separately using 'viewNamespace'.
359
     *
360
     * @param  string  $value  Path to the blade file, after the view namespace.
361
     * @return CrudFilter
362
     */
363
    public function view($value)
364
    {
365
        $this->view = $value;
366
        $this->options['view'] = $value;
367
368
        return $this->save();
369
    }
370
371
    /**
372
     * The path to the blade views directory where the filter file will be found. Ex: 'crud::filters'
373
     * Useful to load filters from a different package or directory.
374
     *
375
     * @param  string  $value  Blade path to the directory.
376
     * @return CrudFilter
377
     */
378
    public function viewNamespace($value)
379
    {
380
        $this->viewNamespace = $value;
381
382
        return $this->save();
383
    }
384
385
    /**
386
     * Define what happens when the filter is active, through a closure.
387
     *
388
     * @param  Closure  $value  Closure that will be called when Request has this name as GET parameter.
389
     * @return CrudFilter
390
     */
391
    public function logic($value)
392
    {
393
        $this->logic = $value;
394
395
        return $this->save();
396
    }
397
398
    /**
399
     * Define what happens when the filter is NOT active, through a closure.
400
     *
401
     * @param  Closure  $value  Closure that will be called when Request does NOT have this name as GET parameter.
402
     * @return CrudFilter
403
     */
404
    public function fallbackLogic($value)
405
    {
406
        $this->fallbackLogic = $value;
407
408
        return $this->save();
409
    }
410
411
    /**
412
     * Define if the filter has already been applied (logic or fallbackLogic called).
413
     *
414
     * @param  bool  $value  Whether the filter has been run.
415
     * @return CrudFilter
416
     */
417
    public function applied($value)
418
    {
419
        $this->applied = $value;
420
421
        return $this->save();
422
    }
423
424
    /**
425
     * Aliases of the logic() method.
426
     */
427
    public function whenActive($value)
428
    {
429
        return $this->logic($value);
430
    }
431
432
    public function ifActive($value)
433
    {
434
        return $this->logic($value);
435
    }
436
437
    /**
438
     * Alises of the fallbackLogic() method.
439
     */
440
    public function whenInactive($value)
441
    {
442
        return $this->fallbackLogic($value);
443
    }
444
445
    public function whenNotActive($value)
446
    {
447
        return $this->fallbackLogic($value);
448
    }
449
450
    public function ifInactive($value)
451
    {
452
        return $this->fallbackLogic($value);
453
    }
454
455
    public function ifNotActive($value)
456
    {
457
        return $this->fallbackLogic($value);
458
    }
459
460
    public function else($value)
461
    {
462
        return $this->fallbackLogic($value);
463
    }
464
465
    // ---------------
466
    // PRIVATE METHODS
467
    // ---------------
468
469
    private function crud()
470
    {
471
        return app()->make('crud');
472
    }
473
474
    /**
475
     * Set the value for a certain attribute on the CrudFilter object.
476
     *
477
     * @param  string  $attribute  Name of the attribute.
478
     * @param  string  $value  Value of that attribute.
479
     */
480
    private function setOptionValue($attribute, $value)
481
    {
482
        $this->options[$attribute] = $value;
483
    }
484
485
    /**
486
     * Replace all field options on the CrudFilter object
487
     * with the given array of attribute-value pairs.
488
     *
489
     * @param  array  $array  Array of options and their values.
490
     */
491
    private function setAllOptionsValues($array)
0 ignored issues
show
Unused Code introduced by
The method setAllOptionsValues() is not used, and could be removed.

This check looks for private methods that have been defined, but are not used inside the class.

Loading history...
492
    {
493
        $this->options = $array;
494
    }
495
496
    /**
497
     * Update the global CrudPanel object with the current field options.
498
     *
499
     * @return CrudFilter
500
     */
501
    private function save()
502
    {
503
        $key = $this->name;
504
505
        if ($this->crud()->hasFilterWhere('name', $key)) {
506
            $this->crud()->modifyFilter($key, (array) $this);
507
        } else {
508
            $this->crud()->addCrudFilter($this);
509
        }
510
511
        return $this;
512
    }
513
514
    /**
515
     * @param  string  $name
516
     * @param  string  $operator
517
     * @param  array  $input
518
     */
519
    private function applyDefaultLogic($name, $operator, $input = null)
520
    {
521
        $input = $input ?? $this->crud()->getRequest()->all();
522
523
        // if this filter is active (the URL has it as a GET parameter)
524
        switch ($operator) {
525
            // if no operator was passed, just use the equals operator
526
            case false:
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $operator of type string to the boolean false. If you are specifically checking for an empty string, consider using the more explicit === '' instead.
Loading history...
527
                $this->crud()->addClause('where', $name, $input[$name]);
528
                break;
529
530
            case 'scope':
531
                $this->crud()->addClause($operator);
532
                break;
533
534
                // TODO:
535
                // whereBetween
536
                // whereNotBetween
537
                // whereIn
538
                // whereNotIn
539
                // whereNull
540
                // whereNotNull
541
                // whereDate
542
                // whereMonth
543
                // whereDay
544
                // whereYear
545
                // whereColumn
546
                // like
547
548
                // sql comparison operators
549
            case '=':
550
            case '<=>':
551
            case '<>':
552
            case '!=':
553
            case '>':
554
            case '>=':
555
            case '<':
556
            case '<=':
557
                $this->crud()->addClause('where', $name, $operator, $input[$name]);
558
                break;
559
560
            default:
561
                abort(500, 'Unknown filter operator.', ['developer-error-exception']);
562
                break;
563
        }
564
    }
565
566
    // -----------------
567
    // DEBUGGING METHODS
568
    // -----------------
569
570
    /**
571
     * Dump the current object to the screen,
572
     * so that the developer can see its contents.
573
     *
574
     * @codeCoverageIgnore
575
     *
576
     * @return CrudFilter
577
     */
578
    public function dump()
579
    {
580
        dump($this);
581
582
        return $this;
583
    }
584
585
    /**
586
     * Dump and die. Dumps the current object to the screen,
587
     * so that the developer can see its contents, then stops
588
     * the execution.
589
     *
590
     * @codeCoverageIgnore
591
     *
592
     * @return CrudFilter
593
     */
594
    public function dd()
595
    {
596
        dd($this);
597
598
        return $this;
599
    }
600
601
    // -------------
602
    // MAGIC METHODS
603
    // -------------
604
605
    /**
606
     * If a developer calls a method that doesn't exist, assume they want:
607
     * - $this->options['whatever'] to be set to that value;
608
     * - that filter be updated inside the global CrudPanel object;.
609
     *
610
     * Eg: type('number') will set the "type" attribute to "number"
611
     *
612
     * @param  string  $method  The method being called that doesn't exist.
613
     * @param  array  $parameters  The arguments when that method was called.
614
     * @return CrudFilter
615
     */
616
    public function __call($method, $parameters)
617
    {
618
        $this->setOptionValue($method, $parameters[0]);
619
620
        return $this->save();
621
    }
622
}
623