Test Failed
Pull Request — master (#5)
by
unknown
13:21
created

Rest::validateAction()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 62
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 34
c 2
b 0
f 0
dl 0
loc 62
ccs 0
cts 24
cp 0
rs 8.4426
cc 7
nc 8
nop 1
crap 56

How to fix   Long Method   

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 Zemit Framework.
4
 *
5
 * (c) Zemit Team <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE.txt
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Zemit\Mvc\Controller;
12
13
use League\Csv\CharsetConverter;
14
use Phalcon\Http\Response;
15
use Phalcon\Mvc\Dispatcher;
16
use Phalcon\Mvc\Model\Resultset;
17
use League\Csv\Writer;
18
use Phalcon\Version;
19
use Zemit\Db\Profiler;
20
use Zemit\Utils\Slug;
21
22
/**
23
 * Class Rest
24
 *
25
 * @author Julien Turbide <[email protected]>
26
 * @copyright Zemit Team <[email protected]>
27
 *
28
 * @since 1.0
29
 * @version 1.0
30
 *
31
 *
32
 * @property Profiler $profiler
33
 * @package Zemit\Mvc\Controller
34
 */
35
class Rest extends \Zemit\Mvc\Controller
36
{
37
    use Model;
0 ignored issues
show
Bug introduced by
The trait Zemit\Mvc\Controller\Model requires the property $loader which is not provided by Zemit\Mvc\Controller\Rest.
Loading history...
38
    
39
    /**
40
     * Rest Bootstrap
41
     */
42
    public function indexAction($id = null)
43
    {
44
        $this->restForwarding($id);
45
    }
46
    
47
    /**
48
     * Rest bootstrap forwarding
49
     *
50
     * @return \Phalcon\Http\ResponseInterface
51
     */
52
    protected function restForwarding($id = null)
53
    {
54
        $id ??= $this->getParam('id');
55
        
56
        if ($this->request->isPost() || $this->request->isPut()) {
57
            $this->dispatcher->forward(['action' => 'save']);
58
        }
59
        else if ($this->request->isDelete()) {
60
            $this->dispatcher->forward(['action' => 'delete']);
61
        }
62
        else if ($this->request->isGet()) {
63
            if (is_null($id)) {
64
                $this->dispatcher->forward(['action' => 'getList']);
65
            }
66
            else {
67
                $this->dispatcher->forward(['action' => 'get']);
68
            }
69
        }
70
        else if ($this->request->isOptions()) {
71
            
72
            // @TODO handle this correctly
73
            return $this->setRestResponse(['result' => 'OK']);
74
        }
75
    }
76
    
77
    /**
78
     * Retrieving a single record
79
     * Alias of method getAction()
80
     * @deprecated Should use getAction() method instead
81
     *
82
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
83
     *
84
     * @return bool|\Phalcon\Http\ResponseInterface
85
     */
86
    public function getSingleAction($id = null) {
87
        return $this->getAction($id);
88
    }
89
    
90
    /**
91
     * Retrieving a single record
92
     *
93
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
94
     *
95
     * @return bool|\Phalcon\Http\ResponseInterface
96
     */
97
    public function getAction($id = null)
98
    {
99
        $modelName = $this->getModelClassName();
100
        $single = $this->getSingle($id, $modelName, null);
101
        
102
        $this->view->single = $single ? $single->expose($this->getExpose()) : false;
0 ignored issues
show
Bug introduced by
The method expose() does not exist on Phalcon\Mvc\Model\Resultset. ( Ignorable by Annotation )

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

102
        $this->view->single = $single ? $single->/** @scrutinizer ignore-call */ expose($this->getExpose()) : false;

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...
Bug introduced by
Are you sure the usage of $this->getExpose() targeting Zemit\Mvc\Controller\Rest::getExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
103
        $this->view->model = $modelName;
104
        $this->view->source = $single ? $single->getSource() : false;
0 ignored issues
show
Bug introduced by
The method getSource() does not exist on Phalcon\Mvc\Model\Resultset. ( Ignorable by Annotation )

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

104
        $this->view->source = $single ? $single->/** @scrutinizer ignore-call */ getSource() : false;

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...
105
        
106
        if (!$single) {
107
            $this->response->setStatusCode(404, 'Not Found');
108
            
109
            return false;
110
        }
111
        
112
        return $this->setRestResponse();
113
    }
114
    
115
    /**
116
     * Retrieving a record list
117
     * Alias of method getListAction()
118
     * @deprecated Should use getListAction() method instead
119
     *
120
     * @return \Phalcon\Http\ResponseInterface
121
     */
122
    public function getAllAction() {
123
        return $this->getListAction();
124
    }
125
    
126
    /**
127
     * Retrieving a record list
128
     *
129
     * @return \Phalcon\Http\ResponseInterface
130
     * @throws \Exception
131
     */
132
    public function getListAction()
133
    {
134
        $model = $this->getModelClassName();
135
        
136
        /** @var Resultset $with */
137
        $find = $this->getFind();
138
        $with = $model::with($this->getListWith() ? : [], $find ? : []);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getListWith() targeting Zemit\Mvc\Controller\Rest::getListWith() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
139
        
140
        /**
141
         * Expose the list
142
         * @var int $key
143
         * @var \Zemit\Mvc\Model $item
144
         */
145
        $list = [];
146
        foreach ($with as $key => $item) {
147
            $list[$key] = $item->expose($this->getListExpose());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getListExpose() targeting Zemit\Mvc\Controller\Rest::getListExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
148
        }
149
        
150
        $list = is_array($list) ? array_values(array_filter($list)) : $list;
0 ignored issues
show
introduced by
The condition is_array($list) is always true.
Loading history...
151
        $this->view->list = $list;
152
        $this->view->listCount = count($list);
153
        $this->view->totalCount = $model::find($this->getFindCount($find));
154
        $this->view->totalCount = is_int($this->view->totalCount)? $this->view->totalCount : count($this->view->totalCount); // @todo fix count to work with rollup when joins
155
        $this->view->limit = $find['limit'] ?? false;
156
        $this->view->offset = $find['offset'] ?? false;
157
        $this->view->find = ($this->config->app->debug || $this->config->debug->enable) ? $find : false;
0 ignored issues
show
Bug Best Practice introduced by
The property app does not exist on Zemit\Bootstrap\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
Bug Best Practice introduced by
The property debug does not exist on Zemit\Bootstrap\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
158
        
159
        return $this->setRestResponse();
160
    }
161
    
162
    /**
163
     * Exporting a record list into a CSV stream
164
     *
165
     * @return \Phalcon\Http\ResponseInterface
166
     * @throws \League\Csv\CannotInsertRecord
167
     * @throws \Zemit\Exception
168
     */
169
    public function exportAction()
170
    {
171
        $model = $this->getModelClassName();
172
        $params = $this->view->getParamsToView();
173
        $contentType = $this->getContentType();
174
        $fileName = ucfirst(Slug::generate(basename(str_replace('\\', '/', $this->getModelClassName())))) . ' List (' . date('Y-m-d') . ')';
175
        
176
        /** @var Resultset $with */
177
        $find = $this->getFind();
178
        $with = $model::with($this->getListWith() ? : [], $find ? : []);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getListWith() targeting Zemit\Mvc\Controller\Rest::getListWith() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
179
180
        /**
181
         * Expose the list
182
         * @var int $key
183
         * @var \Zemit\Mvc\Model $item
184
         */
185
        $list = [];
186
        foreach ($with as $key => $item) {
187
            $list[$key] = $item->expose($this->getExportExpose());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getExportExpose() targeting Zemit\Mvc\Controller\Rest::getExportExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
188
        }
189
190
        $list = is_array($list) ? array_values(array_filter($list)) : $list;
0 ignored issues
show
introduced by
The condition is_array($list) is always true.
Loading history...
191
        $this->flatternArrayForCsv($list);
192
193
        if ($contentType === 'json') {
194
//            $this->response->setJsonContent($list);
195
            $this->response->setContent(json_encode($list, JSON_PRETTY_PRINT, 2048));
196
            $this->response->setContentType('application/json');
197
            $this->response->setHeader('Content-disposition', 'attachment; filename="'.addslashes($fileName).'.json"');
198
            return $this->response->send();
199
        }
200
        
201
        // CSV
202
        if ($contentType === 'csv') {
203
            
204
            // Get CSV custom request parameters
205
            $mode = $params['mode'] ?? null;
206
            $delimiter = $params['delimiter'] ?? null;
207
            $newline = $params['newline'] ?? null;
208
            $escape = $params['escape'] ?? null;
209
            $outputBOM = $params['outputBOM'] ?? null;
210
            $skipIncludeBOM = $params['skipIncludeBOM'] ?? null;
211
            
212
//            $csv = Writer::createFromFileObject(new \SplTempFileObject());
213
            $csv = Writer::createFromStream(fopen('php://memory', 'r+'));
214
            
215
            // CSV - MS Excel on MacOS
216
            if ($mode === 'mac') {
217
                $csv->setOutputBOM(Writer::BOM_UTF16_LE); // utf-16
218
                $csv->setDelimiter("\t"); // tabs separated
219
                $csv->setNewline("\r\n"); // new lines
220
                CharsetConverter::addTo($csv, 'UTF-8', 'UTF-16');
221
            }
222
            
223
            // CSV - MS Excel on Windows
224
            else {
225
                $csv->setOutputBOM(Writer::BOM_UTF8); // utf-8
226
                $csv->setDelimiter(','); // comma separated
227
                $csv->setNewline("\n"); // new line windows
228
                CharsetConverter::addTo($csv, 'UTF-8', 'UTF-8');
229
            }
230
            
231
            // Apply forced params from request
232
            if (isset($outputBOM)) {
233
                $csv->setOutputBOM($outputBOM);
234
            }
235
            if (isset($delimiter)) {
236
                $csv->setDelimiter($delimiter);
237
            }
238
            if (isset($newline)) {
239
                $csv->setNewline($newline);
240
            }
241
            if (isset($escape)) {
242
                $csv->setEscape($escape);
243
            }
244
            if ($skipIncludeBOM) {
245
                $csv->skipInputBOM();
246
            }
247
            else {
248
                $csv->includeInputBOM();
249
            }
250
            
251
            // CSV
252
            $csv->insertOne(array_keys($list[0]));
253
            $csv->insertAll($list);
254
            $csv->output($fileName . '.csv');
255
            die;
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...
256
        }
257
        
258
        // XLSX
259
        if ($contentType === 'xlsx') {
260
            $xlsxArray = [];
261
            foreach ($list as $array) {
262
                if (empty($xlsxArray)) {
263
                    $xlsxArray []= array_keys($array);
264
                }
265
                $xlsxArray []= array_values($array);
266
            }
267
            $xlsx = \SimpleXLSXGen::fromArray($xlsxArray);
268
            $xlsx->downloadAs($fileName . '.xlsx');
269
            die;
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...
270
        }
271
        
272
        // Something went wrong
273
        throw new \Exception('Failed to export `' . $this->getModelClassName() . '` using content-type `' . $contentType . '`', 400);
274
    }
275
276
    /**
277
     * @param array|null $array
278
     *
279
     * @return array|null
280
     */
281
    public function flatternArrayForCsv(?array &$list = null) {
282
283
        foreach ($list as $listKey => $listValue) {
284
            foreach ($listValue as $column => $value) {
285
                if (is_array($value) || is_object($value)) {
286
                    $value = $this->concatListFieldElementForCsv($value, ' ');
287
                    $list[$listKey][$column] = $this->arrayFlatten($value , $column);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type object; however, parameter $array of Zemit\Mvc\Controller\Rest::arrayFlatten() does only seem to accept array|null, 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

287
                    $list[$listKey][$column] = $this->arrayFlatten(/** @scrutinizer ignore-type */ $value , $column);
Loading history...
Coding Style introduced by
Space found before comma in argument list
Loading history...
288
                    if (is_array($list[$listKey][$column])) {
289
                        foreach ($list[$listKey][$column] as $childKey => $childValue) {
290
                            $list[$listKey][$childKey] = $childValue;
291
                            unset ($list[$listKey][$column]);
0 ignored issues
show
Coding Style introduced by
Space before opening parenthesis of function call prohibited
Loading history...
292
                        }
293
                    }
294
                }
295
            }
296
        }
297
298
        $this->formatColumnText($list);
299
        return $this->mergeColumns($list);
300
    }
301
302
    /**
303
     * @param array|object $list
304
     * @param string|null $seperator
305
     *
306
     * @return array|object
307
     */
308
    public function concatListFieldElementForCsv($list, $seperator = ' ') {
309
        foreach ($list as $valueKey => $element) {
310
            if (is_array($element) || is_object($element)) {
311
                $lastKey = array_key_last($list);
0 ignored issues
show
Bug introduced by
It seems like $list can also be of type object; however, parameter $array of array_key_last() 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

311
                $lastKey = array_key_last(/** @scrutinizer ignore-type */ $list);
Loading history...
312
                if ($valueKey === $lastKey) {
313
                    continue;
314
                }
315
                foreach ($element as $elKey => $elValue) {
316
                    $list[$lastKey][$elKey] .= $seperator . $elValue;
317
                    if ($lastKey != $valueKey) {
318
                        unset($list[$valueKey]);
319
                    }
320
                }
321
            }
322
        }
323
324
        return $list;
325
    }
326
327
    /**
328
     * @param array|null $array
329
     * @param string|null $alias
330
     *
331
     * @return array|null
332
     */
333
    function arrayFlatten(?array $array, ?string $alias = null) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for arrayFlatten.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
334
        $return = array();
335
        foreach ($array as $key => $value) {
336
            if (is_array($value)) {
337
                $return = array_merge($return, $this->arrayFlatten($value, $alias));
338
            }
339
            else {
340
                $return[$alias . '.' . $key] = $value;
341
            }
342
        }
343
        return $return;
344
    }
345
346
    /**
347
     * @param array|null $list
348
     *
349
     * @return array|null
350
     */
351
    public function mergeColumns (?array &$list) {
0 ignored issues
show
Coding Style introduced by
Expected "function abc(...)"; found "function abc (...)"
Loading history...
Coding Style introduced by
Expected 0 spaces before opening parenthesis; 1 found
Loading history...
352
        $columnToMergeList = $this->getExportMergeColum ();
0 ignored issues
show
Coding Style introduced by
Space before opening parenthesis of function call prohibited
Loading history...
Bug introduced by
Are you sure the assignment to $columnToMergeList is correct as $this->getExportMergeColum() targeting Zemit\Mvc\Controller\Rest::getExportMergeColum() seems to always return null.

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

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

}

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

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

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

Loading history...
353
        if (!$columnToMergeList || empty($columnToMergeList)) {
0 ignored issues
show
introduced by
$columnToMergeList is of type null, thus it always evaluated to false.
Loading history...
354
            return  $list;
355
        }
356
357
        $columnList = [];
358
        foreach ($list as $listKey => $listValue) {
359
            foreach ($columnToMergeList as $columnToMerge) {
360
                foreach ($columnToMerge['columns'] as $column) {
361
                    if (isset($listValue[$column])) {
362
                        $columnList[$listKey][] = $listValue[$column];
363
                        unset($list[$listKey][$column]);
364
                    }
365
                }
366
                $list[$listKey][$columnToMerge['name']] = implode (' ', $columnList[$listKey] ?? []);
0 ignored issues
show
Coding Style introduced by
Space before opening parenthesis of function call prohibited
Loading history...
367
            }
368
        }
369
370
        return $list;
371
    }
372
373
    /**
374
     * @param array|null $list
375
     *
376
     * @return array|null
377
     */
378
    public function formatColumnText (?array &$list) {
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces before opening parenthesis; 1 found
Loading history...
Coding Style introduced by
Expected "function abc(...)"; found "function abc (...)"
Loading history...
379
        foreach ($list as $listKey => $listValue) {
380
            $formatArray = $this->getExportFormatFieldText ($listValue);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $formatArray is correct as $this->getExportFormatFieldText($listValue) targeting Zemit\Mvc\Controller\Res...ExportFormatFieldText() seems to always return null.

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

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

}

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

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

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

Loading history...
Coding Style introduced by
Space before opening parenthesis of function call prohibited
Loading history...
381
            $columNameList = array_keys($formatArray);
0 ignored issues
show
Bug introduced by
$formatArray of type null is incompatible with the type array expected by parameter $array of array_keys(). ( Ignorable by Annotation )

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

381
            $columNameList = array_keys(/** @scrutinizer ignore-type */ $formatArray);
Loading history...
382
383
            if ($formatArray) {
384
                foreach ($formatArray as $formatKey => $formatValue) {
0 ignored issues
show
Bug introduced by
The expression $formatArray of type void is not traversable.
Loading history...
385
                    if (isset($formatValue['text'])) {
386
                        $list[$listKey][$formatKey] = $formatValue['text'];
387
                    }
388
389
                    if (isset($formatValue['rename'])) {
390
391
                        $list[$listKey][$formatValue['rename']] = $formatValue['text'] ?? ($list[$listKey][$formatKey] ?? null);
392
                        if ($formatValue['rename'] !== $formatKey) {
393
                            foreach ($columNameList as $columnKey => $columnValue) {
394
395
                                if ($formatKey === $columnValue) {
396
                                    $columNameList[$columnKey] = $formatValue['rename'];
397
                                }
398
                            }
399
400
                            unset($list[$listKey][$formatKey]);
401
                        }
402
                    }
403
                }
404
            }
405
406
            if (isset($formatArray['reorder']) && $formatArray['reorder']) {
407
                $list[$listKey] = $this->arrayCustomOrder($list[$listKey], $columNameList);
408
            }
409
        }
410
411
        return $list;
412
    }
413
414
    /**
415
     * @param array $arrayToOrder
416
     * @param array $orderList
417
     *
418
     * @return array
419
     */
420
    function arrayCustomOrder($arrayToOrder, $orderList) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for arrayCustomOrder.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
421
        $ordered = array();
422
        foreach ($orderList as $key) {
423
            if (isset($arrayToOrder[$key])) {
424
                $ordered[$key] = $arrayToOrder[$key];
425
            }
426
        }
427
        return $ordered;
428
    }
429
430
    /**
431
     * Count a record list
432
     * @TODO add total count / deleted count / active count
433
     *
434
     * @return \Phalcon\Http\ResponseInterface
435
     */
436
    public function countAction()
437
    {
438
        $model = $this->getModelClassName();
439
        
440
        /** @var \Zemit\Mvc\Model $entity */
441
        $entity = new $model();
442
        
443
        $this->view->totalCount = $model::count($this->getFindCount($this->getFind()));
444
        $this->view->totalCount = is_int($this->view->totalCount)? $this->view->totalCount : count($this->view->totalCount);
445
        $this->view->model = get_class($entity);
446
        $this->view->source = $entity->getSource();
447
        
448
        return $this->setRestResponse();
449
    }
450
    
451
    /**
452
     * Prepare a new model for the frontend
453
     *
454
     * @return \Phalcon\Http\ResponseInterface
455
     */
456
    public function newAction()
457
    {
458
        $model = $this->getModelClassName();
459
        
460
        /** @var \Zemit\Mvc\Model $entity */
461
        $entity = new $model();
462
        $entity->assign($this->getParams(), $this->getWhiteList(), $this->getColumnMap());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getWhiteList() targeting Zemit\Mvc\Controller\Rest::getWhiteList() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
Bug introduced by
Are you sure the usage of $this->getColumnMap() targeting Zemit\Mvc\Controller\Rest::getColumnMap() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
463
        
464
        $this->view->model = get_class($entity);
465
        $this->view->source = $entity->getSource();
466
        $this->view->single = $entity->expose($this->getExpose());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getExpose() targeting Zemit\Mvc\Controller\Rest::getExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
467
        
468
        return $this->setRestResponse();
469
    }
470
    
471
    /**
472
     * Prepare a new model for the frontend
473
     *
474
     * @return \Phalcon\Http\ResponseInterface
475
     */
476
    public function validateAction($id = null)
477
    {
478
        $model = $this->getModelClassName();
479
        
480
        /** @var \Zemit\Mvc\Model $entity */
481
        $entity = $this->getSingle($id);
482
        $new = !$entity;
0 ignored issues
show
introduced by
$entity is of type Zemit\Mvc\Model, thus it always evaluated to true.
Loading history...
483
        
484
        if ($new) {
0 ignored issues
show
introduced by
The condition $new is always false.
Loading history...
485
            $entity = new $model();
486
        }
487
        
488
        $entity->assign($this->getParams(), $this->getWhiteList(), $this->getColumnMap());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getColumnMap() targeting Zemit\Mvc\Controller\Rest::getColumnMap() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
Bug introduced by
Are you sure the usage of $this->getWhiteList() targeting Zemit\Mvc\Controller\Rest::getWhiteList() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
489
        
490
        /**
491
         * Event to run
492
         * @see https://docs.phalcon.io/4.0/en/db-models-events
493
         */
494
        $events = [
495
            'beforeCreate' => null,
496
            'beforeUpdate' => null,
497
            'beforeSave' => null,
498
            'beforeValidationOnCreate' => null,
499
            'beforeValidationOnUpdate' => null,
500
            'beforeValidation' => null,
501
            'prepareSave' => null,
502
            'validation' => null,
503
            'afterValidationOnCreate' => null,
504
            'afterValidationOnUpdate' => null,
505
            'afterValidation' => null,
506
        ];
507
        
508
        // run events, as it would normally
509
        foreach ($events as $event => $state) {
510
            $this->skipped = false;
0 ignored issues
show
Bug Best Practice introduced by
The property skipped does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
511
            
512
            // skip depending wether it's a create or update
513
            if (strpos($event, $new ? 'Update' : 'Create') !== false) {
514
                continue;
515
            }
516
            
517
            // fire the event, allowing to fail or skip
518
            $events[$event] = $entity->fireEventCancel($event);
519
            if ($events[$event] === false) {
520
                // event failed
521
                break;
522
            }
523
            
524
            // event was skipped, just for consistencies purpose
525
            if ($this->skipped) {
526
                continue;
527
            }
528
        }
529
        
530
        $this->view->model = get_class($entity);
531
        $this->view->source = $entity->getSource();
532
        $this->view->single = $entity->expose($this->getExpose());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getExpose() targeting Zemit\Mvc\Controller\Rest::getExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
533
        $this->view->messages = $entity->getMessages();
534
        $this->view->events = $events;
535
        $this->view->validated = empty($this->view->messages);
536
        
537
        return $this->setRestResponse($this->view->validated);
0 ignored issues
show
Bug introduced by
$this->view->validated of type boolean is incompatible with the type array|null expected by parameter $response of Zemit\Mvc\Controller\Rest::setRestResponse(). ( Ignorable by Annotation )

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

537
        return $this->setRestResponse(/** @scrutinizer ignore-type */ $this->view->validated);
Loading history...
538
    }
539
    
540
    /**
541
     * Saving a record
542
     * - Create
543
     * - Update
544
     *
545
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
546
     *
547
     * @return array
548
     */
549
    public function saveAction($id = null)
550
    {
551
        $this->view->setVars($this->save($id));
0 ignored issues
show
Bug introduced by
The method setVars() does not exist on Phalcon\Mvc\ViewInterface. Did you maybe mean setVar()? ( Ignorable by Annotation )

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

551
        $this->view->/** @scrutinizer ignore-call */ 
552
                     setVars($this->save($id));

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...
552
        
553
        return $this->setRestResponse($this->view->saved);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->setRestResponse($this->view->saved) returns the type Phalcon\Http\ResponseInterface which is incompatible with the documented return type array.
Loading history...
554
    }
555
    
556
    /**
557
     * Deleting a record
558
     *
559
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
560
     *
561
     * @return bool
562
     */
563
    public function deleteAction($id = null)
564
    {
565
        $single = $this->getSingle($id);
566
        
567
        $this->view->deleted = $single ? $single->delete() : false;
568
        $this->view->single = $single ? $single->expose($this->getExpose()) : false;
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getExpose() targeting Zemit\Mvc\Controller\Rest::getExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
569
        $this->view->messages = $single ? $single->getMessages() : false;
570
        
571
        if (!$single) {
572
            $this->response->setStatusCode(404, 'Not Found');
573
            
574
            return false;
575
        }
576
        
577
        return $this->setRestResponse($this->view->deleted);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->setRestRes...e($this->view->deleted) returns the type Phalcon\Http\ResponseInterface which is incompatible with the documented return type boolean.
Loading history...
Bug introduced by
$this->view->deleted of type boolean is incompatible with the type array|null expected by parameter $response of Zemit\Mvc\Controller\Rest::setRestResponse(). ( Ignorable by Annotation )

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

577
        return $this->setRestResponse(/** @scrutinizer ignore-type */ $this->view->deleted);
Loading history...
578
    }
579
    
580
    /**
581
     * Restoring record
582
     *
583
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
584
     *
585
     * @return bool
586
     */
587
    public function restoreAction($id = null)
588
    {
589
        $single = $this->getSingle($id);
590
        
591
        $this->view->restored = $single ? $single->restore() : false;
0 ignored issues
show
Bug introduced by
The method restore() does not exist on Phalcon\Mvc\Model\Resultset. ( Ignorable by Annotation )

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

591
        $this->view->restored = $single ? $single->/** @scrutinizer ignore-call */ restore() : false;

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...
592
        $this->view->single = $single ? $single->expose($this->getExpose()) : false;
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getExpose() targeting Zemit\Mvc\Controller\Rest::getExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
593
        $this->view->messages = $single ? $single->getMessages() : false;
594
        
595
        if (!$single) {
596
            $this->response->setStatusCode(404, 'Not Found');
597
            
598
            return false;
599
        }
600
        
601
        return $this->setRestResponse($this->view->restored);
0 ignored issues
show
Bug introduced by
It seems like $this->view->restored can also be of type false; however, parameter $response of Zemit\Mvc\Controller\Rest::setRestResponse() does only seem to accept array|null, 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

601
        return $this->setRestResponse(/** @scrutinizer ignore-type */ $this->view->restored);
Loading history...
Bug Best Practice introduced by
The expression return $this->setRestRes...($this->view->restored) returns the type Phalcon\Http\ResponseInterface which is incompatible with the documented return type boolean.
Loading history...
602
    }
603
    
604
    /**
605
     * Re-ordering a position
606
     *
607
     * @param null $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
608
     * @param null $position
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $position is correct as it would always require null to be passed?
Loading history...
609
     *
610
     * @return bool|\Phalcon\Http\ResponseInterface
611
     */
612
    public function reorderAction($id = null)
613
    {
614
        $single = $this->getSingle($id);
615
        
616
        $position = $this->getParam('position', 'int');
617
        
618
        $this->view->reordered = $single ? $single->reorder($position) : false;
0 ignored issues
show
Bug introduced by
The method reorder() does not exist on Phalcon\Mvc\Model\Resultset. ( Ignorable by Annotation )

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

618
        $this->view->reordered = $single ? $single->/** @scrutinizer ignore-call */ reorder($position) : false;

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...
619
        $this->view->single = $single ? $single->expose($this->getExpose()) : false;
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->getExpose() targeting Zemit\Mvc\Controller\Rest::getExpose() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
620
        $this->view->messages = $single ? $single->getMessages() : false;
621
        
622
        if (!$single) {
623
            $this->response->setStatusCode(404, 'Not Found');
624
            
625
            return false;
626
        }
627
        
628
        return $this->setRestResponse($this->view->reordered);
0 ignored issues
show
Bug introduced by
It seems like $this->view->reordered can also be of type false; however, parameter $response of Zemit\Mvc\Controller\Rest::setRestResponse() does only seem to accept array|null, 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

628
        return $this->setRestResponse(/** @scrutinizer ignore-type */ $this->view->reordered);
Loading history...
629
    }
630
    
631
    /**
632
     * Sending an error as an http response
633
     *
634
     * @param null $error
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $error is correct as it would always require null to be passed?
Loading history...
635
     * @param null $response
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $response is correct as it would always require null to be passed?
Loading history...
636
     *
637
     * @return \Phalcon\Http\ResponseInterface
638
     */
639
    public function setRestErrorResponse($code = 400, $status = 'Bad Request', $response = null)
640
    {
641
        return $this->setRestResponse($response, $code, $status);
642
    }
643
    
644
    /**
645
     * Sending rest response as an http response
646
     *
647
     * @param array|null $response
648
     * @param null $status
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $status is correct as it would always require null to be passed?
Loading history...
649
     * @param null $code
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $code is correct as it would always require null to be passed?
Loading history...
650
     * @param int $jsonOptions
651
     * @param int $depth
652
     *
653
     * @return \Phalcon\Http\ResponseInterface
654
     */
655
    public function setRestResponse($response = null, $code = null, $status = null, $jsonOptions = 0, $depth = 512)
656
    {
657
        $debug = $this->config->app->debug ?? false;
0 ignored issues
show
Bug Best Practice introduced by
The property app does not exist on Zemit\Bootstrap\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
658
        
659
        // keep forced status code or set our own
660
        $responseStatusCode = $this->response->getStatusCode();
661
        $reasonPhrase = $this->response->getReasonPhrase();
662
        $status ??= $reasonPhrase ? : 'OK';
663
        $code ??= (int)$responseStatusCode ? : 200;
664
        $view = $this->view->getParamsToView();
665
        $hash = hash('sha512', json_encode($view));
666
        
667
        /**
668
         * Debug section
669
         * - Versions
670
         * - Request
671
         * - Identity
672
         * - Profiler
673
         * - Dispatcher
674
         * - Router
675
         */
676
        $request = $debug ? $this->request->toArray() : null;
0 ignored issues
show
introduced by
The method toArray() does not exist on Phalcon\Http\Request. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

676
        $request = $debug ? $this->request->/** @scrutinizer ignore-call */ toArray() : null;
Loading history...
Bug introduced by
The method toArray() does not exist on Phalcon\Http\RequestInterface. It seems like you code against a sub-type of Phalcon\Http\RequestInterface such as Zemit\Http\Request. ( Ignorable by Annotation )

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

676
        $request = $debug ? $this->request->/** @scrutinizer ignore-call */ toArray() : null;
Loading history...
677
        $identity = $debug ? $this->identity->getIdentity() : null;
678
        $profiler = $debug && $this->profiler ? $this->profiler->toArray() : null;
679
        $dispatcher = $debug ? $this->dispatcher->toArray() : null;
680
        $router = $debug ? $this->router->toArray() : null;
681
        
682
        $api = $debug ? [
683
            'php' => phpversion(),
684
            'phalcon' => Version::get(),
685
            'zemit' => $this->config->core->version,
0 ignored issues
show
Bug Best Practice introduced by
The property core does not exist on Zemit\Bootstrap\Config. Since you implemented __get, consider adding a @property annotation.
Loading history...
686
            'core' => $this->config->core->name,
687
            'app' => $this->config->app->version,
688
            'name' => $this->config->app->name,
689
        ] : [];
690
        $api['version'] = '0.1';
691
        
692
        $this->response->setStatusCode($code, $code . ' ' . $status);
693
        
694
        // @todo handle this correctly
695
        // @todo private vs public cache type
696
        $cache = $this->getCache();
697
        if (!empty($cache['lifetime'])) {
698
            if ($this->response->getStatusCode() === 200) {
699
                $this->response->setCache($cache['lifetime']);
700
                $this->response->setEtag($hash);
701
            }
702
        } else {
703
            $this->response->setCache(0);
704
            $this->response->setHeader('Cache-Control', 'no-cache, max-age=0');
705
        }
706
        
707
        return $this->response->setJsonContent(array_merge([
708
            'api' => $api,
709
            'timestamp' => date('c'),
710
            'hash' => $hash,
711
            'status' => $status,
712
            'code' => $code,
713
            'response' => $response,
714
            'view' => $view,
715
        ], $debug ? [
716
            'identity' => $identity,
717
            'profiler' => $profiler,
718
            'request' => $request,
719
            'dispatcher' => $dispatcher,
720
            'router' => $router,
721
        ] : []), $jsonOptions, $depth);
0 ignored issues
show
Unused Code introduced by
The call to Phalcon\Http\ResponseInterface::setJsonContent() has too many arguments starting with $jsonOptions. ( Ignorable by Annotation )

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

721
        return $this->response->/** @scrutinizer ignore-call */ setJsonContent(array_merge([

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...
722
    }
723
    
724
    /**
725
     * Handle rest response automagically
726
     *
727
     * @param Dispatcher $dispatcher
728
     */
729
    public function afterExecuteRoute(Dispatcher $dispatcher)
730
    {
731
        $response = $dispatcher->getReturnedValue();
732
        
733
        // Avoid breaking default phalcon behaviour
734
        if ($response instanceof Response) {
735
            return;
736
        }
737
        
738
        // Merge response into view variables
739
        if (is_array($response)) {
740
            $this->view->setVars($response, true);
741
        }
742
        
743
        // Return our Rest normalized response
744
        $dispatcher->setReturnedValue($this->setRestResponse(is_array($response) ? null : $response));
745
    }
746
}
747