RequestCriteria::parserFieldsSearch()   C
last analyzed

Complexity

Conditions 12
Paths 5

Size

Total Lines 46
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 27
dl 0
loc 46
rs 6.9666
c 1
b 0
f 0
cc 12
nc 5
nop 3

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace Salah3id\Domains\Repository\Criteria;
3
4
use Illuminate\Database\Eloquent\Builder;
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Http\Request;
7
use Illuminate\Support\Str;
8
use Salah3id\Domains\Repository\Contracts\CriteriaInterface;
9
use Salah3id\Domains\Repository\Contracts\RepositoryInterface;
10
11
/**
12
 * Class RequestCriteria
13
 * @package Salah3id\Domains\Repository\Criteria
14
 * @author Anderson Andrade <[email protected]>
15
 */
16
class RequestCriteria implements CriteriaInterface
17
{
18
    /**
19
     * @var \Illuminate\Http\Request
20
     */
21
    protected $request;
22
23
    public function __construct(Request $request)
24
    {
25
        $this->request = $request;
26
    }
27
28
29
    /**
30
     * Apply criteria in query repository
31
     *
32
     * @param         Builder|Model     $model
33
     * @param RepositoryInterface $repository
34
     *
35
     * @return mixed
36
     * @throws \Exception
37
     */
38
    public function apply($model, RepositoryInterface $repository)
39
    {
40
        $fieldsSearchable = $repository->getFieldsSearchable();
41
        $search = $this->request->get(config('domains.criteria.params.search', 'search'), null);
42
        $searchFields = $this->request->get(config('domains.criteria.params.searchFields', 'searchFields'), null);
43
        $filter = $this->request->get(config('domains.criteria.params.filter', 'filter'), null);
44
        $orderBy = $this->request->get(config('domains.criteria.params.orderBy', 'orderBy'), null);
45
        $sortedBy = $this->request->get(config('domains.criteria.params.sortedBy', 'sortedBy'), 'asc');
46
        $with = $this->request->get(config('domains.criteria.params.with', 'with'), null);
47
        $withCount = $this->request->get(config('domains.criteria.params.withCount', 'withCount'), null);
48
        $searchJoin = $this->request->get(config('domains.criteria.params.searchJoin', 'searchJoin'), null);
49
        $sortedBy = !empty($sortedBy) ? $sortedBy : 'asc';
50
51
        if ($search && is_array($fieldsSearchable) && count($fieldsSearchable)) {
52
53
            $searchFields = is_array($searchFields) || is_null($searchFields) ? $searchFields : explode(';', $searchFields);
54
            $isFirstField = true;
55
            $searchData = $this->parserSearchData($search);
56
            $fields = $this->parserFieldsSearch($fieldsSearchable, $searchFields, array_keys($searchData));
57
            $search = $this->parserSearchValue($search);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $search is correct as $this->parserSearchValue($search) targeting Salah3id\Domains\Reposit...ia::parserSearchValue() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
58
            $modelForceAndWhere = strtolower($searchJoin) === 'and';
59
60
            $model = $model->where(function ($query) use ($fields, $search, $searchData, $isFirstField, $modelForceAndWhere) {
61
                /** @var Builder $query */
62
63
                foreach ($fields as $field => $condition) {
64
65
                    if (is_numeric($field)) {
66
                        $field = $condition;
67
                        $condition = "=";
68
                    }
69
70
                    $value = null;
71
72
                    $condition = trim(strtolower($condition));
73
74
                    if (isset($searchData[$field])) {
75
                        $value = ($condition == "like" || $condition == "ilike") ? "%{$searchData[$field]}%" : $searchData[$field];
76
                    } else {
77
                        if (!is_null($search) && !in_array($condition,['in','between'])) {
78
                            $value = ($condition == "like" || $condition == "ilike") ? "%{$search}%" : $search;
79
                        }
80
                    }
81
82
                    $relation = null;
83
                    if(stripos($field, '.')) {
84
                        $explode = explode('.', $field);
85
                        $field = array_pop($explode);
86
                        $relation = implode('.', $explode);
87
                    }
88
                    if($condition === 'in'){
89
                        $value = explode(',',$value);
90
                        if( trim($value[0]) === "" || $field == $value[0]){
91
                            $value = null;
92
                        }
93
                    }
94
                    if($condition === 'between'){
95
                        $value = explode(',',$value);
96
                        if(count($value) < 2){
97
                            $value = null;
98
                        }
99
                    }
100
                    $modelTableName = $query->getModel()->getTable();
101
                    if ( $isFirstField || $modelForceAndWhere ) {
102
                        if (!is_null($value)) {
103
                            if(!is_null($relation)) {
104
                                $query->whereHas($relation, function($query) use($field,$condition,$value) {
105
                                    if($condition === 'in'){
106
                                        $query->whereIn($field,$value);
107
                                    }elseif($condition === 'between'){
108
                                        $query->whereBetween($field,$value);
109
                                    }else{
110
                                        $query->where($field,$condition,$value);
111
                                    }
112
                                });
113
                            } else {
114
                                if($condition === 'in'){
115
                                    $query->whereIn($modelTableName.'.'.$field,$value);
116
                                }elseif($condition === 'between'){
117
                                    $query->whereBetween($modelTableName.'.'.$field,$value);
118
                                }else{
119
                                    $query->where($modelTableName.'.'.$field,$condition,$value);
120
                                }
121
                            }
122
                            $isFirstField = false;
123
                        }
124
                    } else {
125
                        if (!is_null($value)) {
126
                            if(!is_null($relation)) {
127
                                $query->orWhereHas($relation, function($query) use($field,$condition,$value) {
128
                                    if($condition === 'in'){
129
                                        $query->whereIn($field,$value);
130
                                    }elseif($condition === 'between'){
131
                                        $query->whereBetween($field, $value);
132
                                    }else{
133
                                        $query->where($field,$condition,$value);
134
                                    }
135
                                });
136
                            } else {
137
                                if($condition === 'in'){
138
                                    $query->orWhereIn($modelTableName.'.'.$field, $value);
139
                                }elseif($condition === 'between'){
140
                                    $query->whereBetween($modelTableName.'.'.$field,$value);
141
                                }else{
142
                                    $query->orWhere($modelTableName.'.'.$field, $condition, $value);
143
                                }
144
                            }
145
                        }
146
                    }
147
                }
148
            });
149
        }
150
151
        if (isset($orderBy) && !empty($orderBy)) {
152
            $orderBySplit = explode(';', $orderBy);
153
            if(count($orderBySplit) > 1) {
154
                $sortedBySplit = explode(';', $sortedBy);
155
                foreach ($orderBySplit as $orderBySplitItemKey => $orderBySplitItem) {
156
                    $sortedBy = isset($sortedBySplit[$orderBySplitItemKey]) ? $sortedBySplit[$orderBySplitItemKey] : $sortedBySplit[0];
157
                    $model = $this->parserFieldsOrderBy($model, $orderBySplitItem, $sortedBy);
158
                }
159
            } else {
160
                $model = $this->parserFieldsOrderBy($model, $orderBySplit[0], $sortedBy);
161
            }
162
        }
163
164
        if (isset($filter) && !empty($filter)) {
165
            if (is_string($filter)) {
166
                $filter = explode(';', $filter);
167
            }
168
169
            $model = $model->select($filter);
170
        }
171
172
        if ($with) {
173
            $with = explode(';', $with);
174
            $model = $model->with($with);
175
        }
176
177
        if ($withCount) {
178
            $withCount = explode(';', $withCount);
179
            $model = $model->withCount($withCount);
180
        }
181
182
        return $model;
183
    }
184
185
    /**
186
     * @param $model
187
     * @param $orderBy
188
     * @param $sortedBy
189
     * @return mixed
190
     */
191
    protected function parserFieldsOrderBy($model, $orderBy, $sortedBy)
192
    {
193
        $split = explode('|', $orderBy);
194
        if(count($split) > 1) {
195
            /*
196
             * ex.
197
             * products|description -> join products on current_table.product_id = products.id order by description
198
             *
199
             * products:custom_id|products.description -> join products on current_table.custom_id = products.id order
200
             * by products.description (in case both tables have same column name)
201
             */
202
            $table = $model->getModel()->getTable();
203
            $sortTable = $split[0];
204
            $sortColumn = $split[1];
205
206
            $split = explode(':', $sortTable);
207
            $localKey = '.id';
208
            if (count($split) > 1) {
209
                $sortTable = $split[0];
210
211
                $commaExp = explode(',', $split[1]);
212
                $keyName = $table.'.'.$split[1];
213
                if (count($commaExp) > 1) {
214
                    $keyName = $table.'.'.$commaExp[0];
215
                    $localKey = '.'.$commaExp[1];
216
                }
217
            } else {
218
                /*
219
                 * If you do not define which column to use as a joining column on current table, it will
220
                 * use a singular of a join table appended with _id
221
                 *
222
                 * ex.
223
                 * products -> product_id
224
                 */
225
                $prefix = Str::singular($sortTable);
226
                $keyName = $table.'.'.$prefix.'_id';
227
            }
228
229
            $model = $model
230
                ->leftJoin($sortTable, $keyName, '=', $sortTable.$localKey)
231
                ->orderBy($sortColumn, $sortedBy)
232
                ->addSelect($table.'.*');
233
        } else {
234
            $model = $model->orderBy($orderBy, $sortedBy);
235
        }
236
        return $model;
237
    }
238
239
    /**
240
     * @param $search
241
     *
242
     * @return array
243
     */
244
    protected function parserSearchData($search)
245
    {
246
        $searchData = [];
247
248
        if (stripos($search, ':')) {
249
            $fields = explode(';', $search);
250
251
            foreach ($fields as $row) {
252
                try {
253
                    list($field, $value) = explode(':', $row);
254
                    $searchData[$field] = $value;
255
                } catch (\Exception $e) {
256
                    //Surround offset error
257
                }
258
            }
259
        }
260
261
        return $searchData;
262
    }
263
264
    /**
265
     * @param $search
266
     *
267
     * @return null
268
     */
269
    protected function parserSearchValue($search)
270
    {
271
272
        if (stripos($search, ';') || stripos($search, ':')) {
273
            $values = explode(';', $search);
274
            foreach ($values as $value) {
275
                $s = explode(':', $value);
276
                if (count($s) == 1) {
277
                    return $s[0];
0 ignored issues
show
Bug Best Practice introduced by
The expression return $s[0] returns the type string which is incompatible with the documented return type null.
Loading history...
278
                }
279
            }
280
281
            return null;
282
        }
283
284
        return $search;
285
    }
286
287
    protected function parserFieldsSearch(array $fields = [], array $searchFields = null, array $dataKeys = null)
288
    {
289
        if (!is_null($searchFields) && count($searchFields)) {
290
            $acceptedConditions = config('domains.criteria.acceptedConditions', [
291
                '=',
292
                'like'
293
            ]);
294
            $originalFields = $fields;
295
            $fields = [];
296
297
            foreach ($searchFields as $index => $field) {
298
                $field_parts = explode(':', $field);
299
                $temporaryIndex = array_search($field_parts[0], $originalFields);
300
301
                if (count($field_parts) == 2) {
302
                    if (in_array($field_parts[1], $acceptedConditions)) {
303
                        unset($originalFields[$temporaryIndex]);
304
                        $field = $field_parts[0];
305
                        $condition = $field_parts[1];
306
                        $originalFields[$field] = $condition;
307
                        $searchFields[$index] = $field;
308
                    }
309
                }
310
            }
311
312
            if (!is_null($dataKeys) && count($dataKeys)) {
313
                $searchFields = array_unique(array_merge($dataKeys, $searchFields));
314
            }
315
316
            foreach ($originalFields as $field => $condition) {
317
                if (is_numeric($field)) {
318
                    $field = $condition;
319
                    $condition = "=";
320
                }
321
                if (in_array($field, $searchFields)) {
322
                    $fields[$field] = $condition;
323
                }
324
            }
325
326
            if (count($fields) == 0) {
327
                throw new \Exception(trans('repository::criteria.fields_not_accepted', ['field' => implode(',', $searchFields)]));
328
            }
329
330
        }
331
332
        return $fields;
333
    }
334
}