Passed
Pull Request — master (#1116)
by Iman
03:38
created

ExecuteApi::validateMethodType()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 2
nop 4
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
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
8
class ExecuteApi
9
{
10
    private $ctrl;
11
12
    /**
13
     * ExecuteApi constructor.
14
     *
15
     * @param $ctrl
16
     */
17
    public function __construct($ctrl)
18
    {
19
        $this->ctrl = $ctrl;
20
    }
21
22
    public function execute()
23
    {
24
        $result = [];
25
        $posts = request()->all();
26
        //$posts_keys = array_keys($posts);
27
        //$posts_values = array_values($posts);
28
29
        $row_api = DB::table('cms_apicustom')->where('permalink', $this->ctrl->permalink)->first();
0 ignored issues
show
Bug introduced by
The type crocodicstudio\crudboost...ollers\ApiController\DB was not found. Did you mean DB? If so, make sure to prefix the type with \.
Loading history...
30
31
        $action_type = $row_api->aksi;
32
        $table = $row_api->tabel;
33
34
        $debugModeMessage = 'You are in debug mode !';
35
36
        /* Do some custome pre-checking for posted data, if failed discard API execution */
37
        $this->doCustomePrecheck($posts, $result, $debugModeMessage);
38
39
        /* Method Type validation */
40
        $this->validateMethodType($row_api, $result, $debugModeMessage, $posts);
41
42
        /* Check the row is exists or not */
43
        $this->checkApiDefined($row_api, $result, $debugModeMessage, $posts);
44
45
        @$parameters = unserialize($row_api->parameters);
46
        @$responses = unserialize($row_api->responses);
47
48
        /*
49
        | ----------------------------------------------
50
        | User Data Validation
51
        | ----------------------------------------------
52
        |
53
        */
54
        if ($parameters) {
55
            $type_except = ['password', 'ref', 'base64_file', 'custom', 'search'];
56
            $input_validator = [];
57
            $data_validation = [];
58
59
            foreach ($parameters as $param) {
60
                $name = $param['name'];
61
                $value = $posts[$name];
62
                $used = $param['used'];
63
64
                if ($used == 0) {
65
                    continue;
66
                }
67
                if ($param['config'] && substr($param['config'], 0, 1) != '*') {
68
                    continue;
69
                }
70
71
                $input_validator[$name] = $value;
72
                $data_validation[$name] = app(ValidationRules::class)->make($param, $type_except, $table);
73
            }
74
75
            $result = $this->doValidation($input_validator, $data_validation, $result, $debugModeMessage, $posts);
76
        }
77
78
        $responses_fields = $this->prepareResponses($responses);
79
80
        $this->ctrl->hookBefore($posts);
81
82
        $limit = ($posts['limit']) ?: 20;
83
        $offset = ($posts['offset']) ?: 0;
84
        $orderby = ($posts['orderby']) ?: $table.'.id,desc';
85
86
        unset($posts['limit'], $posts['offset'], $posts['orderby']);
87
88
        if (in_array($action_type, ['list', 'detail', 'delete'])) {
89
            $data = DB::table($table);
90
            $data->skip($offset);
91
            $data->take($limit);
92
            $data = $this->responses($table, $data, $responses, $responses_fields); //End Responses
93
94
            $this->params($parameters, $posts, $data, $table);
95
96
            if (\Schema::hasColumn($table, 'deleted_at')) {
97
                $data->where($table.'.deleted_at', null);
98
            }
99
100
            $this->filterRows($data, $parameters, $posts, $table, $type_except);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $type_except does not seem to be defined for all execution paths leading up to this point.
Loading history...
101
102
            //IF SQL WHERE IS NOT NULL
103
            if ($row_api->sql_where) {
104
                $data->whereraw($row_api->sql_where);
105
            }
106
107
            $this->ctrl->hookQuery($data);
108
            if ($action_type == 'list') {
109
                list($result, $row) = $this->handleListAction($table, $orderby, $data, $result, $debugModeMessage, $row, $responses_fields);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $row seems to be never defined.
Loading history...
110
            }
111
            $result = $this->handleDetailsAction($action_type, $result, $debugModeMessage, $data, $parameters, $posts, $responses_fields);
112
            if ($action_type == 'delete') {
113
                $result = $this->handleDeleteAction($action_type, $table, $data, $result, $debugModeMessage);
0 ignored issues
show
Unused Code introduced by
The call to crocodicstudio\crudboost...i::handleDeleteAction() has too many arguments starting with $debugModeMessage. ( Ignorable by Annotation )

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

113
                /** @scrutinizer ignore-call */ 
114
                $result = $this->handleDeleteAction($action_type, $table, $data, $result, $debugModeMessage);

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...
114
            }
115
        }
116
117
        if (in_array($action_type, ['save_add', 'save_edit'])) {
118
            $this->handleAddEdit($parameters, $posts, $row_assign);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $row_assign does not exist. Did you maybe mean $row_api?
Loading history...
119
        }
120
121
        $this->show($result, $debugModeMessage, $posts);
122
    }
123
124
    /**
125
     * @param $result
126
     * @param $debugModeMessage
127
     * @param $posts
128
     * @return mixed
129
     */
130
    private function show($result, $debugModeMessage, $posts)
131
    {
132
        $result['api_status'] = $this->ctrl->hook_api_status ?: $result['api_status'];
133
        $result['api_message'] = $this->ctrl->hook_api_message ?: $result['api_message'];
134
135
        if (cbGetsetting('api_debug_mode') == 'true') {
136
            $result['api_authorization'] = $debugModeMessage;
137
        }
138
139
        $this->ctrl->hookAfter($posts, $result);
140
141
        sendAndTerminate(response()->json($result));
0 ignored issues
show
Bug introduced by
The method json() does not exist on Symfony\Component\HttpFoundation\Response. It seems like you code against a sub-type of Symfony\Component\HttpFoundation\Response such as Illuminate\Http\Response or Illuminate\Http\JsonResponse or Illuminate\Http\RedirectResponse. ( Ignorable by Annotation )

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

141
        sendAndTerminate(response()->/** @scrutinizer ignore-call */ json($result));
Loading history...
142
    }
143
144
    /**
145
     * @param $responses
146
     * @return array
147
     */
148
    private function prepareResponses($responses)
149
    {
150
        $responsesFields = [];
151
        foreach ($responses as $r) {
152
            if ($r['used']) {
153
                $responsesFields[] = $r['name'];
154
            }
155
        }
156
157
        return $responsesFields;
158
    }
159
160
    /**
161
     * @param $table
162
     * @param $orderby
163
     * @param $data
164
     * @param $result
165
     * @param $debugModeMessage
166
     * @param $row
167
     * @param $responses_fields
168
     * @return array
169
     */
170
    private function handleListAction($table, $orderby, $data, $result, $debugModeMessage, $row, $responses_fields)
171
    {
172
        $orderby_col = $table.'.id';
173
        $orderby_val = 'desc';
174
175
        if ($orderby) {
176
            $orderby_raw = explode(',', $orderby);
177
            $orderby_col = $orderby_raw[0];
178
            $orderby_val = $orderby_raw[1];
179
        }
180
181
        $rows = $data->orderby($orderby_col, $orderby_val)->get();
182
183
        $result['api_status'] = 0;
184
        $result['api_message'] = 'There is no data found !';
185
        if (cbGetsetting('api_debug_mode') == 'true') {
186
            $result['api_authorization'] = $debugModeMessage;
187
        }
188
        $result['data'] = [];
189
        if ($rows) {
190
            list($row, $result) = $this->handleRows($result, $debugModeMessage, $row, $responses_fields, $rows);
191
        }
192
193
        return [$result, $row];
194
    }
195
196
    /**
197
     * @param $table
198
     * @param $data
199
     * @param $result
200
     * @param $debugModeMessage
201
     * @return mixed
202
     */
203
    private function handleDeleteAction($table, $data, $result, $debugModeMessage)
204
    {
205
        if (\Schema::hasColumn($table, 'deleted_at')) {
206
            $delete = $data->update(['deleted_at' => date('Y-m-d H:i:s')]);
207
        } else {
208
            $delete = $data->delete();
209
        }
210
211
        $result['api_status'] = ($delete) ? 1 : 0;
212
        $result['api_message'] = ($delete) ? "success" : "failed";
213
        if (cbGetsetting('api_debug_mode') == 'true') {
214
            $result['api_authorization'] = $debugModeMessage;
215
        }
216
217
        return $result;
218
    }
219
220
    /**
221
     * @param $data
222
     * @param $parameters
223
     * @param $posts
224
     * @param $table
225
     * @param $type_except
226
     */
227
    private function filterRows($data, $parameters, $posts, $table, $type_except)
228
    {
229
        $data->where(function ($w) use ($parameters, $posts, $table, $type_except) {
230
            foreach ($parameters as $param) {
231
                $name = $param['name'];
232
                $type = $param['type'];
233
                $value = $posts[$name];
234
                $used = $param['used'];
235
                $required = $param['required'];
236
237
                if (in_array($type, $type_except)) {
238
                    continue;
239
                }
240
241
                if ($param['config'] != '' && substr($param['config'], 0, 1) != '*') {
242
                    $value = $param['config'];
243
                }
244
245
                if ($required == '1') {
246
                    $this->applyWhere($w, $table, $name, $value);
247
                } else {
248
                    if ($used && $value) {
249
                        $this->applyWhere($w, $table, $name, $value);
250
                    }
251
                }
252
            }
253
        });
254
    }
255
256
    /**
257
     * @param $w
258
     * @param $table
259
     * @param $name
260
     * @param $value
261
     */
262
    private function applyWhere($w, $table, $name, $value)
263
    {
264
        if (\Schema::hasColumn($table, $name)) {
265
            $w->where($table.'.'.$name, $value);
266
        } else {
267
            $w->having($name, '=', $value);
268
        }
269
    }
270
271
    /**
272
     * @param $parameters
273
     * @param $posts
274
     * @param $data
275
     * @param $table
276
     * @return null
277
     */
278
    private function params($parameters, $posts, $data, $table)
279
    {
280
        foreach ($parameters as $param) {
281
            $name = $param['name'];
282
            $type = $param['type'];
283
            $value = $posts[$name];
284
            $used = $param['used'];
285
            $required = $param['required'];
286
            $config = $param['config'];
287
288
            if ($type == 'password') {
289
                $data->addselect($table.'.'.$name);
290
            }
291
292
            if ($type !== 'search') {
293
                continue;
294
            }
295
            $search_in = explode(',', $config);
296
297
            if ($required == '1' || ($used && $value)) {
298
                $this->applyLike($data, $search_in, $value);
299
            }
300
        }
301
    }
302
303
    /**
304
     * @param $result
305
     * @param $debug_mode_message
306
     * @param $row
307
     * @param $responses_fields
308
     * @param $rows
309
     * @return array
310
     */
311
    private function handleRows($result, $debug_mode_message, $row, $responses_fields, $rows)
312
    {
313
        $uploadsFormatCandidate = explode(',', cbConfig("UPLOAD_TYPES"));
314
        foreach ($rows as &$row) {
0 ignored issues
show
introduced by
$row is overwriting one of the parameters of this function.
Loading history...
315
            foreach ($row as $k => $v) {
316
                $ext = \File::extension($v);
317
                if (in_array($ext, $uploadsFormatCandidate)) {
318
                    $row->$k = asset($v);
319
                }
320
321
                if (! in_array($k, $responses_fields)) {
322
                    unset($row[$k]);
323
                }
324
            }
325
        }
326
327
        $result['api_status'] = 1;
328
        $result['api_message'] = 'success';
329
        if (cbGetsetting('api_debug_mode') == 'true') {
330
            $result['api_authorization'] = $debug_mode_message;
331
        }
332
        $result['data'] = $rows;
333
334
        return [$row, $result];
335
    }
336
337
    /**
338
     * @param $parameters
339
     * @param $posts
340
     * @param $row_assign
341
     */
342
    private function handleAddEdit($parameters, $posts, $row_assign)
343
    {
344
        foreach ($parameters as $param) {
345
            $name = $param['name'];
346
            $used = $param['used'];
347
            $value = $posts[$name];
348
            if ($used == '1' && $value == '') {
349
                unset($row_assign[$name]);
350
            }
351
        }
352
    }
353
354
    /**
355
     * @param $result
356
     * @param $debug_mode_message
357
     * @param $posts
358
     * @return mixed
359
     */
360
    private function passwordError($result, $debug_mode_message, $posts)
361
    {
362
        $result['api_status'] = 0;
363
        $result['api_message'] = 'Your password is wrong !';
364
        if (cbGetsetting('api_debug_mode') == 'true') {
365
            $result['api_authorization'] = $debug_mode_message;
366
        }
367
368
        $this->show($result, $debug_mode_message, $posts);
369
    }
370
371
    /**
372
     * @param $rows
373
     * @param $responses_fields
374
     * @param $row
375
     */
376
    private function handleFile($rows, $responses_fields, $row)
377
    {
378
        foreach ($rows as $k => $v) {
379
            $ext = \File::extension($v);
380
            if (FieldDetector::isUploadField($ext)) {
381
                $rows->$k = asset($v);
382
            }
383
384
            if (! in_array($k, $responses_fields)) {
385
                unset($row[$k]);
386
            }
387
        }
388
    }
389
390
    /**
391
     * @param $table
392
     * @param $data
393
     * @param $responses
394
     * @param $responses_fields
395
     * @return array
396
     */
397
    private function responses($table, $data, $responses, $responses_fields)
398
    {
399
        $name_tmp = [];
400
        foreach ($responses as $resp) {
401
            $name = $resp['name'];
402
            $type = $resp['type'];
403
            $subquery = $resp['subquery'];
404
            $used = intval($resp['used']);
405
406
            if ($used == 0 && ! DbInspector::isForeignKey($name)) {
407
                continue;
408
            }
409
410
            if (in_array($name, $name_tmp)) {
411
                continue;
412
            }
413
414
            if ($name == 'ref_id' || $type == 'custom') {
415
                continue;
416
            }
417
418
            if ($subquery) {
419
                $data->addSelect(DB::raw('('.$subquery.') as '.$name));
420
                $name_tmp[] = $name;
421
                continue;
422
            }
423
424
            if ($used) {
425
                $data->addSelect($table.'.'.$name);
426
            }
427
428
            $name_tmp[] = $name;
429
            $name_tmp = $this->joinRelatedTables($table, $responses_fields, $name, $data, $name_tmp);
430
        }
431
432
        return $data;
433
    }
434
435
    /**
436
     * @param $result
437
     * @param $debug_mode_message
438
     * @param $rows
439
     * @return array
440
     */
441
    private function success($result, $debug_mode_message, $rows)
442
    {
443
        $result['api_status'] = 1;
444
        $result['api_message'] = 'success';
445
        if (cbGetsetting('api_debug_mode') == 'true') {
446
            $result['api_authorization'] = $debug_mode_message;
447
        }
448
        $rows = (array) $rows;
449
        $result = array_merge($result, $rows);
450
451
        return $result;
452
    }
453
454
    /**
455
     * @param $data
456
     * @param $search_in
457
     * @param $value
458
     */
459
    private function applyLike($data, $search_in, $value)
460
    {
461
        $data->where(function ($w) use ($search_in, $value) {
462
            foreach ($search_in as $k => $field) {
463
                if ($k == 0) {
464
                    $w->where($field, "like", "%$value%");
465
                } else {
466
                    $w->orWhere($field, "like", "%$value%");
467
                }
468
            }
469
        });
470
    }
471
472
    /**
473
     * @param $table
474
     * @param $responses_fields
475
     * @param $name
476
     * @param $data
477
     * @param $name_tmp
478
     * @return array
479
     */
480
    private function joinRelatedTables($table, $responses_fields, $name, $data, $name_tmp)
481
    {
482
        if (DbInspector::isForeignKey($name)) {
483
            $jointable = CRUDBooster::getTableForeignKey($name);
0 ignored issues
show
Bug introduced by
The type crocodicstudio\crudboost...iController\CRUDBooster 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...
484
            $jointable_field = DbInspector::getTableCols($jointable);
485
486
            $data->leftjoin($jointable, $jointable.'.id', '=', $table.'.'.$name);
487
            foreach ($jointable_field as $jf) {
488
                $jf_alias = $jointable.'_'.$jf;
489
                if (in_array($jf_alias, $responses_fields)) {
490
                    $data->addselect($jointable.'.'.$jf.' as '.$jf_alias);
491
                    $name_tmp[] = $jf_alias;
492
                }
493
            }
494
        }
495
496
        return $name_tmp;
497
    }
498
499
    /**
500
     * @param $row_api
501
     * @param $result
502
     * @param $debugModeMessage
503
     * @param $posts
504
     * @return mixed
505
     */
506
    private function validateMethodType($row_api, $result, $debugModeMessage, $posts)
507
    {
508
        $method_type = $row_api->method_type;
509
        if (! $method_type || ! Request::isMethod($method_type)) {
0 ignored issues
show
Bug introduced by
The type crocodicstudio\crudboost...s\ApiController\Request was not found. Did you mean Request? If so, make sure to prefix the type with \.
Loading history...
510
            $result['api_status'] = 0;
511
            $result['api_message'] = "The request method is not allowed !";
512
513
            $this->show($result, $debugModeMessage, $posts);
514
        }
515
516
        return $result;
517
    }
518
519
    /**
520
     * @param $posts
521
     * @param $result
522
     * @param $debugModeMessage
523
     * @return mixed
524
     */
525
    private function doCustomePrecheck($posts, $result, $debugModeMessage)
526
    {
527
        $this->ctrl->hookValidate($posts);
528
        if ($this->ctrl->validate) { // hook have to return true
529
            $result['api_status'] = 0;
530
            $result['api_message'] = "Failed to execute API !";
531
532
            $this->show($result, $debugModeMessage, $posts);
533
        }
534
535
        return $result;
536
    }
537
538
    /**
539
     * @param $row_api
540
     * @param $result
541
     * @param $debugModeMessage
542
     * @param $posts
543
     * @return mixed
544
     */
545
    private function checkApiDefined($row_api, $result, $debugModeMessage, $posts)
546
    {
547
        if (! $row_api) {
548
            $result['api_status'] = 0;
549
            $result['api_message'] = 'Sorry this API is no longer available, maybe has changed by admin, or please make sure api url is correct.';
550
551
            $this->show($result, $debugModeMessage, $posts);
552
        }
553
554
        return $result;
555
    }
556
557
    /**
558
     * @param $input_validator
559
     * @param $data_validation
560
     * @param $result
561
     * @param $debugModeMessage
562
     * @param $posts
563
     * @return mixed
564
     */
565
    private function doValidation($input_validator, $data_validation, $result, $debugModeMessage, $posts)
566
    {
567
        $validator = Validator::make($input_validator, $data_validation);
0 ignored issues
show
Bug introduced by
The type crocodicstudio\crudboost...ApiController\Validator was not found. Did you mean Validator? If so, make sure to prefix the type with \.
Loading history...
568
        if ($validator->fails()) {
569
            $message = $validator->errors()->all();
570
            $message = implode(', ', $message);
571
            $result['api_status'] = 0;
572
            $result['api_message'] = $message;
573
574
            $this->show($result, $debugModeMessage, $posts);
575
        }
576
577
        return $result;
578
    }
579
580
    /**
581
     * @param $action_type
582
     * @param $result
583
     * @param $debugModeMessage
584
     * @param $data
585
     * @param $parameters
586
     * @param $posts
587
     * @param $responses_fields
588
     * @return array
589
     */
590
    private function handleDetailsAction($action_type, $result, $debugModeMessage, $data, $parameters, $posts, $responses_fields)
591
    {
592
        if ($action_type == 'detail') {
593
            $result['api_status'] = 0;
594
            $result['api_message'] = 'There is no data found !';
595
596
            if (cbGetsetting('api_debug_mode') == 'true') {
597
                $result['api_authorization'] = $debugModeMessage;
598
            }
599
600
            $row = $data->first();
601
602
            if ($row) {
603
                foreach ($parameters as $param) {
604
                    $name = $param['name'];
605
                    $type = $param['type'];
606
                    $value = $posts[$name];
607
                    $used = $param['used'];
608
                    $required = $param['required'];
609
610
                    if ($param['config'] != '' && substr($param['config'], 0, 1) != '*') {
611
                        $value = $param['config'];
612
                    }
613
614
                    if ($required && $type == 'password' && ! Hash::check($value, $row->{$name})) {
0 ignored issues
show
Bug introduced by
The type crocodicstudio\crudboost...lers\ApiController\Hash was not found. Did you mean Hash? If so, make sure to prefix the type with \.
Loading history...
615
                        $this->passwordError($result, $debugModeMessage, $posts);
616
                    }
617
618
                    if (! $required && $used && $value && ! Hash::check($value, $row->{$name})) {
619
                        $this->passwordError($result, $debugModeMessage, $posts);
620
                    }
621
                }
622
623
                $this->handleFile($row, $responses_fields, $row);
624
625
                $result = $this->success($result, $debugModeMessage, $row);
626
            }
627
        }
628
629
        return $result;
630
    }
631
}