Passed
Push — master ( d63a45...8016ac )
by Iman
09:10
created

ExecuteApi   F

Complexity

Total Complexity 60

Size/Duplication

Total Lines 375
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 375
rs 3.6
c 0
b 0
f 0
wmc 60

15 Methods

Rating   Name   Duplication   Size   Complexity  
A fetchDataFromDB() 0 14 2
A validateParams() 0 30 5
A joinRelatedTables() 0 16 4
A handleDeleteAction() 0 12 4
A __construct() 0 3 1
B execute() 0 43 7
A applyLike() 0 9 3
B params() 0 21 7
A filterRedundantResp() 0 11 3
A responses() 0 30 5
B filterRows() 0 23 8
A applyWhere() 0 6 2
A doValidation() 0 11 2
A handleAddEdit() 0 8 4
A prepareResponses() 0 10 3

How to fix   Complexity   

Complex Class

Complex classes like ExecuteApi often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ExecuteApi, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Crocodicstudio\Crudbooster\Controllers\ApiController;
4
5
use Crocodicstudio\Crudbooster\Helpers\DbInspector;
6
use Illuminate\Support\Facades\DB;
7
use Illuminate\Support\Facades\Schema;
8
use Illuminate\Support\Facades\Validator;
9
10
class ExecuteApi
11
{
12
    private $ctrl;
13
14
    /**
15
     * ExecuteApi constructor.
16
     *
17
     * @param $ctrl
18
     */
19
    public function __construct($ctrl)
20
    {
21
        $this->ctrl = $ctrl;
22
    }
23
24
    public function execute()
25
    {
26
        $rowApi = DB::table('cms_apicustom')->where('permalink', $this->ctrl->permalink)->first();
27
        ApiValidations::doValidations($rowApi, $this->ctrl);
28
29
        $table = $rowApi->tabel;
30
31
        @$parameters = unserialize($rowApi->parameters);
32
        list($type_except, $input_validator) = $this->validateParams($parameters, $table);
33
34
        $posts = request()->all();
35
        $this->ctrl->hookBefore($posts);
36
37
38
        unset($posts['limit'], $posts['offset'], $posts['orderby']);
39
        $actionType = $rowApi->aksi;
40
        if (in_array($actionType, ['list', 'detail', 'delete'])) {
41
            @$responses = unserialize($rowApi->responses);
42
            $responses_fields = $this->prepareResponses($responses);
43
            $data = $this->fetchDataFromDB($table, $responses, $responses_fields, $parameters, $posts);
44
45
            $this->filterRows($data, $parameters, $posts, $table, $type_except);
46
47
            if (!is_null($rowApi->sql_where)) {
48
                $data->whereraw($rowApi->sql_where);
49
            }
50
51
            $this->ctrl->hookQuery($data);
52
            $result = [];
53
            if ($actionType == 'list') {
54
                $result = HandleListAction::handle($table, $data, $responses_fields, $this);
55
            } elseif ($actionType == 'detail') {
56
                $result = HandleDetailsAction::handle($data, $parameters, $posts, $responses_fields, $this);
57
            } elseif ($actionType == 'delete') {
58
                $result = $this->handleDeleteAction($table, $data);
59
            }
60
            ApiResponder::send($result, $posts, $this->ctrl);
61
        } elseif (in_array($actionType, ['save_add', 'save_edit'])) {
62
            $rowAssign = array_filter($input_validator, function ($column) use ($table) {
63
                return Schema::hasColumn($table, $column);
64
            }, ARRAY_FILTER_USE_KEY);
65
66
            $this->handleAddEdit($parameters, $posts, $rowAssign);
67
        }
68
69
    }
70
71
    /**
72
     * @param $responses
73
     * @return array
74
     */
75
    private function prepareResponses($responses)
76
    {
77
        $responsesFields = [];
78
        foreach ($responses as $r) {
79
            if ($r['used']) {
80
                $responsesFields[] = $r['name'];
81
            }
82
        }
83
84
        return $responsesFields;
85
    }
86
87
    /**
88
     * @param $table
89
     * @param $data
90
     * @return mixed
91
     */
92
    private function handleDeleteAction($table, $data)
93
    {
94
        if (\Schema::hasColumn($table, 'deleted_at')) {
95
            $delete = $data->update(['deleted_at' => YmdHis()]);
96
        } else {
97
            $delete = $data->delete();
98
        }
99
100
        $status = ($delete) ? 1 : 0;
101
        $msg = ($delete) ? "success" : "failed";
102
103
        return ApiResponder::makeResult($status, $msg);
104
    }
105
106
    /**
107
     * @param $data
108
     * @param $parameters
109
     * @param $posts
110
     * @param $table
111
     * @param $typeExcept
112
     */
113
    private function filterRows($data, $parameters, $posts, $table, $typeExcept)
114
    {
115
        $data->where(function ($w) use ($parameters, $posts, $table, $typeExcept) {
116
            foreach ($parameters as $param) {
117
                $name = $param['name'];
118
                $type = $param['type'];
119
                $value = $posts[$name];
120
                $used = $param['used'];
121
                $required = $param['required'];
122
123
                if (in_array($type, $typeExcept)) {
124
                    continue;
125
                }
126
127
                if ($param['config'] != '' && substr($param['config'], 0, 1) != '*') {
128
                    $value = $param['config'];
129
                }
130
131
                if ($required == '1') {
132
                    $this->applyWhere($w, $table, $name, $value);
133
                } else {
134
                    if ($used && $value) {
135
                        $this->applyWhere($w, $table, $name, $value);
136
                    }
137
                }
138
            }
139
        });
140
    }
141
142
    /**
143
     * @param $w
144
     * @param $table
145
     * @param $name
146
     * @param $value
147
     */
148
    private function applyWhere($w, $table, $name, $value)
149
    {
150
        if (\Schema::hasColumn($table, $name)) {
151
            $w->where($table.'.'.$name, $value);
152
        } else {
153
            $w->having($name, '=', $value);
154
        }
155
    }
156
157
    /**
158
     * @param $parameters
159
     * @param $posts
160
     * @param $data
161
     * @param $table
162
     * @return null
163
     */
164
    private function params($parameters, $posts, $data, $table)
165
    {
166
        foreach ($parameters as $param) {
167
            $name = $param['name'];
168
            $type = $param['type'];
169
            $value = $posts[$name];
170
            $used = $param['used'];
171
            $required = $param['required'];
172
            $config = $param['config'];
173
174
            if ($type == 'password') {
175
                $data->addselect($table.'.'.$name);
176
            }
177
178
            if ($type !== 'search') {
179
                continue;
180
            }
181
            $search_in = explode(',', $config);
182
183
            if ($required == '1' || ($used && $value)) {
184
                $this->applyLike($data, $search_in, $value);
185
            }
186
        }
187
    }
188
189
    /**
190
     * @param $parameters
191
     * @param $posts
192
     * @param $rowAssign
193
     */
194
    private function handleAddEdit($parameters, $posts, $rowAssign)
195
    {
196
        foreach ($parameters as $param) {
197
            $name = $param['name'];
198
            $used = $param['used'];
199
            $value = $posts[$name];
200
            if ($used == '1' && $value == '') {
201
                unset($rowAssign[$name]);
202
            }
203
        }
204
    }
205
206
    /**
207
     * @param $table
208
     * @param $data
209
     * @param $responses
210
     *
211
     * @param $responsesFields
212
     * @return array
213
     */
214
    private function responses($table, $data, $responses, $responsesFields)
215
    {
216
        $name_tmp = [];
217
218
        $responses = $this->filterRedundantResp($responses);
219
220
        foreach ($responses as $resp) {
221
            $name = $resp['name'];
222
            $subquery = $resp['subquery'];
223
            $used = intval($resp['used']);
224
225
            if (in_array($name, $name_tmp)) {
226
                continue;
227
            }
228
229
            if ($subquery) {
230
                $data->addSelect(DB::raw('('.$subquery.') as '.$name));
231
                $name_tmp[] = $name;
232
                continue;
233
            }
234
235
            if ($used) {
236
                $data->addSelect($table.'.'.$name);
237
            }
238
239
            $name_tmp[] = $name;
240
            $name_tmp = $this->joinRelatedTables($table, $responsesFields, $name, $data, $name_tmp);
241
        }
242
243
        return $data;
244
    }
245
246
    /**
247
     * @param $data
248
     * @param $search_in
249
     * @param $value
250
     */
251
    private function applyLike($data, $search_in, $value)
252
    {
253
        $data->where(function ($w) use ($search_in, $value) {
254
            foreach ($search_in as $k => $field) {
255
                $method = 'orWhere';
256
                if ($k == 0) {
257
                    $method = 'where';
258
                }
259
                $w->$method($field, "like", "%$value%");
260
            }
261
        });
262
    }
263
264
    /**
265
     * @param $table
266
     * @param $responsesFields
267
     * @param $name
268
     * @param $data
269
     * @param $nameTmp
270
     * @return array
271
     */
272
    private function joinRelatedTables($table, $responsesFields, $name, $data, $nameTmp)
273
    {
274
        if (! DbInspector::isForeignKey($name)) {
275
            return $nameTmp;
276
        }
277
        $joinTable = DbInspector::getRelatedTableName($name);
278
        $data->leftjoin($joinTable, $joinTable.'.id', '=', $table.'.'.$name);
279
        foreach (\Schema::getColumnListing($joinTable) as $jf) {
280
            $jfAlias = $joinTable.'_'.$jf;
281
            if (in_array($jfAlias, $responsesFields)) {
282
                $data->addselect($joinTable.'.'.$jf.' as '.$jfAlias);
283
                $nameTmp[] = $jfAlias;
284
            }
285
        }
286
287
        return $nameTmp;
288
    }
289
290
    /**
291
     * @param $inputValidator
292
     * @param $dataValidation
293
     * @param $posts
294
     * @return mixed
295
     */
296
    private function doValidation($inputValidator, $dataValidation, $posts)
297
    {
298
        $validator = Validator::make($inputValidator, $dataValidation);
299
        if (! $validator->fails()) {
300
            return true;
301
        }
302
        $message = $validator->errors()->all();
303
        $message = implode(', ', $message);
304
        $result = ApiResponder::makeResult(0, $message);
305
306
        ApiResponder::send($result, $posts, $this->ctrl);
307
    }
308
309
    /**
310
     * @param $responses
311
     * @return array
312
     */
313
    private function filterRedundantResp($responses)
314
    {
315
        $responses = array_filter($responses, function ($resp) {
316
            return ! ($resp['name'] == 'ref_id' || $resp['type'] == 'custom');
317
        });
318
319
        $responses = array_filter($responses, function ($resp) {
320
            return (intval($resp['used']) != 0 || DbInspector::isForeignKey($resp['name']));
321
        });
322
323
        return $responses;
324
    }
325
326
    /**
327
     * @param $parameters
328
     * @param $table
329
     * @return array
330
     */
331
    private function validateParams($parameters, $table)
332
    {
333
        $posts = request()->all();
334
        if (! $parameters) {
335
            return ['', ''];
336
        }
337
        $typeExcept = ['password', 'ref', 'base64_file', 'custom', 'search'];
338
        $inputValidator = [];
339
        $dataValidation = [];
340
341
        $parameters = array_filter($parameters, function ($param){
342
            return !(is_string($param['config'])&& !starts_with($param['config'], '*'));
343
        });
344
345
        foreach ($parameters as $param) {
346
            $name = $param['name'];
347
            $value = $posts[$name];
348
            $used = $param['used'];
349
350
            if ($used == 0) {
351
                continue;
352
            }
353
354
            $inputValidator[$name] = $value;
355
            $dataValidation[$name] = app(ValidationRules::class)->make($param, $typeExcept, $table);
356
        }
357
358
        $this->doValidation($inputValidator, $dataValidation, $posts);
359
360
        return [$typeExcept, $inputValidator];
361
    }
362
363
    /**
364
     * @param $table
365
     * @param $responses
366
     * @param $responsesFields
367
     * @param $parameters
368
     * @param $posts
369
     * @return array
370
     */
371
    private function fetchDataFromDB($table, $responses, $responsesFields, $parameters, $posts)
372
    {
373
        $data = DB::table($table);
374
        $data->skip(request('offset', 0));
0 ignored issues
show
Bug introduced by
request('offset', 0) of type Illuminate\Http\Request|string|array is incompatible with the type integer expected by parameter $value of Illuminate\Database\Query\Builder::skip(). ( Ignorable by Annotation )

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

374
        $data->skip(/** @scrutinizer ignore-type */ request('offset', 0));
Loading history...
375
        $data->take(request('limit', 20));
0 ignored issues
show
Bug introduced by
request('limit', 20) of type Illuminate\Http\Request|string|array is incompatible with the type integer expected by parameter $value of Illuminate\Database\Query\Builder::take(). ( Ignorable by Annotation )

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

375
        $data->take(/** @scrutinizer ignore-type */ request('limit', 20));
Loading history...
376
        $data = $this->responses($table, $data, $responses, $responsesFields); //End Responses
377
378
        $this->params($parameters, $posts, $data, $table);
379
380
        if (\Schema::hasColumn($table, 'deleted_at')) {
381
            $data->where($table.'.deleted_at', null);
382
        }
383
384
        return $data;
385
    }
386
}