QueryHelper::getFilterValue()   A
last analyzed

Complexity

Conditions 3
Paths 4

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
cc 3
eloc 2
c 3
b 0
f 1
nc 4
nop 1
dl 0
loc 4
rs 10
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: alive
5
 * Date: 10/8/17
6
 * Time: 4:04 AM
7
 */
8
9
namespace Alive2212\LaravelQueryHelper;
10
11
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...
12
13
class QueryHelper
14
{
15
    /**
16
     * filter Delimiter
17
     * @var
18
     */
19
    protected $filterDelimiter = '.';
20
21
    protected $orWhereConditionLevel = 1;
22
23
    /**
24
     * @var string
25
     */
26
    protected $queryFilterTitle = 'query_filters';
27
28
    /**
29
     * @param $query
30
     * @param $filters
31
     * @return mixed
32
     */
33
    public function orDeepFilter($query, $filters)
34
    {
35
        $result = $query;
36
        $keys = explode('.', $filters[0]['key']);
37
        if (collect($keys)->count() == 2) {
38
            $result = $result->orWhereHas($keys[0], function ($query) use ($filters, $keys) {
0 ignored issues
show
Unused Code introduced by
The import $keys is not used and could be removed.

This check looks for imports that have been defined, but are not used in the scope.

Loading history...
39
                foreach ($filters as $filter) {
40
                    $keys = explode('.', $filter['key']);
41
                    $query->where($keys[1], $filter['operator'], $filter['value']);
42
                }
43
            });
44
        }
45
        return $result;
46
    }
47
48
    /**
49
     * @param $query
50
     * @param $param
51
     * @return mixed
52
     */
53
    public function orderBy($query, $param)
54
    {
55
        $result = $query;
56
        if ($param->count()) {
57
            return $query->orderBy($param[0], $param[1]);
58
        }
59
        return $result;
60
    }
61
62
    /**
63
     * @param $params
64
     * @param $field
65
     * @return array
66
     */
67
    public function getValueArray($params, $field)
68
    {
69
        $result = [];
70
        foreach ($params as $key => $item) {
71
            array_push($result, $item[$field]);
72
        }
73
        return $result;
74
    }
75
76
    /**
77
     * @param Builder $model
78
     * @param array $filters
79
     * @return Builder
80
     */
81
    public function smartDeepFilter($model, array $filters)
82
    {
83
        $filters = $this->filterAdaptor($filters);
84
        $model = $this->addWhereCondition($model, $filters);
85
        return $model;
86
    }
87
88
    /**
89
     * @param array $filters
90
     * @param int $level
91
     * @param array $adaptedFilters
92
     * @return array
93
     */
94
    public function filterAdaptor(array $filters, $level = 0, $adaptedFilters = []): array
95
    {
96
        foreach ($filters as $filter) {
97
            if (is_array($filter[0])) {
98
                $result = $this->filterAdaptor($filter, $level + 1);
99
            } else {
100
                $result = $this->getHierarchyFilterKey($filter);
101
            }
102
            $key = $level % 2 == $this->orWhereConditionLevel ?
103
                'or_' . $this->queryFilterTitle :
104
                'and_' . $this->queryFilterTitle;
105
            $adaptedFilters = array_merge_recursive($adaptedFilters, [$key => $result]);
106
        }
107
        return $adaptedFilters;
108
    }
109
110
    /**
111
     * @param array $filters
112
     * @return array
113
     */
114
    public function filterWhereConditionAdaptor(array $filters): array
115
    {
116
        $result = [];
117
        foreach ($filters as $filter) {
118
            $result = array_merge_recursive($result, $this->getHierarchyFilterKey($filter));
119
        }
120
        return $result;
121
    }
122
123
    /**
124
     * @param array $filter
125
     * @return array
126
     */
127
    public function getHierarchyFilterKey(array $filter): array
128
    {
129
        $filterKeyParams = $this->getFilterKey($filter);
130
        $firstFilterKey = $filterKeyParams[0];
131
        if (count($filterKeyParams) > 1) {
132
            unset($filterKeyParams[0]);
133
            $filter[0] = implode($this->filterDelimiter, $filterKeyParams);
134
            $result[$firstFilterKey] = $this->getHierarchyFilterKey($filter);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$result was never initialized. Although not strictly required by PHP, it is generally a good practice to add $result = array(); before regardless.
Loading history...
135
        } else {
136
            $firstFilterOperator = $this->getFilterOperator($filter);
137
            $firstFilterValue = $this->getFilterValue($filter);
138
            $result[$this->queryFilterTitle] = [
139
                [
140
                    $firstFilterKey,
141
                    $firstFilterOperator,
142
                    $firstFilterValue == null ? null : $firstFilterValue,
143
                ],
144
            ];
145
        }
146
        return $result;
147
    }
148
149
    /**
150
     * @param Builder $model
151
     * @param array $filters
152
     * @param string $type
153
     * @return Builder
154
     */
155
    public function addCondition(Builder $model, array $filters, string $type = ''): Builder
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

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

155
    public function addCondition(Builder $model, array $filters, /** @scrutinizer ignore-unused */ string $type = ''): Builder

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
156
    {
157
        foreach ($filters as $filterKey => $filterValues) {
158
            $currentFilter = [$filterKey => $filterValues];
159
            $model = $model->Where(function ($query) use ($currentFilter) {
160
                $this->addWhereCondition($query, $currentFilter, $this->orWhereConditionLevel == 0 ? 'and' : 'or');
161
            });
162
        }
163
        return $model;
164
    }
165
166
    /**
167
     * @param Builder $model
168
     * @param array $filters
169
     * @param string $type
170
     * @param int $index
171
     * @return Builder
172
     */
173
    public function addWhereCondition($model, array $filters, $type = 'and', $index = 0)
174
    {
175
        // Get key and value
176
        $firstFilterKey = array_key_first($filters);
177
        if ($firstFilterKey === null) {
178
            return $model;
179
        }
180
        $firstFilterValue = $filters[$firstFilterKey];
181
182
        switch ($firstFilterKey) {
183
            // if final query
184
            case $this->queryFilterTitle:
185
186
                $firstFilterInnerKey = array_key_first($filters[$firstFilterKey]);
187
                if ($firstFilterInnerKey === null) {
188
                    return $model;
189
                }
190
191
                // if not first record and type is or
192
                if ($type == "or" && $index > 0) {
193
                    $model = $model->orWhere([$firstFilterValue[$firstFilterInnerKey]]);
194
                } else {
195
                    $whereCondition = $firstFilterValue[$firstFilterInnerKey];
196
                    if (strtolower($whereCondition[2]) == "null") {
197
                        if (
198
                            strtolower($whereCondition[1]) == "is" ||
199
                            $whereCondition[1] == "="
200
                        ) {
201
                            $model = $model->whereNull($whereCondition[0]);
202
                        } elseif (
203
                            strtolower($whereCondition[1]) == "not" ||
204
                            $whereCondition[1] == "<>" ||
205
                            $whereCondition[1] == "!="
206
                        ) {
207
                            $model = $model->whereNotNull($whereCondition[0]);
208
                        }
209
                    } else {
210
                        if (
211
                            strtolower($whereCondition[1]) == "in"
212
                        ) {
213
                            $model = $model->whereIn(
214
                                $whereCondition[0],
215
                                json_decode($whereCondition[2], true)
216
                            );
217
                        } else {
218
                            $model = $model->where([$whereCondition]);
219
                        }
220
                    }
221
                }
222
223
                // Get Inner key and value
224
                if (count($filters[$firstFilterKey]) === 1) {
225
                    break;
226
                }
227
                unset($filters[$firstFilterKey][$firstFilterInnerKey]);
228
                return $this->addWhereCondition($model, $filters, $type, ++$index);
229
230
            // if and
231
            case 'and_' . $this->queryFilterTitle:
232
                // if not first record and type is or
233
                if ($type == "or" && $index > 0) {
234
                    $model = $model->orWhere(function (Builder $builder) use ($firstFilterValue) {
235
                        $builder = $this->addWhereCondition($builder, $firstFilterValue, 'and', 0);
236
                        return $builder;
237
                    });
238
                } else {
239
                    $model = $model->where(function (Builder $builder) use ($firstFilterValue) {
240
                        $builder = $this->addWhereCondition($builder, $firstFilterValue, 'and', 0);
241
                        return $builder;
242
                    });
243
                }
244
                break;
245
246
            // if or
247
            case 'or_' . $this->queryFilterTitle:
248
                // if not first record and type is or
249
                if ($type == "or" && $index > 0) {
250
                    $model = $model->orWhere(function (Builder $builder) use ($firstFilterValue) {
251
                        $builder = $this->addWhereCondition($builder, $firstFilterValue, 'or', 0);
252
                        return $builder;
253
                    });
254
                } else {
255
                    $model = $model->where(function (Builder $builder) use ($firstFilterValue) {
256
                        $builder = $this->addWhereCondition($builder, $firstFilterValue, 'or', 0);
257
                        return $builder;
258
                    });
259
                }
260
                break;
261
262
            // if relational
263
            default:
264
                // if not first record and type is or
265
                if ($type == "or" && $index > 0) {
266
                    $model = $model->orWhereHas($firstFilterKey, function (Builder $builder) use ($firstFilterValue) {
267
                        $builder = $this->addWhereCondition($builder, $firstFilterValue, 'or', 0);
268
                        return $builder;
269
                    });
270
                } else {
271
                    $model = $model->whereHas($firstFilterKey, function (Builder $builder) use ($firstFilterValue) {
272
                        $builder = $this->addWhereCondition($builder, $firstFilterValue, 'and', 0);
273
                        return $builder;
274
                    });
275
                }
276
                break;
277
        }
278
279
        unset($filters[$firstFilterKey]);
280
        if (count($filters)) {
281
            return $this->addWhereCondition($model, $filters, $type, ++$index);
282
        }
283
        return $model;
284
    }
285
286
    /**
287
     * @return string
288
     */
289
    public function getFilterDelimiter(): string
290
    {
291
        return $this->filterDelimiter;
292
    }
293
294
    /**
295
     * @param $filterDelimiter
296
     * @return $this
297
     */
298
    public function setFilterDelimiter($filterDelimiter): QueryHelper
299
    {
300
        $this->filterDelimiter = $filterDelimiter;
301
        return $this;
302
    }
303
304
    /**
305
     * @param array $filter
306
     * @return array
307
     */
308
    public function getFilterKey(array $filter): array
309
    {
310
        if (array_key_exists('key', $filter)) {
311
            $result = explode($this->filterDelimiter, $filter['key']);
312
        } else {
313
            $result = explode($this->filterDelimiter, $filter[0]);
314
        }
315
        return $result;
316
    }
317
318
    /**
319
     * @param array $filter
320
     * @return string
321
     */
322
    public function getFilterOperator(array $filter): string
323
    {
324
        return array_key_exists('operator', $filter) ? $filter['operator'] : $filter[1];
325
    }
326
327
    /**
328
     * @param array $filter
329
     * @return string
330
     */
331
    public function getFilterValue(array $filter): ?string
332
    {
333
        return (array_key_exists('value', $filter)) ? $filter['value'] :
334
            ($filter[2] == null ? "null" : $filter[2]);
335
    }
336
}
337