Passed
Pull Request — master (#136)
by Zing
05:52
created

WithSearchable::applySearchable()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 1
nop 2
dl 0
loc 25
ccs 17
cts 17
cp 1
crap 3
rs 9.8333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Zing\QueryBuilder\Concerns;
6
7
use Illuminate\Database\Eloquent\Builder;
8
use Illuminate\Support\Str;
9
use Zing\QueryBuilder\Exceptions\ParameterException;
10
use Zing\QueryBuilder\Filter;
11
12
trait WithSearchable
13
{
14
    use NestedRelation;
15
16
    /**
17
     * @param string|Filter|array<string|Filter> $searchable
18
     *
19
     * @return $this
20
     */
21 5
    public function searchable($searchable)
22
    {
23 5
        $searchable = is_array($searchable) ? $searchable : func_get_args();
24 5
        $search = $this->request->input('search');
25 5
        if ($search === null) {
26 1
            return $this;
27
        }
28
29 4
        if (is_string($search) && trim($search) === '') {
30 1
            return $this;
31
        }
32
33 3
        $searchable = $this->resolveNestedSearchable($searchable);
34
35 3
        return $this->applySearchable($search, $searchable);
36
    }
37
38
    /**
39
     * @param mixed $search
40
     * @param array<int|string, string|array<string>|Filter> $searchable
41
     *
42
     * @return $this
43
     */
44 3
    protected function applySearchable($search, array $searchable = [])
45
    {
46 3
        $this->where(
0 ignored issues
show
Bug introduced by
It seems like where() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

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

46
        $this->/** @scrutinizer ignore-call */ 
47
               where(
Loading history...
47 3
            function (Builder $query) use ($search, $searchable): void {
48 3
                collect($searchable)->each(
49 3
                    function ($value, $key) use ($query, $search): void {
50 3
                        if ($value instanceof Filter){
51 1
                            $query->orWhere(function ($query)use ($value,$search){
52 1
                                $value->filter($query, $search);
53 1
                            });
54 1
                            return;
55
                        }
56 3
                        if (is_numeric($key)) {
57 2
                            $query->orWhere($value, 'like', sprintf('%%%s%%', $search));
58
59 2
                            return;
60
                        }
61
62 1
                        $this->applyRelationSearchable($query, $key, (array) $value, $search);
63 3
                    }
64
                );
65 3
            }
66
        );
67
68 3
        return $this;
69
    }
70
71
    /**
72
     * @param array<string> $fields
73
     * @param mixed $search
74
     */
75 1
    protected function applyRelationSearchable(Builder $query, string $relation, array $fields, $search): Builder
76
    {
77 1
        return $query->orWhereHas(
78 1
            $relation,
79 1
            function (Builder $query) use ($fields, $search): void {
80 1
                $query->where(
81 1
                    function (Builder $query) use ($fields, $search): void {
82 1
                        foreach ($fields as $field) {
83 1
                            $query->orWhere($field, 'like', sprintf('%%%s%%', $search));
84
                        }
85 1
                    }
86
                );
87 1
            }
88
        );
89
    }
90
91
    /**
92
     * @param array<string|Filter> $searchable
93
     *
94
     * @return array<int|string, string|array<string>|Filter>
95
     */
96 3
    private function resolveNestedSearchable(array $searchable)
97
    {
98 3
        $results = [];
99 3
        foreach ($searchable as $singleSearchable) {
100 3
            if ($singleSearchable instanceof Filter){
101 1
                if ($singleSearchable->getDefault()!==null){
102
                    throw ParameterException::unsupportedFilterWithDefaultValueForSearch();
103
                }
104 1
                $results[] = $singleSearchable;
105
            }
106 3
            elseif (Str::contains($singleSearchable, '.')) {
107 1
                [$relation, $property] = $this->resolveNestedRelation($singleSearchable);
108
109 1
                $results[$relation][] = $property;
110
            } else {
111 2
                $results[] = $singleSearchable;
112
            }
113
        }
114
115 3
        return $results;
116
    }
117
}
118