Issues (22)

src/Concerns/WithSearchable.php (2 issues)

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|\Zing\QueryBuilder\Filter|array<(string|\Zing\QueryBuilder\Filter)> $searchable
18
     *
19
     * @return $this
20
     */
21 8
    public function searchable($searchable)
22
    {
23 8
        $searchable = \is_array($searchable) ? $searchable : \func_get_args();
24 8
        $search = $this->request->input('search');
25 8
        if ($search === null) {
26 1
            return $this;
27
        }
28
29 7
        if (\is_string($search) && trim($search) === '') {
30 1
            return $this;
31
        }
32
33 6
        $searchable = $this->resolveNestedSearchable($searchable);
34
35 6
        return $this->applySearchable($search, $searchable);
36
    }
37
38
    /**
39
     * @param mixed $search
40
     * @param array<(int|string), (string|array<string>|\Zing\QueryBuilder\Filter)> $searchable
41
     *
42
     * @return $this
43
     */
44 6
    protected function applySearchable($search, array $searchable = [])
45
    {
46 6
        $this->where(
0 ignored issues
show
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 6
            function (Builder $query) use ($search, $searchable): void {
48 6
                collect($searchable)->each(
49 6
                    function ($value, $key) use ($query, $search): void {
50 6
                        if ($value instanceof Filter) {
51 2
                            if ($value->getDefault() !== null) {
52 1
                                throw ParameterException::unsupportedFilterWithDefaultValueForSearch();
53
                            }
54
55 2
                            $query->orWhere(function ($query) use ($value, $search): void {
56 2
                                $value->filter($query, $search);
57
                            });
58
59 2
                            return;
60
                        }
61
62 6
                        if (is_numeric($key)) {
63 5
                            $query->orWhere($value, 'like', sprintf('%%%s%%', $search));
64
65 5
                            return;
66
                        }
67
68 1
                        $this->applyRelationSearchable($query, $key, (array) $value, $search);
69
                    }
70
                );
71
            }
72
        );
73
74 6
        return $this;
75
    }
76
77
    /**
78
     * @param array<string> $fields
79
     * @param mixed $search
80
     */
81 1
    protected function applyRelationSearchable(Builder $query, string $relation, array $fields, $search): Builder
82
    {
83 1
        return $query->orWhereHas(
84
            $relation,
85 1
            function (Builder $query) use ($fields, $search): void {
86 1
                $query->where(
87 1
                    function (Builder $query) use ($fields, $search): void {
88 1
                        foreach ($fields as $field) {
89 1
                            $query->orWhere($field, 'like', sprintf('%%%s%%', $search));
90
                        }
91
                    }
92
                );
93
            }
94
        );
95
    }
96
97
    /**
98
     * @param array<(string|\Zing\QueryBuilder\Filter)> $searchable
99
     *
100
     * @return array<(int|string), (string|array<string>|\Zing\QueryBuilder\Filter)>
101
     */
102 6
    private function resolveNestedSearchable(array $searchable): array
103
    {
104 6
        $results = [];
105 6
        foreach ($searchable as $singleSearchable) {
106 6
            if (! $singleSearchable instanceof Filter && Str::contains($singleSearchable, '.')) {
107 1
                [$relation, $property] = $this->resolveNestedRelation($singleSearchable);
108
109 1
                $results[$relation][] = $property;
110
            } else {
111 5
                $results[] = $singleSearchable;
112
            }
113
        }
114
115 6
        return $results;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $results returns an array which contains values of type Zing\QueryBuilder\Filter which are incompatible with the documented value type string|string[]&Zing\QueryBuilder\Filter.
Loading history...
116
    }
117
}
118