GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Restful::sendPayload()   B
last analyzed

Complexity

Conditions 10
Paths 14

Size

Total Lines 64
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 29
nc 14
nop 2
dl 0
loc 64
rs 7.6666
c 0
b 0
f 0

How to fix   Long Method    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
/**
3
 * This file is part of the O2System Framework package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 *
8
 * @author         Steeve Andrian Salim
9
 * @copyright      Copyright (c) Steeve Andrian Salim
10
 */
11
12
// ------------------------------------------------------------------------
13
14
namespace O2System\Framework\Http\Controllers;
15
16
// ------------------------------------------------------------------------
17
18
use O2System\Cache\Item;
19
use O2System\Framework\Http\Controller;
20
use O2System\Framework\Models\Sql\Model;
21
use O2System\Psr\Http\Header\ResponseFieldInterface;
22
use O2System\Security\Filters\Rules;
23
use O2System\Spl\Exceptions\Logic\OutOfRangeException;
24
25
/**
26
 * Class Restful
27
 *
28
 * @package O2System\Framework\Http\Controllers
29
 */
30
class Restful extends Controller
31
{
32
    /**
33
     * Push headers flag
34
     *
35
     * Used for push default headers by controller.
36
     * Set to FALSE if you want to set default headers on the web-server configuration.
37
     *
38
     * APACHE via .htaccess
39
     * IIS via .webconfig
40
     * Nginx via config
41
     *
42
     * @type string
43
     */
44
    protected $pushDefaultHeaders = false;
45
46
    /**
47
     * Access-Control-Allow-Origin
48
     *
49
     * Used for indicates whether a resource can be shared based by
50
     * returning the value of the Origin request header, "*", or "null" in the response.
51
     *
52
     * @type string
53
     */
54
    protected $accessControlAllowOrigin = '*';
55
56
    /**
57
     * Access-Control-Allow-Credentials
58
     *
59
     * Used for indicates whether the response to request can be exposed when the omit credentials flag is unset.
60
     * When part of the response to a preflight request it indicates that the actual request can include user
61
     * credentials.
62
     *
63
     * @type bool
64
     */
65
    protected $accessControlAllowCredentials = true;
66
67
    /**
68
     * Access-Control-Method
69
     *
70
     * @var string
71
     */
72
    protected $accessControlMethod = 'GET';
73
74
    /**
75
     * Access-Control-Params
76
     *
77
     * @var array
78
     */
79
    protected $accessControlParams = [];
80
81
    /**
82
     * Access-Control-Allow-Methods
83
     *
84
     * Used for indicates, as part of the response to a preflight request,
85
     * which methods can be used during the actual request.
86
     *
87
     * @type array
88
     */
89
    protected $accessControlAllowMethods = [
90
        'GET', // common request
91
        'POST', // used for create, update request
92
        'PUT', // used for upload files request
93
        'DELETE', // used for delete request
94
        'OPTIONS', // used for preflight request
95
    ];
96
97
    /**
98
     * Access-Control-Allow-Headers
99
     *
100
     * Used for indicates, as part of the response to a preflight request,
101
     * which header field names can be used during the actual request.
102
     *
103
     * @type array
104
     */
105
    protected $accessControlAllowHeaders = [
106
        'Origin',
107
        'Access-Control-Request-Method',
108
        'Access-Control-Request-Headers',
109
        'X-Api-Authenticate', // API-Authenticate: api_key="xxx", api_secret="xxx", api_signature="xxx"
110
        'X-Api-Token',
111
        'X-Web-Token', // X-Web-Token: xxx (json-web-token)
112
        'X-Csrf-Token',
113
        'X-Xss-Token',
114
        'X-Request-ID',
115
        'X-Requested-With',
116
        'X-Requested-Result',
117
    ];
118
119
    /**
120
     * Access-Control-Allow-Headers
121
     *
122
     * Used for indicates, as part of the response to a preflight request,
123
     * which header field names can be used during the actual request.
124
     *
125
     * @type array
126
     */
127
    protected $accessControlAllowContentTypes = [
128
        'text/html',
129
        'application/json',
130
        'application/xml',
131
    ];
132
133
    /**
134
     * Access-Control-Max-Age
135
     *
136
     * Used for indicates how long the results of a preflight request can be cached in a preflight result cache
137
     *
138
     * @type int
139
     */
140
    protected $accessControlMaxAge = 86400;
141
142
    /**
143
     * Restful::$ajaxOnly
144
     *
145
     * @var bool
146
     */
147
    protected $ajaxOnly = false;
148
149
    /**
150
     * Restful::$model
151
     *
152
     * @var \O2System\Framework\Models\Sql\Model|\O2System\Framework\Models\NoSql\Model|\O2System\Framework\Models\Files\Model
153
     */
154
    public $model;
155
156
    /**
157
     * Restful::$params
158
     *
159
     * @var array
160
     */
161
    public $params = [];
162
163
    /**
164
     * Restful::$paramsWithRules
165
     *
166
     * @var array
167
     */
168
    public $paramsWithRules = [];
169
170
    /**
171
     * Restful::$fillableColumns
172
     *
173
     * @var array
174
     */
175
    public $fillableColumns = [];
176
177
    /**
178
     * Restful::$fillableColumnsWithRules
179
     *
180
     * @var array
181
     */
182
    public $fillableColumnsWithRules = [];
183
184
    /**
185
     * Restful::$dataTableColumns
186
     *
187
     * @var array
188
     */
189
    public $dataTableColumns = [];
190
191
    // ------------------------------------------------------------------------
192
193
    /**
194
     * Restful::__construct
195
     */
196
    public function __construct()
197
    {
198
        if (services()->has('presenter')) {
199
            presenter()->setTheme(false);
0 ignored issues
show
Bug introduced by
false of type false is incompatible with the type string expected by parameter $theme of O2System\Framework\Http\Presenter::setTheme(). ( Ignorable by Annotation )

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

199
            presenter()->setTheme(/** @scrutinizer ignore-type */ false);
Loading history...
200
        }
201
202
        if (is_ajax()) {
203
            output()->setContentType('application/json');
0 ignored issues
show
Bug introduced by
The method setContentType() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

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

203
            output()->/** @scrutinizer ignore-call */ setContentType('application/json');

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...
204
        } elseif ($this->ajaxOnly === false) {
205
            output()->setContentType('application/json');
206
        } else {
207
            output()->setContentType('text/html');
208
        }
209
210
        if ($contentType = input()->server('HTTP_X_REQUESTED_CONTENT_TYPE')) {
211
            if (in_array($contentType, $this->accessControlAllowContentTypes)) {
212
                output()->setContentType($contentType);
213
            }
214
        }
215
216
        if ($this->pushDefaultHeaders) {
217
218
            $origin = input()->server('HTTP_ORIGIN');
219
220
            /**
221
             * Prepare for preflight modern browser request
222
             *
223
             * Since some server cannot use 'Access-Control-Allow-Origin: *'
224
             * the Access-Control-Allow-Origin will be defined based on requested origin
225
             */
226
            if ($this->accessControlAllowOrigin === '*') {
227
                output()->addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_ORIGIN, $origin);
0 ignored issues
show
Bug introduced by
The method addHeader() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

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

227
                output()->/** @scrutinizer ignore-call */ addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_ORIGIN, $origin);

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...
228
            }
229
230
            // Set response access control allowed credentials
231
            if ($this->accessControlAllowCredentials === false) {
232
                output()->addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_CREDENTIALS, 'false');
233
            }
234
235
            // Set response access control allowed methods header
236
            if (count($this->accessControlAllowMethods)) {
237
                output()->addHeader(
238
                    ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_METHODS,
239
                    implode(', ', $this->accessControlAllowMethods)
240
                );
241
            }
242
243
            // Set response access control allowed headers header
244
            if (count($this->accessControlAllowHeaders)) {
245
                output()->addHeader(
246
                    ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_HEADERS,
247
                    implode(', ', $this->accessControlAllowHeaders)
248
                );
249
            }
250
251
            // Set response access control allowed content types header
252
            if (count($this->accessControlAllowContentTypes)) {
253
                output()->addHeader(
254
                    ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_ALLOW_CONTENT_TYPES,
255
                    implode(', ', $this->accessControlAllowContentTypes)
256
                );
257
            }
258
259
            // Set response access control max age header
260
            if ($this->accessControlMaxAge > 0) {
261
                output()->addHeader(ResponseFieldInterface::RESPONSE_ACCESS_CONTROL_MAX_AGE,
262
                    $this->accessControlMaxAge);
263
            }
264
        }
265
266
        if (input()->server('REQUEST_METHOD') === 'OPTIONS') {
267
            exit(EXIT_SUCCESS);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
268
        } elseif ( ! in_array(input()->server('REQUEST_METHOD'), $this->accessControlAllowMethods)) {
269
            $this->sendError(405);
270
        } elseif (count($this->accessControlParams)) {
271
            if ($this->accessControlMethod === 'GET') {
272
                if (empty($_GET)) {
273
                    $this->sendError(400);
274
                }
275
            } elseif ($this->accessControlMethod === 'POST') {
276
                if (empty($_POST)) {
277
                    $this->sendError(400);
278
                }
279
            } elseif (in_array($this->accessControlMethod, ['GETPOST', 'POSTGET'])) {
280
                if (empty($_REQUEST)) {
281
                    $this->sendError(400);
282
                }
283
            }
284
        }
285
286
        if (empty($this->model)) {
287
            $controllerClassName = get_called_class();
288
            $modelClassName = str_replace('Controllers', 'Models', $controllerClassName);
289
290
            if (class_exists($modelClassName)) {
291
                $this->model = new $modelClassName();
292
            }
293
        } elseif (class_exists($this->model)) {
0 ignored issues
show
Bug introduced by
$this->model of type O2System\Framework\Model...mework\Models\Sql\Model is incompatible with the type string expected by parameter $class_name of class_exists(). ( Ignorable by Annotation )

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

293
        } elseif (class_exists(/** @scrutinizer ignore-type */ $this->model)) {
Loading history...
294
            $this->model = new $this->model();
295
        }
296
    }
297
298
    // ------------------------------------------------------------------------
299
300
    /**
301
     * Restful::index
302
     */
303
    public function index()
304
    {
305
        if (empty($this->model)) {
306
            output()->sendError(204);
307
        } else {
308
            if ( ! $this->model instanceof Model) {
309
                $this->sendError(503, 'Model is not exists!');
310
            }
311
312
            if ( ! $this->model instanceof Model) {
0 ignored issues
show
introduced by
$this->model is always a sub-type of O2System\Framework\Models\Sql\Model.
Loading history...
313
                $this->sendError(503, 'Model is not exists!');
314
            }
315
316
            if (count($this->params)) {
317
                if ($get = input()->get()) {
318
                    if (false !== ($result = $this->model->withPaging()->findWhere($get->getArrayCopy()))) {
319
                        if ($result->count()) {
320
                            $this->sendPayload($result);
321
                        } else {
322
                            $this->sendError(204);
323
                        }
324
                    } else {
325
                        $this->sendError(204);
326
                    }
327
                } else {
328
                    $this->sendError(400, 'Get parameters cannot be empty!');
329
                }
330
            } elseif (count($this->paramsWithRules)) {
331
                if ($get = input()->get()) {
332
                    $rules = new Rules($get);
0 ignored issues
show
Bug introduced by
$get of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

332
                    $rules = new Rules(/** @scrutinizer ignore-type */ $get);
Loading history...
333
                    $rules->sets($this->paramsWithRules);
334
335
                    if ( ! $rules->validate()) {
336
                        $this->sendError(400, implode(', ', $rules->displayErrors(true)));
0 ignored issues
show
Unused Code introduced by
The call to O2System\Security\Filters\Rules::displayErrors() has too many arguments starting with true. ( Ignorable by Annotation )

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

336
                        $this->sendError(400, implode(', ', $rules->/** @scrutinizer ignore-call */ displayErrors(true)));

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...
Bug introduced by
It seems like $rules->displayErrors(true) can also be of type string; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

336
                        $this->sendError(400, implode(', ', /** @scrutinizer ignore-type */ $rules->displayErrors(true)));
Loading history...
337
                    } else {
338
                        $conditions = [];
339
340
                        foreach ($this->paramsWithRules as $param) {
341
                            if ($get->offsetExists($param[ 'field' ])) {
342
                                $conditions[ $param[ 'field' ] ] = $get->offsetGet($param[ 'field' ]);
343
                            }
344
                        }
345
346
                        if (false !== ($result = $this->model->withPaging()->findWhere($conditions))) {
347
                            if ($result->count()) {
348
                                $this->sendPayload($result);
349
                            } else {
350
                                $this->sendError(204);
351
                            }
352
                        } else {
353
                            $this->sendError(204);
354
                        }
355
                    }
356
                } else {
357
                    $this->sendError(400, 'Get parameters cannot be empty!');
358
                }
359
            } elseif ($get = input()->get()) {
360
                if (false !== ($result = $this->model->withPaging()->findWhere($get->getArrayCopy()))) {
361
                    if ($result->count()) {
362
                        $this->sendPayload($result);
363
                    } else {
364
                        $this->sendError(204);
365
                    }
366
                } else {
367
                    $this->sendError(204);
368
                }
369
            } else {
370
                if (false !== ($result = $this->model->allWithPaging())) {
371
                    $this->sendPayload($result);
372
                } else {
373
                    $this->sendError(204);
374
                }
375
            }
376
        }
377
    }
378
379
    // ------------------------------------------------------------------------
380
381
    /**
382
     * Restful::datatable
383
     */
384
    public function datatable()
385
    {
386
        if (empty($this->model)) {
387
            output()->sendError(204);
388
        } else {
389
            if ( ! $this->model instanceof Model) {
390
                $this->sendError(503, 'Model is not exists!');
391
            }
392
393
            if ( ! $this->model instanceof Model) {
0 ignored issues
show
introduced by
$this->model is always a sub-type of O2System\Framework\Models\Sql\Model.
Loading history...
394
                $this->sendError(503, 'Model is not exists!');
395
            }
396
397
            $hasAction = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $hasAction is dead and can be removed.
Loading history...
398
            if($request = input()->request()) {
399
                // Start as limit
400
                $this->model->qb->limit($request['start']);
401
402
                // Length as offset
403
                $this->model->qb->offset($request['length']);
404
405
                // Set ordering
406
                if( ! empty($request['order'])) {
407
                    foreach($request['order'] as $dt => $order) {
408
                        $field = $request['columns'][$order['column']]['data'];
409
                        $this->model->qb->orderBy($field, strtoupper($order['dir']));
410
                    }
411
                }
412
413
                $this->model->visibleColumns = [];
414
415
                foreach($request['columns'] as $dt => $column) {
416
                    if($column['data'] === 'action') {
417
                        $this->model->appendColumns[] = 'action';
418
419
                        continue;
420
                    }
421
422
                    if($column['searchable']) {
423
                        if($dt == 0) {
424
                            if( ! empty($column['search']['value']) ) {
425
                                $this->model->qb->like($column['data'], $column['search']['value']);
426
427
                                if( ! empty($request['search']['value'])) {
428
                                    $this->model->qb->orLike($column['data'], $request['search']['value']);
429
                                }
430
                            } elseif( ! empty($request['search']['value'])) {
431
                                $this->model->qb->like($column['data'], $request['search']['value']);
432
                            }
433
                        } else {
434
                            if( ! empty($column['search']['value']) ) {
435
                                $this->model->qb->orLike($column[ 'data' ], $column[ 'search' ][ 'value' ]);
436
                            }
437
438
                            if( ! empty($request['search']['value'])) {
439
                                $this->model->qb->orLike($column['data'], $request['search']['value']);
440
                            }
441
                        }
442
                    }
443
444
                    $this->model->visibleColumns[] = $column['data'];
445
                }
446
            }
447
448
            $this->model->rebuildRowCallback(function ($row) {
449
                $row->DT_RowId = 'datatable-row-' . $row->id;
450
            });
451
452
            if (false !== ($result = $this->model->all())) {
453
                output()->sendPayload([
0 ignored issues
show
Bug introduced by
The method sendPayload() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

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

453
                output()->/** @scrutinizer ignore-call */ sendPayload([

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...
454
                    'draw'            => input()->request('draw'),
455
                    'recordsTotal'    => $result->info->num_total,
0 ignored issues
show
Bug Best Practice introduced by
The property $info is declared protected in O2System\Framework\Models\Sql\DataObjects\Result. Since you implement __get, consider adding a @property or @property-read.
Loading history...
456
                    'recordsFiltered' => $result->info->num_founds,
457
                    'data'            => $result->toArray(),
458
                ]);
459
            } else {
460
                $this->sendError(204);
461
            }
462
        }
463
    }
464
465
    // ------------------------------------------------------------------------
466
467
    /**
468
     * Controller::create
469
     *
470
     * @throws \O2System\Spl\Exceptions\Logic\BadFunctionCall\BadDependencyCallException
471
     * @throws \O2System\Spl\Exceptions\Logic\OutOfRangeException
472
     */
473
    public function create()
474
    {
475
        if ($post = input()->post()) {
476
            if (count($this->fillableColumnsWithRules)) {
477
                $rules = new Rules($post);
0 ignored issues
show
Bug introduced by
$post of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

477
                $rules = new Rules(/** @scrutinizer ignore-type */ $post);
Loading history...
478
                $rules->sets($this->fillableColumnsWithRules);
479
                if ( ! $rules->validate()) {
480
                    $this->sendError(400, $rules->displayErrors(true));
0 ignored issues
show
Bug introduced by
It seems like $rules->displayErrors(true) can also be of type array; however, parameter $message of O2System\Framework\Http\...rs\Restful::sendError() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

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

480
                    $this->sendError(400, /** @scrutinizer ignore-type */ $rules->displayErrors(true));
Loading history...
Unused Code introduced by
The call to O2System\Security\Filters\Rules::displayErrors() has too many arguments starting with true. ( Ignorable by Annotation )

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

480
                    $this->sendError(400, $rules->/** @scrutinizer ignore-call */ displayErrors(true));

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...
481
                }
482
            }
483
484
            if ( ! $this->model instanceof Model) {
485
                $this->sendError(503, 'Model is not ready');
486
            }
487
488
            $data = [];
489
490
            if (count($this->fillableColumnsWithRules)) {
491
                foreach ($this->fillableColumnsWithRules as $column) {
492
                    if ($post->offsetExists($column[ 'field' ])) {
493
                        $data[ $column[ 'field' ] ] = $post->offsetGet($column[ 'field' ]);
494
                    }
495
                }
496
            } elseif (count($this->fillableColumns)) {
497
                foreach ($this->fillableColumns as $column) {
498
                    if ($post->offsetExists($column[ 'field' ])) {
499
                        $data[ $column[ 'field' ] ] = $post->offsetGet($column[ 'field' ]);
500
                    }
501
                }
502
            } else {
503
                $data = $post->getArrayCopy();
504
            }
505
506
            if (count($data)) {
507
                $data[ 'record_create_timestamp' ] = $data[ 'record_update_timestamp' ] = timestamp();
508
                $data[ 'record_create_user' ] = $data[ 'record_update_user' ] = globals()->account->id;
0 ignored issues
show
Bug Best Practice introduced by
The property account does not exist on O2System\Framework\Containers\Globals. Since you implemented __get, consider adding a @property annotation.
Loading history...
509
510
                if ($this->model->insert($data)) {
511
                    $data[ 'id' ] = $this->model->db->getLastInsertId();
512
                    $this->sendPayload([
513
                        'code' => 201,
514
                        'Successful insert request',
515
                        'data' => $data,
516
                    ]);
517
                } else {
518
                    $this->sendError(501, 'Failed update request');
519
                }
520
            } else {
521
                $this->sendError(400, 'Post parameters cannot be empty!');
522
            }
523
        } else {
524
            $this->sendError(400);
525
        }
526
    }
527
528
    // ------------------------------------------------------------------------
529
530
    /**
531
     * Restful::update
532
     *
533
     * @throws \O2System\Spl\Exceptions\Logic\BadFunctionCall\BadDependencyCallException
534
     * @throws \O2System\Spl\Exceptions\Logic\OutOfRangeException
535
     */
536
    public function update()
537
    {
538
539
        if ($post = input()->post()) {
540
            $conditions = [];
541
542
            if (count($this->fillableColumnsWithRules)) {
543
                $rules = new Rules($post);
0 ignored issues
show
Bug introduced by
$post of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

543
                $rules = new Rules(/** @scrutinizer ignore-type */ $post);
Loading history...
544
                $rules->sets($this->fillableColumnsWithRules);
545
546
547
                if (count($this->model->primaryKeys)) {
0 ignored issues
show
Bug Best Practice introduced by
The property primaryKeys does not exist on O2System\Framework\Models\Files\Model. Since you implemented __get, consider adding a @property annotation.
Loading history...
548
                    foreach ($this->model->primaryKeys as $primaryKey) {
549
                        $rules->add($primaryKey, language('LABEL_' . strtoupper($primaryKey)), 'required',
0 ignored issues
show
Bug introduced by
language('LABEL_' . strtoupper($primaryKey)) of type O2System\Framework\Servi...ernel\Services\Language is incompatible with the type string expected by parameter $label of O2System\Security\Filters\Rules::add(). ( Ignorable by Annotation )

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

549
                        $rules->add($primaryKey, /** @scrutinizer ignore-type */ language('LABEL_' . strtoupper($primaryKey)), 'required',
Loading history...
550
                            'this field cannot be empty!');
0 ignored issues
show
Bug introduced by
'this field cannot be empty!' of type string is incompatible with the type array expected by parameter $messages of O2System\Security\Filters\Rules::add(). ( Ignorable by Annotation )

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

550
                            /** @scrutinizer ignore-type */ 'this field cannot be empty!');
Loading history...
551
                    }
552
                } else {
553
                    $primaryKey = empty($this->model->primaryKey) ? 'id' : $this->model->primaryKey;
554
                    $conditions = [$primaryKey => $post->offsetGet($primaryKey)];
555
                    $rules->add($primaryKey, language('LABEL_' . strtoupper($primaryKey)), 'required',
556
                        'this field cannot be empty!');
557
                }
558
559
                if ( ! $rules->validate()) {
560
                    $this->sendError(400, implode(', ', $rules->displayErrors(true)));
0 ignored issues
show
Unused Code introduced by
The call to O2System\Security\Filters\Rules::displayErrors() has too many arguments starting with true. ( Ignorable by Annotation )

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

560
                    $this->sendError(400, implode(', ', $rules->/** @scrutinizer ignore-call */ displayErrors(true)));

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...
Bug introduced by
It seems like $rules->displayErrors(true) can also be of type string; however, parameter $pieces of implode() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

560
                    $this->sendError(400, implode(', ', /** @scrutinizer ignore-type */ $rules->displayErrors(true)));
Loading history...
561
                }
562
            }
563
564
            if ( ! $this->model instanceof Model) {
565
                $this->sendError(503, 'Model is not ready');
566
            }
567
568
            $data = [];
569
570
            if (count($this->fillableColumnsWithRules)) {
571
                foreach ($this->fillableColumnsWithRules as $column) {
572
                    if ($post->offsetExists($column[ 'field' ])) {
573
                        $data[ $column[ 'field' ] ] = $post->offsetGet($column[ 'field' ]);
574
                    }
575
                }
576
            } elseif (count($this->fillableColumns)) {
577
                foreach ($this->fillableColumns as $column) {
578
                    if ($post->offsetExists($column[ 'field' ])) {
579
                        $data[ $column[ 'field' ] ] = $post->offsetGet($column[ 'field' ]);
580
                    }
581
                }
582
            } else {
583
                $data = $post->getArrayCopy();
584
            }
585
586
            if (count($data)) {
587
                $data[ 'record_update_timestamp' ] = timestamp();
588
                $data[ 'record_update_user' ] = globals()->account->id;
0 ignored issues
show
Bug Best Practice introduced by
The property account does not exist on O2System\Framework\Containers\Globals. Since you implemented __get, consider adding a @property annotation.
Loading history...
589
590
591
                if ($this->model->update($data, $conditions)) {
592
                    $this->sendError(201, 'Successful update request');
593
                } else {
594
                    $this->sendError(501, 'Failed update request');
595
                }
596
            } else {
597
                $this->sendError(400, 'Post parameters cannot be empty!');
598
            }
599
        } else {
600
            $this->sendError(400);
601
        }
602
    }
603
604
    // ------------------------------------------------------------------------
605
606
    /**
607
     * Restful::delete
608
     *
609
     * @throws \O2System\Spl\Exceptions\Logic\OutOfRangeException
610
     * @throws \O2System\Spl\Exceptions\RuntimeException
611
     * @throws \Psr\Cache\InvalidArgumentException
612
     */
613
    public function delete()
614
    {
615
        if ($post = input()->post()) {
616
            $rules = new Rules($post);
0 ignored issues
show
Bug introduced by
$post of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

616
            $rules = new Rules(/** @scrutinizer ignore-type */ $post);
Loading history...
617
            $rules->add('id', 'ID', 'required', 'ID field cannot be empty!');
0 ignored issues
show
Bug introduced by
'ID field cannot be empty!' of type string is incompatible with the type array expected by parameter $messages of O2System\Security\Filters\Rules::add(). ( Ignorable by Annotation )

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

617
            $rules->add('id', 'ID', 'required', /** @scrutinizer ignore-type */ 'ID field cannot be empty!');
Loading history...
618
619
            if ( ! $rules->validate()) {
620
                $this->sendError(400, implode(', ', $rules->getErrors()));
621
            }
622
623
            if ( ! $this->model instanceof Model) {
624
                $this->sendError(503, 'Model is not ready');
625
            }
626
627
            if ($this->model->delete($post->id)) {
628
                $this->sendError(201, 'Successful delete request');
629
            } else {
630
                $this->sendError(501, 'Failed delete request');
631
            }
632
        } else {
633
            $this->sendError(400);
634
        }
635
    }
636
637
    // ------------------------------------------------------------------------
638
639
    /**
640
     * Restful::publish
641
     *
642
     * @throws OutOfRangeException
643
     */
644
    public function publish()
645
    {
646
        if ($post = input()->post()) {
647
            $rules = new Rules($post);
0 ignored issues
show
Bug introduced by
$post of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

647
            $rules = new Rules(/** @scrutinizer ignore-type */ $post);
Loading history...
648
            $rules->add('id', 'ID', 'required', 'ID field cannot be empty!');
0 ignored issues
show
Bug introduced by
'ID field cannot be empty!' of type string is incompatible with the type array expected by parameter $messages of O2System\Security\Filters\Rules::add(). ( Ignorable by Annotation )

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

648
            $rules->add('id', 'ID', 'required', /** @scrutinizer ignore-type */ 'ID field cannot be empty!');
Loading history...
649
650
            if ( ! $rules->validate()) {
651
                $this->sendError(400, implode(', ', $rules->getErrors()));
652
            }
653
654
            if ( ! $this->model instanceof Model) {
655
                $this->sendError(503, 'Model is not ready');
656
            }
657
658
            if ($this->model->publish($post->id)) {
659
                $this->sendError(201, 'Successful publish request');
660
            } else {
661
                $this->sendError(501, 'Failed publish request');
662
            }
663
        } else {
664
            $this->sendError(400);
665
        }
666
    }
667
668
    // ------------------------------------------------------------------------
669
670
    /**
671
     * Restful::unpublish
672
     *
673
     * @throws OutOfRangeException
674
     */
675
    public function unpublish()
676
    {
677
        if ($post = input()->post()) {
678
            $rules = new Rules($post);
0 ignored issues
show
Bug introduced by
$post of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

678
            $rules = new Rules(/** @scrutinizer ignore-type */ $post);
Loading history...
679
            $rules->add('id', 'ID', 'required', 'ID field cannot be empty!');
0 ignored issues
show
Bug introduced by
'ID field cannot be empty!' of type string is incompatible with the type array expected by parameter $messages of O2System\Security\Filters\Rules::add(). ( Ignorable by Annotation )

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

679
            $rules->add('id', 'ID', 'required', /** @scrutinizer ignore-type */ 'ID field cannot be empty!');
Loading history...
680
681
            if ( ! $rules->validate()) {
682
                $this->sendError(400, implode(', ', $rules->getErrors()));
683
            }
684
685
            if ( ! $this->model instanceof Model) {
686
                $this->sendError(503, 'Model is not ready');
687
            }
688
689
            if ($this->model->unpublish($post->id)) {
690
                $this->sendError(201, 'Successful unpublish request');
691
            } else {
692
                $this->sendError(501, 'Failed unpublish request');
693
            }
694
        } else {
695
            $this->sendError(400);
696
        }
697
    }
698
699
    // ------------------------------------------------------------------------
700
701
    /**
702
     * Restful::archive
703
     *
704
     * @throws OutOfRangeException
705
     */
706
    public function archive()
707
    {
708
        if ($post = input()->post()) {
709
            $rules = new Rules($post);
0 ignored issues
show
Bug introduced by
$post of type O2System\Spl\DataStructures\SplArrayObject is incompatible with the type array expected by parameter $sourceVars of O2System\Security\Filters\Rules::__construct(). ( Ignorable by Annotation )

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

709
            $rules = new Rules(/** @scrutinizer ignore-type */ $post);
Loading history...
710
            $rules->add('id', 'ID', 'required', 'ID field cannot be empty!');
0 ignored issues
show
Bug introduced by
'ID field cannot be empty!' of type string is incompatible with the type array expected by parameter $messages of O2System\Security\Filters\Rules::add(). ( Ignorable by Annotation )

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

710
            $rules->add('id', 'ID', 'required', /** @scrutinizer ignore-type */ 'ID field cannot be empty!');
Loading history...
711
712
            if ( ! $rules->validate()) {
713
                $this->sendError(400, implode(', ', $rules->getErrors()));
714
            }
715
716
            if ( ! $this->model instanceof Model) {
717
                $this->sendError(503, 'Model is not ready');
718
            }
719
720
            if ($this->model->archive($post->id)) {
721
                $this->sendError(201, 'Successful archived request');
722
            } else {
723
                $this->sendError(501, 'Failed archived request');
724
            }
725
        } else {
726
            $this->sendError(400);
727
        }
728
    }
729
730
    // ------------------------------------------------------------------------
731
732
    /**
733
     * Restful::sendError
734
     *
735
     * @param int         $code
736
     * @param string|null $message
737
     */
738
    public function sendError($code, $message = null)
739
    {
740
        if ($this->ajaxOnly === false) {
741
            output()->setContentType('application/json');
742
        }
743
744
        if (is_array($code)) {
0 ignored issues
show
introduced by
The condition is_array($code) is always false.
Loading history...
745
            if (is_numeric(key($code))) {
746
                $message = reset($code);
747
                $code = key($code);
748
            } elseif (isset($code[ 'code' ])) {
749
                $code = $code[ 'code' ];
750
                $message = $code[ 'message' ];
751
            }
752
        }
753
754
        output()->sendError($code, $message);
755
    }
756
757
    // ------------------------------------------------------------------------
758
759
    /**
760
     * Restful::sendPayload
761
     *
762
     * @param mixed $data        The payload data to-be send.
763
     * @param bool  $longPooling Long pooling flag mode.
764
     *
765
     * @throws \Exception
766
     */
767
    public function sendPayload($data, $longPooling = false)
768
    {
769
        if ($longPooling === false) {
770
            if ($this->ajaxOnly) {
771
                if (is_ajax()) {
772
                    output()->send($data);
0 ignored issues
show
Bug introduced by
The method send() does not exist on O2System\Kernel\Cli\Output. ( Ignorable by Annotation )

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

772
                    output()->/** @scrutinizer ignore-call */ send($data);

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...
773
                } else {
774
                    output()->sendError(403);
775
                }
776
            } else {
777
                output()->send($data);
778
            }
779
        } elseif (is_ajax()) {
780
            /**
781
             * Server-side file.
782
             * This file is an infinitive loop. Seriously.
783
             * It gets the cache created timestamp, checks if this is larger than the timestamp of the
784
             * AJAX-submitted timestamp (time of last ajax request), and if so, it sends back a JSON with the data from
785
             * data.txt (and a timestamp). If not, it waits for one seconds and then start the next while step.
786
             *
787
             * Note: This returns a JSON, containing the content of data.txt and the timestamp of the last data.txt change.
788
             * This timestamp is used by the client's JavaScript for the next request, so THIS server-side script here only
789
             * serves new content after the last file change. Sounds weird, but try it out, you'll get into it really fast!
790
             */
791
792
            // set php runtime to unlimited
793
            set_time_limit(0);
794
795
            $longPoolingCacheKey = 'long-pooling-' . session()->get('id');
0 ignored issues
show
Bug introduced by
Are you sure session()->get('id') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

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

795
            $longPoolingCacheKey = 'long-pooling-' . /** @scrutinizer ignore-type */ session()->get('id');
Loading history...
796
            $longPoolingCacheData = null;
797
798
            if ( ! cache()->hasItem($longPoolingCacheKey)) {
799
                cache()->save(new Item($longPoolingCacheKey, $data));
800
            }
801
802
            // main loop
803
            while (true) {
804
                // if ajax request has send a timestamp, then $lastCallTimestamp = timestamp, else $last_call = null
805
                $lastCallTimestamp = (int)input()->getPost('last_call_timestamp');
0 ignored issues
show
Bug introduced by
The method getPost() does not exist on O2System\Kernel\Cli\Input. ( Ignorable by Annotation )

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

805
                $lastCallTimestamp = (int)input()->/** @scrutinizer ignore-call */ getPost('last_call_timestamp');

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...
806
807
                // PHP caches file data, like requesting the size of a file, by default. clearstatcache() clears that cache
808
                clearstatcache();
809
810
                if (cache()->hasItem($longPoolingCacheKey)) {
811
                    $longPoolingCacheData = cache()->getItem($longPoolingCacheKey);
812
                }
813
814
                // get timestamp of when file has been changed the last time
815
                $longPoolingCacheMetadata = $longPoolingCacheData->getMetadata();
816
817
                // if no timestamp delivered via ajax or data.txt has been changed SINCE last ajax timestamp
818
                if ($lastCallTimestamp == null || $longPoolingCacheMetadata[ 'ctime' ] > $lastCallTimestamp) {
819
                    output()->send([
820
                        'timestamp' => $longPoolingCacheMetadata,
821
                        'data'      => $data,
822
                    ]);
823
                } else {
824
                    // wait for 1 sec (not very sexy as this blocks the PHP/Apache process, but that's how it goes)
825
                    sleep(1);
826
                    continue;
827
                }
828
            }
829
        } else {
830
            output()->sendError(501);
831
        }
832
    }
833
}