Filterable::getFilterable()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Fomvasss\Filterable;
4
5
use Carbon\Carbon;
6
use Illuminate\Database\Eloquent\Builder;
0 ignored issues
show
Bug introduced by
The type Illuminate\Database\Eloquent\Builder 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...
7
8
/**
9
 * Trait Filterable
10
 * @package Fomvasss\Searchable
11
 */
12
trait Filterable
13
{
14
    /**
15
     *
16
     * @param $query
17
     * @param array|null $filterAttributes
18
     * @return mixed
19
     */
20
    public function scopeFilterable($query, array $filterAttributes = null)
21
    {
22
        $filterable = $this->getFilterable();
23
        $attributes = $this->getFilterAttributes($filterAttributes);
24
25
        if (! empty($attributes)) {
26
            $query->where(function ($q) use ($attributes, $filterable) {
27
                foreach ($filterable as $key => $filterType) {
28
                    switch ($filterType) {
29
                        case 'equal':
30
                            if (array_key_exists($key, $attributes) && $attributes[$key] !== null) {
31
                                $this->fWhereEqual($q, $key, $attributes);
32
                            }
33
                            break;
34
                        case 'like':
35
                            if (array_key_exists($key, $attributes) && $attributes[$key] !== null) {
36
                                $q->where($key, 'LIKE', '%' . $attributes[$key] . '%');
37
                            }
38
                            break;
39
                        case 'in':
40
                            if (array_key_exists($key, $attributes) && $attributes[$key] !== null) {
41
                                $this->fWhereIn($q, $key, $attributes);
42
                            }
43
                            break;
44
                        case 'between':
45
                            $fromVal = $attributes[$key . '_from'] ?? null;
46
                            $toVal = $attributes[$key . '_to'] ?? null;
47
                            if ($fromVal != null && $toVal != null) {
48
                                $q->whereBetween($key, [$fromVal, $toVal]);
49
                            } elseif ($fromVal != null && $toVal == null) {
50
                                $q->where($key, '>=', $fromVal);
51
                            } elseif ($fromVal == null && $toVal != null) {
52
                                $q->where($key, '<=', $toVal);
53
                            }
54
                            break;
55
                        case 'equal_date':
56
                            if (array_key_exists($key, $attributes)) {
57
                                try {
58
                                    $date = Carbon::parse($attributes[$key])->toDateString();
59
                                    $q->whereDate($key, $date);
60
                                } catch (\Exception $exception) {
61
                                    \Log::error(__METHOD__ . $exception->getMessage());
62
                                }
63
                            }
64
                            break;
65
                        case 'between_date':
66
                            $fromVal = $attributes[$key . '_from'] ?? null;
67
                            $toVal = $attributes[$key . '_to'] ?? null;
68
69
                            try {
70
                                if ($fromVal != null && $toVal != null) {
71
                                    $dateFrom = Carbon::parse($fromVal);
72
                                    $dateTo = Carbon::parse($toVal)->addDay()->addSecond(-1);
0 ignored issues
show
Unused Code introduced by
The call to Carbon\Carbon::addSecond() has too many arguments starting with -1. ( Ignorable by Annotation )

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

72
                                    $dateTo = Carbon::parse($toVal)->addDay()->/** @scrutinizer ignore-call */ addSecond(-1);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
73
                                    $q->whereBetween($key, [$dateFrom, $dateTo]);
74
                                } elseif ($fromVal != null && $toVal == null) {
75
                                    $dateFrom = Carbon::parse($fromVal);
76
                                    $q->where($key, '>=', $dateFrom);
77
                                } elseif ($fromVal == null && $toVal != null) {
78
                                    $dateTo = Carbon::parse($toVal)->addDay()->addSecond(-1);
79
                                    $q->where($key, '<=', $dateTo);
80
                                }
81
                            } catch (\Exception $exception) {
82
                                \Log::error(__METHOD__ . $exception->getMessage());
83
                            }
84
                            break;
85
                        case 'custom':
86
                            $method = 'scopeCustomFilterable';
87
                            if (array_key_exists($key, $attributes) && method_exists(self::class, $method)) {
88
                                $this->{$method}($q, $key, $attributes[$key]);
89
                            }
90
                            break;
91
                    }
92
                }
93
            });
94
        }
95
96
        return $query;
97
    }
98
99
    protected function customFilterable($q)
100
    {
101
        //...
102
    }
103
104
    protected function getFilterable(): array
105
    {
106
        return $this->filterable ?? [];
107
    }
108
109
    protected function getFilterAttributes(array $attributes = null)
110
    {
111
        $requestKeyName = config('filterable.input_keys.filter', 'filter');
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

111
        $requestKeyName = /** @scrutinizer ignore-call */ config('filterable.input_keys.filter', 'filter');
Loading history...
112
113
        if (! empty($attributes)) {
114
            return $attributes;
115
        } elseif ($requestKeyName && request($requestKeyName) && is_array(request($requestKeyName))) {
0 ignored issues
show
Bug introduced by
The function request was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

115
        } elseif ($requestKeyName && /** @scrutinizer ignore-call */ request($requestKeyName) && is_array(request($requestKeyName))) {
Loading history...
116
            return request($requestKeyName);
117
        }
118
119
        return [];
120
    }
121
122
    /**
123
     * https://site.test/post?filter[status]=post_published
124
     * @param $q
125
     * @param $key
126
     * @param array $attributes
127
     * @return mixed
128
     */
129
    protected function fWhereEqual($q, $key, array $attributes)
130
    {
131
        $value = $attributes[$key];
132
133
        if (preg_match('/\./', $key)) {
134
            $has = preg_replace("/\.\w+$/", '', $key);
135
            $key = preg_replace("/\w+\./", '', $key);
136
137
            $q->whereHas($has, function ($qq) use ($key, $value) {
138
                $qq->where($key, $value);
139
            });
140
        } else {
141
            $q->where($key, $value);
142
        }
143
144
        return $q;
145
    }
146
147
    /**
148
     * https://site.test/post?filter[status][]=post_moderation&filter[status][]=post_published
149
     * or if set $filterSeparator
150
     * https://site.test/post?filter[status]=post_moderation|post_published
151
     * or
152
     * https://site.test/post?filter[status]=post_moderation
153
     * @param $q
154
     * @param $key
155
     * @param array $attributes
156
     * @return mixed
157
     */
158
    protected function fWhereIn($q, $key, array $attributes)
159
    {
160
        //$value = is_array($attributes[$key]) ? $attributes[$key] : [$attributes[$key]];
161
162
        if (is_array($attributes[$key])) {
163
            $value = $attributes[$key];
164
        } elseif ($filterSeparator = '|') {
165
            $value = explode($filterSeparator, $attributes[$key]);
166
        } else {
167
            $value = [$attributes[$key]];
168
        }
169
170
        if (preg_match('/\./', $key)) {
171
            $has = preg_replace("/\.\w+$/", '', $key);
172
            $key = preg_replace("/\w+\./", '', $key);
173
174
            $q->whereHas($has, function ($qq) use ($key, $value) {
175
                $qq->whereIn($key, $value);
176
            });
177
        } else {
178
            $q->whereIn($key, $value);
179
        }
180
181
        return $q;
182
    }
183
184
    /**
185
     * https://site.test/post?q=запрос
186
     *
187
     * @param \Illuminate\Database\Eloquent\Builder $query
188
     * @param string|null $search
189
     */
190
    public function scopeSearchable(Builder $query, string $search = null)
191
    {
192
        $search = $this->getSearchStr($search);
193
194
        $query->when($search !== null, function () use ($query, $search) {
195
            $query->where(function ($query2) use ($search) {
196
                foreach ($this->getSearchable() as $key) {
197
                    if (preg_match('/\./', $key)) {
198
                        $has = preg_replace("/\.\w+$/", '', $key);
199
                        $key = preg_replace("/\w+\./", '', $key);
200
                        $query2->orWhereHas($has, function ($qq) use ($key, $search) {
201
                            $qq->where($key, 'LIKE', "%$search%");
202
                        });
203
                    } else {
204
                        $query2->orWhere($key, 'LIKE', "%$search%");
205
                    }
206
                }
207
            });
208
        });
209
    }
210
211
    /**
212
     * @return array
213
     */
214
    public function getSearchable(): array
215
    {
216
        return $this->searchable ?? [];
217
    }
218
219
    /**
220
     * @param string|null $search
221
     * @return array|\Illuminate\Http\Request|null|string
0 ignored issues
show
Bug introduced by
The type Illuminate\Http\Request 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...
222
     */
223
    protected function getSearchStr(string $search = null)
224
    {
225
        $requestKeyName = config('filterable.input_keys.search', 'q');
0 ignored issues
show
Bug introduced by
The function config was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

225
        $requestKeyName = /** @scrutinizer ignore-call */ config('filterable.input_keys.search', 'q');
Loading history...
226
227
        if ($search !== null) {
228
            return $search;
229
        } elseif ($requestKeyName && request($requestKeyName) && is_string(request($requestKeyName))) {
0 ignored issues
show
Bug introduced by
The function request was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

229
        } elseif ($requestKeyName && /** @scrutinizer ignore-call */ request($requestKeyName) && is_string(request($requestKeyName))) {
Loading history...
230
            return request($requestKeyName);
231
        }
232
233
        return null;
234
    }
235
236
    /**
237
     * @return bool
238
     */
239
    public static function isFilterable(): bool
240
    {
241
        return (new self())->getFilterable() ? true : false;
242
    }
243
244
    /**
245
     * @return bool
246
     */
247
    public static function isSearchable(): bool
248
    {
249
        return (new self())->getSearchable() ? true : false;
250
    }
251
}