Passed
Push — master ( 1f1fa0...e21a18 )
by Stephen
01:05 queued 16s
created

ApplyFilter::getAttributeFilter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Sfneal\Queries\Traits;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Sfneal\Filters\Filter;
7
8
trait ApplyFilter
9
{
10
    // todo: improve return type hinting
11
12
    /**
13
     * Retrieve an array of model attribute keys & corresponding Filter class values.
14
     *
15
     * @return array
16
     */
17
    abstract protected function queryFilters(): array;
18
19
    /**
20
     * Apply a filter to a Query if the Filter class is valid.
21
     *
22
     * @param Builder $query
23
     * @param string $filterName
24
     * @param mixed $filterValue
25
     * @param Filter $decorator
26
     * @return Builder
27
     */
28
    public function applyFilterToQuery(Builder $query, string $filterName, $filterValue = null, $decorator = null)
29
    {
30
        // Get the Filter class if none is provided
31
        $decorator = $decorator ?? self::getFilterClass($filterName);
0 ignored issues
show
Bug Best Practice introduced by
The method Sfneal\Queries\Traits\Ap...ilter::getFilterClass() is not static, but was called statically. ( Ignorable by Annotation )

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

31
        $decorator = $decorator ?? self::/** @scrutinizer ignore-call */ getFilterClass($filterName);
Loading history...
32
33
        // Apply Filter class if it exists and is a filterable attribute
34
        if (! is_null($decorator) && self::isValidFilterClass($decorator, $filterName)) {
0 ignored issues
show
Bug Best Practice introduced by
The method Sfneal\Queries\Traits\Ap...r::isValidFilterClass() is not static, but was called statically. ( Ignorable by Annotation )

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

34
        if (! is_null($decorator) && self::/** @scrutinizer ignore-call */ isValidFilterClass($decorator, $filterName)) {
Loading history...
35
            $query = (new $decorator)->apply($query, $filterValue);
36
        }
37
38
        return $query;
39
    }
40
41
    /**
42
     * Determine if the Filter decorator class exists and is valid.
43
     *
44
     * Check that the Filter class exists or the $decorator is an object.
45
     * Then check that the attribute is declared as filterable.
46
     *
47
     * @param string|mixed $decorator
48
     * @param string $attribute
49
     * @return bool
50
     */
51
    private function isValidFilterClass($decorator, string $attribute): bool
52
    {
53
        return (class_exists($decorator) || is_object($decorator)) && $this->isFilterableAttribute($attribute);
54
    }
55
56
    /**
57
     * Create a filter decorator by manipulating filter name to find the corresponding filter class.
58
     *
59
     * @param $name
60
     * @return null|string|Filter
61
     */
62
    private function getFilterClass($name)
63
    {
64
        // Check if an array of attribute keys and Filter class values is defined
65
        if (self::isValidFiltersArray($this->queryFilters()) && $this->isFilterableAttribute($name)) {
66
            return $this->getAttributeFilter($name);
67
        }
68
    }
69
70
    /**
71
     * Check if the filters array is valid for querying.
72
     *
73
     * @param $filters
74
     * @return bool
75
     */
76
    private static function isValidFiltersArray($filters)
77
    {
78
        return ! empty($filters) && is_array($filters);
79
    }
80
81
    /**
82
     * Determine if a particular filter is in the array of filterable attributes.
83
     *
84
     * @param string $name
85
     * @return bool
86
     */
87
    private function isFilterableAttribute(string $name)
88
    {
89
        if (method_exists($this, 'queryFilters')) {
90
            return in_array($name, array_keys($this->queryFilters()));
91
        } else {
92
            return true;
93
        }
94
    }
95
96
    /**
97
     * Retrieve a Filter that corresponds to an attribute.
98
     *
99
     * @param string $name
100
     * @return string
101
     */
102
    private function getAttributeFilter(string $name): string
103
    {
104
        return $this->queryFilters()[$name];
105
    }
106
}
107