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
Bug
introduced
by
![]() |
|||
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
|
|||
116 | } |
||
117 | } |
||
118 |