Passed
Push — master ( 21d85a...18548d )
by Iman
04:31
created

ExecuteApi::handleAddEdit()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
nc 3
nop 3
dl 0
loc 8
c 0
b 0
f 0
cc 4
rs 9.2
1
<?php
2
3
namespace crocodicstudio\crudbooster\controllers\ApiController;
4
5
use crocodicstudio\crudbooster\helpers\DbInspector;
6
use crocodicstudio\crudbooster\Modules\ModuleGenerator\ControllerGenerator\FieldDetector;
7
use Illuminate\Support\Facades\DB;
8
use Illuminate\Support\Facades\Schema;
9
use Illuminate\Support\Facades\Validator;
10
11
class ExecuteApi
12
{
13
    private $ctrl;
14
15
    /**
16
     * ExecuteApi constructor.
17
     *
18
     * @param $ctrl
19
     */
20
    public function __construct($ctrl)
21
    {
22
        $this->ctrl = $ctrl;
23
    }
24
25
    public function execute()
26
    {
27
        $rowApi = DB::table('cms_apicustom')->where('permalink', $this->ctrl->permalink)->first();
28
        ApiValidations::doValidations($rowApi, $this->ctrl);
29
30
        $table = $rowApi->tabel;
31
32
        @$parameters = unserialize($rowApi->parameters);
33
        list($type_except, $input_validator) = $this->validateParams($parameters, $table);
34
35
        $posts = request()->all();
36
        $this->ctrl->hookBefore($posts);
37
38
39
        unset($posts['limit'], $posts['offset'], $posts['orderby']);
40
        $actionType = $rowApi->aksi;
41
        if (in_array($actionType, ['list', 'detail', 'delete'])) {
42
            @$responses = unserialize($rowApi->responses);
43
            $responses_fields = $this->prepareResponses($responses);
44
            $data = $this->fetchDataFromDB($table, $responses, $responses_fields, $parameters, $posts);
45
46
            $this->filterRows($data, $parameters, $posts, $table, $type_except);
47
48
            if (!is_null($rowApi->sql_where)) {
49
                $data->whereraw($rowApi->sql_where);
50
            }
51
52
            $this->ctrl->hookQuery($data);
53
            $result = [];
54
            if ($actionType == 'list') {
55
                $result = $this->handleListAction($table, $data, $responses_fields);
0 ignored issues
show
Bug introduced by
The method handleListAction() does not exist on crocodicstudio\crudboost...piController\ExecuteApi. ( Ignorable by Annotation )

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

55
                /** @scrutinizer ignore-call */ 
56
                $result = $this->handleListAction($table, $data, $responses_fields);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
56
            } elseif ($actionType == 'detail') {
57
                $result = HandleDetailsAction::handle($data, $parameters, $posts, $responses_fields, $this);
58
            } elseif ($actionType == 'delete') {
59
                $result = $this->handleDeleteAction($table, $data);
60
            }
61
            ApiResponder::send($result, $posts, $this->ctrl);
62
        } elseif (in_array($actionType, ['save_add', 'save_edit'])) {
63
            $rowAssign = array_filter($input_validator, function ($column) use ($table) {
64
                return Schema::hasColumn($table, $column);
65
            }, ARRAY_FILTER_USE_KEY);
66
67
            $this->handleAddEdit($parameters, $posts, $rowAssign);
68
        }
69
70
    }
71
72
    /**
73
     * @param $responses
74
     * @return array
75
     */
76
    private function prepareResponses($responses)
77
    {
78
        $responsesFields = [];
79
        foreach ($responses as $r) {
80
            if ($r['used']) {
81
                $responsesFields[] = $r['name'];
82
            }
83
        }
84
85
        return $responsesFields;
86
    }
87
88
    /**
89
     * @param $table
90
     * @param $data
91
     * @return mixed
92
     */
93
    private function handleDeleteAction($table, $data)
94
    {
95
        if (\Schema::hasColumn($table, 'deleted_at')) {
96
            $delete = $data->update(['deleted_at' => date('Y-m-d H:i:s')]);
97
        } else {
98
            $delete = $data->delete();
99
        }
100
101
        $status = ($delete) ? 1 : 0;
102
        $msg = ($delete) ? "success" : "failed";
103
104
        return ApiResponder::makeResult($status, $msg);
105
    }
106
107
    /**
108
     * @param $data
109
     * @param $parameters
110
     * @param $posts
111
     * @param $table
112
     * @param $typeExcept
113
     */
114
    private function filterRows($data, $parameters, $posts, $table, $typeExcept)
115
    {
116
        $data->where(function ($w) use ($parameters, $posts, $table, $typeExcept) {
117
            foreach ($parameters as $param) {
118
                $name = $param['name'];
119
                $type = $param['type'];
120
                $value = $posts[$name];
121
                $used = $param['used'];
122
                $required = $param['required'];
123
124
                if (in_array($type, $typeExcept)) {
125
                    continue;
126
                }
127
128
                if ($param['config'] != '' && substr($param['config'], 0, 1) != '*') {
129
                    $value = $param['config'];
130
                }
131
132
                if ($required == '1') {
133
                    $this->applyWhere($w, $table, $name, $value);
134
                } else {
135
                    if ($used && $value) {
136
                        $this->applyWhere($w, $table, $name, $value);
137
                    }
138
                }
139
            }
140
        });
141
    }
142
143
    /**
144
     * @param $w
145
     * @param $table
146
     * @param $name
147
     * @param $value
148
     */
149
    private function applyWhere($w, $table, $name, $value)
150
    {
151
        if (\Schema::hasColumn($table, $name)) {
152
            $w->where($table.'.'.$name, $value);
153
        } else {
154
            $w->having($name, '=', $value);
155
        }
156
    }
157
158
    /**
159
     * @param $parameters
160
     * @param $posts
161
     * @param $data
162
     * @param $table
163
     * @return null
164
     */
165
    private function params($parameters, $posts, $data, $table)
166
    {
167
        foreach ($parameters as $param) {
168
            $name = $param['name'];
169
            $type = $param['type'];
170
            $value = $posts[$name];
171
            $used = $param['used'];
172
            $required = $param['required'];
173
            $config = $param['config'];
174
175
            if ($type == 'password') {
176
                $data->addselect($table.'.'.$name);
177
            }
178
179
            if ($type !== 'search') {
180
                continue;
181
            }
182
            $search_in = explode(',', $config);
183
184
            if ($required == '1' || ($used && $value)) {
185
                $this->applyLike($data, $search_in, $value);
186
            }
187
        }
188
    }
189
190
    /**
191
     * @param $parameters
192
     * @param $posts
193
     * @param $rowAssign
194
     */
195
    private function handleAddEdit($parameters, $posts, $rowAssign)
196
    {
197
        foreach ($parameters as $param) {
198
            $name = $param['name'];
199
            $used = $param['used'];
200
            $value = $posts[$name];
201
            if ($used == '1' && $value == '') {
202
                unset($rowAssign[$name]);
203
            }
204
        }
205
    }
206
207
    /**
208
     * @param $table
209
     * @param $data
210
     * @param $responses
211
     *
212
     * @param $responsesFields
213
     * @return array
214
     */
215
    private function responses($table, $data, $responses, $responsesFields)
216
    {
217
        $name_tmp = [];
218
219
        $responses = $this->filterRedundantResp($responses);
220
221
        foreach ($responses as $resp) {
222
            $name = $resp['name'];
223
            $subquery = $resp['subquery'];
224
            $used = intval($resp['used']);
225
226
            if (in_array($name, $name_tmp)) {
227
                continue;
228
            }
229
230
            if ($subquery) {
231
                $data->addSelect(DB::raw('('.$subquery.') as '.$name));
232
                $name_tmp[] = $name;
233
                continue;
234
            }
235
236
            if ($used) {
237
                $data->addSelect($table.'.'.$name);
238
            }
239
240
            $name_tmp[] = $name;
241
            $name_tmp = $this->joinRelatedTables($table, $responsesFields, $name, $data, $name_tmp);
242
        }
243
244
        return $data;
245
    }
246
247
    /**
248
     * @param $data
249
     * @param $search_in
250
     * @param $value
251
     */
252
    private function applyLike($data, $search_in, $value)
253
    {
254
        $data->where(function ($w) use ($search_in, $value) {
255
            foreach ($search_in as $k => $field) {
256
                $method = 'orWhere';
257
                if ($k == 0) {
258
                    $method = 'where';
259
                }
260
                $w->$method($field, "like", "%$value%");
261
            }
262
        });
263
    }
264
265
    /**
266
     * @param $table
267
     * @param $responsesFields
268
     * @param $name
269
     * @param $data
270
     * @param $nameTmp
271
     * @return array
272
     */
273
    private function joinRelatedTables($table, $responsesFields, $name, $data, $nameTmp)
274
    {
275
        if (! DbInspector::isForeignKey($name)) {
276
            return $nameTmp;
277
        }
278
        $joinTable = DbInspector::getTableForeignKey($name);
279
        $data->leftjoin($joinTable, $joinTable.'.id', '=', $table.'.'.$name);
280
        foreach (\Schema::getColumnListing($joinTable) as $jf) {
281
            $jfAlias = $joinTable.'_'.$jf;
282
            if (in_array($jfAlias, $responsesFields)) {
283
                $data->addselect($joinTable.'.'.$jf.' as '.$jfAlias);
284
                $nameTmp[] = $jfAlias;
285
            }
286
        }
287
288
        return $nameTmp;
289
    }
290
291
    /**
292
     * @param $inputValidator
293
     * @param $dataValidation
294
     * @param $posts
295
     * @return mixed
296
     */
297
    private function doValidation($inputValidator, $dataValidation, $posts)
298
    {
299
        $validator = Validator::make($inputValidator, $dataValidation);
300
        if (! $validator->fails()) {
301
            return true;
302
        }
303
        $message = $validator->errors()->all();
304
        $message = implode(', ', $message);
305
        $result = ApiResponder::makeResult(0, $message);
306
307
        ApiResponder::send($result, $posts, $this->ctrl);
308
    }
309
310
    /**
311
     * @param $responses
312
     * @return array
313
     */
314
    private function filterRedundantResp($responses)
315
    {
316
        $responses = array_filter($responses, function ($resp) {
317
            return ! ($resp['name'] == 'ref_id' || $resp['type'] == 'custom');
318
        });
319
320
        $responses = array_filter($responses, function ($resp) {
321
            return (intval($resp['used']) != 0 || DbInspector::isForeignKey($resp['name']));
322
        });
323
324
        return $responses;
325
    }
326
327
    /**
328
     * @param $parameters
329
     * @param $table
330
     * @return array
331
     */
332
    private function validateParams($parameters, $table)
333
    {
334
        $posts = request()->all();
335
        if (! $parameters) {
336
            return ['', ''];
337
        }
338
        $typeExcept = ['password', 'ref', 'base64_file', 'custom', 'search'];
339
        $inputValidator = [];
340
        $dataValidation = [];
341
342
        $parameters = array_filter($parameters, function ($param){
343
            return !(is_string($param['config'])&& !starts_with($param['config'], '*'));
344
        });
345
346
        foreach ($parameters as $param) {
347
            $name = $param['name'];
348
            $value = $posts[$name];
349
            $used = $param['used'];
350
351
            if ($used == 0) {
352
                continue;
353
            }
354
355
            $inputValidator[$name] = $value;
356
            $dataValidation[$name] = app(ValidationRules::class)->make($param, $typeExcept, $table);
357
        }
358
359
        $this->doValidation($inputValidator, $dataValidation, $posts);
360
361
        return [$typeExcept, $inputValidator];
362
    }
363
364
    /**
365
     * @param $table
366
     * @param $responses
367
     * @param $responsesFields
368
     * @param $parameters
369
     * @param $posts
370
     * @return array
371
     */
372
    private function fetchDataFromDB($table, $responses, $responsesFields, $parameters, $posts)
373
    {
374
        $data = DB::table($table);
375
        $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

375
        $data->skip(/** @scrutinizer ignore-type */ request('offset', 0));
Loading history...
376
        $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

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