Completed
Push — master ( 07e3a8...9561cd )
by William
16:58 queued 14:23
created

ReportsController::view()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 40
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 5.1588

Importance

Changes 0
Metric Value
cc 5
eloc 26
nc 4
nop 1
dl 0
loc 40
ccs 22
cts 27
cp 0.8148
crap 5.1588
rs 9.1928
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * Reports controller handling reports creation and rendering.
5
 *
6
 * phpMyAdmin Error reporting server
7
 * Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
8
 *
9
 * Licensed under The MIT License
10
 * For full copyright and license information, please see the LICENSE.txt
11
 * Redistributions of files must retain the above copyright notice.
12
 *
13
 * @copyright Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
14
 * @license   https://opensource.org/licenses/mit-license.php MIT License
15
 *
16
 * @see      https://www.phpmyadmin.net/
17
 */
18
19
namespace App\Controller;
20
21
use Cake\Core\Configure;
22
use Cake\Http\Exception\NotFoundException;
23
use Cake\Http\Response;
24
use Cake\Log\Log;
25
use Cake\ORM\TableRegistry;
26
use function __;
27
use function array_key_exists;
28
use function array_push;
29
use function array_unshift;
30
use function count;
31
use function json_encode;
32
33
/**
34
 * Reports controller handling reports modification and rendering.
35
 */
36
class ReportsController extends AppController
37
{
38
    /** @var string */
39
    public $components = [
40
        'RequestHandler',
41
        'OrderSearch',
42
    ];
43
44
    /** @var string */
45
    public $helpers = [
46
        'Html',
47
        'Form',
48
        'Reports',
49
        'Incidents',
50
    ];
51
52
    /** @var string */
53
    public $uses = [
54
        'Incidents',
55
        'Reports',
56
        'Notifications',
57
        'Developers',
58
    ];
59
60 4
    public function index(): void
61
    {
62 4
        $this->Reports->recursive = -1;
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
63 4
        $this->set(
64 4
            'distinct_statuses',
65 4
            $this->findArrayList(
66 4
                $this->Reports->find()->select(['status'])->distinct(['status']),
67 4
                'status'
68
            )
69
        );
70 4
        $this->set(
71 4
            'distinct_locations',
72 4
            $this->findArrayList(
73 4
                $this->Reports->find()->select(['location'])
74 4
                    ->distinct(['location']),
75 4
                'location'
76
            )
77
        );
78 4
        $this->set(
79 4
            'distinct_versions',
80 4
            $this->findArrayList($this->Reports->find()->select(['pma_version'])->distinct(['pma_version']), 'pma_version')
81
        );
82 4
        $this->set(
83 4
            'distinct_error_names',
84 4
            $this->findArrayList($this->Reports->find('all', [
85 4
                'fields' => ['error_name'],
86
                'conditions' => ['error_name !=' => ''],
87 4
            ])->distinct(['error_name']), 'error_name')
88
        );
89 4
        $this->set('statuses', $this->Reports->status);
90 4
        $this->autoRender = true;
91 4
    }
92
93 4
    public function view(?string $reportId): void
94
    {
95 4
        if (empty($reportId)) {
96
            throw new NotFoundException(__('Invalid Report'));
97
        }
98 4
        $report = $this->Reports->findById($reportId)->toArray();
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
99 4
        if (! $report) {
100 4
            throw new NotFoundException(__('Invalid Report'));
101
        }
102
103 4
        $this->set('report', $report);
104 4
        $this->set('project_name', Configure::read('GithubRepoPath'));
105 4
        $this->Reports->id = $reportId;
106 4
        $this->set('incidents', $this->Reports->getIncidents()->toArray());
107 4
        $this->set(
108 4
            'incidents_with_description',
109 4
            $this->Reports->getIncidentsWithDescription()
110
        );
111 4
        $this->set(
112 4
            'incidents_with_stacktrace',
113 4
            $this->Reports->getIncidentsWithDifferentStacktrace()
114
        );
115 4
        $this->set('related_reports', $this->Reports->getRelatedReports());
116 4
        $this->set('status', $this->Reports->status);
117 4
        $this->setSimilarFields($reportId);
0 ignored issues
show
Bug introduced by
$reportId of type string is incompatible with the type integer expected by parameter $id of App\Controller\ReportsCo...ler::setSimilarFields(). ( Ignorable by Annotation )

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

117
        $this->setSimilarFields(/** @scrutinizer ignore-type */ $reportId);
Loading history...
118
119
        // if there is an unread notification for this report, then mark it as read
120 4
        $current_developer = TableRegistry::getTableLocator()->get('Developers')->
121 4
                    findById($this->request->getSession()->read('Developer.id'))->all()->first();
122
123 4
        if (! $current_developer || ! $current_developer['Developer']) {
124 4
            return;
125
        }
126
127
        TableRegistry::getTableLocator()->get('Notifications')->deleteAll(
128
            [
129
                'developer_id' => $current_developer['Developer']['id'],
130
                'report_id' => $reportId,
131
            ],
132
            false
0 ignored issues
show
Unused Code introduced by
The call to Cake\ORM\Table::deleteAll() has too many arguments starting with false. ( Ignorable by Annotation )

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

132
        TableRegistry::getTableLocator()->get('Notifications')->/** @scrutinizer ignore-call */ deleteAll(

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...
133
        );
134
    }
135
136 4
    public function data_tables(): ?Response
137
    {
138
        $subquery_params = [
139 2
            'fields' => [
140 2
                'report_id' => 'report_id',
141
                'inci_count' => 'COUNT(id)',
142
            ],
143
            'group' => 'report_id',
144
        ];
145 4
        $subquery = TableRegistry::getTableLocator()->get('incidents')->find('all', $subquery_params);
146
147
        // override automatic aliasing, for proper usage in joins
148
        $aColumns = [
149 4
            'id' => 'id',
150
            'error_name' => 'error_name',
151
            'error_message' => 'error_message',
152
            'location' => 'location',
153
            'pma_version' => 'pma_version',
154
            'status' => 'status',
155
            'exception_type' => 'exception_type',
156
            'inci_count' => 'inci_count',
157
        ];
158
159 4
        $searchConditions = $this->OrderSearch->getSearchConditions($aColumns);
0 ignored issues
show
Bug Best Practice introduced by
The property OrderSearch does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
160 4
        $orderConditions = $this->OrderSearch->getOrder($aColumns);
161
162
        $params = [
163 4
            'fields' => $aColumns,
164
            'conditions' => [
165 4
                $searchConditions,
166 4
                'related_to is NULL',
167
            ],
168 4
            'order' => $orderConditions,
169
        ];
170
171 4
        $pagedParams = $params;
172 4
        $pagedParams['limit'] = (int) $this->request->query('iDisplayLength');
0 ignored issues
show
Deprecated Code introduced by
The function Cake\Http\ServerRequest::query() has been deprecated: 3.4.0 Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead. ( Ignorable by Annotation )

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

172
        $pagedParams['limit'] = (int) /** @scrutinizer ignore-deprecated */ $this->request->query('iDisplayLength');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
173 4
        $pagedParams['offset'] = (int) $this->request->query('iDisplayStart');
0 ignored issues
show
Deprecated Code introduced by
The function Cake\Http\ServerRequest::query() has been deprecated: 3.4.0 Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead. ( Ignorable by Annotation )

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

173
        $pagedParams['offset'] = (int) /** @scrutinizer ignore-deprecated */ $this->request->query('iDisplayStart');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
174
175 4
        $rows = $this->findAllDataTable(
176 4
            $this->Reports->find('all', $pagedParams)->innerJoin(
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
177 4
                ['incidents' => $subquery],
178 4
                ['incidents.report_id = Reports.id']
179
            )
180
        );
181
        //$rows = Sanitize::clean($rows);
182 4
        $totalFiltered = $this->Reports->find('all', $params)->count();
183
184
        // change exception_type from boolean values to strings
185
        // add incident count for related reports
186 4
        $dispRows = [];
187 4
        foreach ($rows as $row) {
188 4
            $row[5] = $this->Reports->status[$row[5]];
189 4
            $row[6] = (int) $row[6] ? 'php' : 'js';
190
            $input_elem = "<input type='checkbox' name='reports[]' value='"
191 4
                . $row[0]
192 4
                . "'/>";
193
194
            $subquery_params_count = [
195 4
                'fields' => ['report_id' => 'report_id'],
196
            ];
197 4
            $subquery_count = TableRegistry::getTableLocator()->get('incidents')->find(
198 4
                'all',
199 2
                $subquery_params_count
200
            );
201
202
            $params_count = [
203 4
                'fields' => ['inci_count' => 'inci_count'],
204
                'conditions' => [
205 4
                    'related_to = ' . $row[0],
206
                ],
207
            ];
208
209 4
            $inci_count_related = $this->Reports->find('all', $params_count)->innerJoin(
210 4
                ['incidents' => $subquery_count],
211 4
                ['incidents.report_id = Reports.related_to']
212 4
            )->count();
213
214 4
            $row[7] += $inci_count_related;
215
216 4
            array_unshift($row, $input_elem);
217 4
            array_push($dispRows, $row);
218
        }
219
220
        $response = [
221 4
            'iTotalRecords' => $this->Reports->find('all')->count(),
222 4
            'iTotalDisplayRecords' => $totalFiltered,
223 4
            'sEcho' => (int) $this->request->query('sEcho'),
0 ignored issues
show
Deprecated Code introduced by
The function Cake\Http\ServerRequest::query() has been deprecated: 3.4.0 Use getQuery() or the PSR-7 getQueryParams() and withQueryParams() methods instead. ( Ignorable by Annotation )

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

223
            'sEcho' => (int) /** @scrutinizer ignore-deprecated */ $this->request->query('sEcho'),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
224 4
            'aaData' => $dispRows,
225
        ];
226 4
        $this->autoRender = false;
227 4
        $this->response->body(json_encode($response));
0 ignored issues
show
Deprecated Code introduced by
The function Cake\Http\Response::body() has been deprecated: 3.4.0 Mutable response methods are deprecated. Use `withBody()`/`withStringBody()` and `getBody()` instead. ( Ignorable by Annotation )

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

227
        /** @scrutinizer ignore-deprecated */ $this->response->body(json_encode($response));

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
228
229 4
        return $this->response;
230
    }
231
232 8
    public function mark_related_to(?string $reportId): void
233
    {
234
        // Only allow POST requests
235 8
        $this->request->allowMethod(['post']);
236
237 8
        $relatedTo = $this->request->getData('related_to');
238 8
        if (! $reportId
239 8
            || ! $relatedTo
240 8
            || $reportId === $relatedTo
241
        ) {
242
            throw new NotFoundException(__('Invalid Report'));
243
        }
244
245 8
        $report = $this->Reports->get($reportId);
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
246 8
        if (! $report) {
247
            throw new NotFoundException(__('Invalid Report'));
248
        }
249
250 8
        $this->Reports->addToRelatedGroup($report, $relatedTo);
251
252 8
        $flash_class = 'alert alert-success';
253 8
        $this->Flash->default(
254
            'This report has been marked the same as #'
255 8
                . $relatedTo,
0 ignored issues
show
Bug introduced by
Are you sure $relatedTo of type array|string 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

255
                . /** @scrutinizer ignore-type */ $relatedTo,
Loading history...
256 8
            ['params' => ['class' => $flash_class]]
257
        );
258 8
        $this->redirect('/reports/view/' . $reportId);
259 8
    }
260
261 4
    public function unmark_related_to(?string $reportId): void
262
    {
263
        // Only allow POST requests
264 4
        $this->request->allowMethod(['post']);
265
266 4
        if (! $reportId) {
267
            throw new NotFoundException(__('Invalid Report'));
268
        }
269
270 4
        $report = $this->Reports->get($reportId);
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
271 4
        if (! $report) {
272
            throw new NotFoundException(__('Invalid Report'));
273
        }
274
275 4
        $this->Reports->removeFromRelatedGroup($report);
276
277 4
        $flash_class = 'alert alert-success';
278 4
        $this->Flash->default(
279 4
            'This report has been marked as different.',
280 4
            ['params' => ['class' => $flash_class]]
281
        );
282 4
        $this->redirect('/reports/view/' . $reportId);
283 4
    }
284
285 4
    public function change_state(?string $reportId): void
286
    {
287 4
        if (! $reportId) {
288
            throw new NotFoundException(__('Invalid Report'));
289
        }
290
291 4
        $report = $this->Reports->get($reportId);
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
292 4
        if (! $report) {
293
            throw new NotFoundException(__('Invalid Report'));
294
        }
295
296 4
        $state = $this->request->data['state'];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead. ( Ignorable by Annotation )

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

296
        $state = /** @scrutinizer ignore-deprecated */ $this->request->data['state'];

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
297 4
        $newState = null;
298
299 4
        if (array_key_exists($state, $this->Reports->status)) {
300 4
            $newState = $this->Reports->status[$state];
301
        }
302 4
        if (! $newState) {
303 4
            throw new NotFoundException(__('Invalid State'));
304
        }
305 4
        $report->status = $state;
306 4
        $this->Reports->save($report);
307
308 4
        $flash_class = 'alert alert-success';
309 4
        $this->Flash->default(
310 4
            'The state has been successfully changed.',
311 4
            ['params' => ['class' => $flash_class]]
312
        );
313 4
        $this->redirect('/reports/view/' . $reportId);
314 4
    }
315
316
    /**
317
     * To carry out mass actions on Reports
318
     * Currently only to change their statuses.
319
     * Can be Extended for other mass operations as well.
320
     * Expects an array of Report Ids as a POST parameter.
321
     *
322
     * @return void Nothing
323
     */
324 4
    public function mass_action(): void
325
    {
326 4
        $flash_class = 'alert alert-error';
327 4
        $state = $this->request->data['state'];
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead. ( Ignorable by Annotation )

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

327
        $state = /** @scrutinizer ignore-deprecated */ $this->request->data['state'];

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
328 4
        $newState = null;
329 4
        if (array_key_exists($state, $this->Reports->status)) {
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
330 4
            $newState = $this->Reports->status[$state];
331
        }
332
333 4
        if (! $newState) {
334 4
            Log::write(
335 4
                'error',
336 4
                'ERRORED: Invalid param "state" in ReportsController::mass_action()',
337 4
                'alert'
338
            );
339 4
            $msg = 'ERROR: Invalid State!!';
340 4
        } elseif (count($this->request->data['reports']) === 0) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead. ( Ignorable by Annotation )

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

340
        } elseif (count(/** @scrutinizer ignore-deprecated */ $this->request->data['reports']) === 0) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
341 4
            $msg = 'No Reports Selected!! Please Select Reports and try again.';
342
        } else {
343
            $msg = "Status has been changed to '"
344 4
                . $this->request->data['state']
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead. ( Ignorable by Annotation )

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

344
                . /** @scrutinizer ignore-deprecated */ $this->request->data['state']

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
345 4
                . "' for selected Reports!";
346 4
            $flash_class = 'alert alert-success';
347 4
            foreach ($this->request->data['reports'] as $report_id) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead. ( Ignorable by Annotation )

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

347
            foreach (/** @scrutinizer ignore-deprecated */ $this->request->data['reports'] as $report_id) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
348 4
                $report = $this->Reports->get($report_id);
349 4
                if (! $report) {
350
                    Log::write(
351
                        'error',
352
                        'ERRORED: Invalid report_id in ReportsController::mass_action()',
353
                        'alert'
354
                    );
355
                    $msg = 'ERROR:Invalid Report ID:' . $report_id;
356
                    $flash_class = 'alert alert-error';
357
                    break;
358
                }
359 4
                $report->status = $state;
360 4
                $this->Reports->save($report);
361
            }
362
        }
363
364 4
        $this->Flash->default(
365 4
            $msg,
366 4
            ['params' => ['class' => $flash_class]]
367
        );
368 4
        $this->redirect('/reports/');
369 4
    }
370
371 4
    protected function setSimilarFields(int $id): void
372
    {
373 4
        $this->Reports->id = $id;
0 ignored issues
show
Bug Best Practice introduced by
The property Reports does not exist on App\Controller\ReportsController. Since you implemented __get, consider adding a @property annotation.
Loading history...
374
375 4
        $this->set('columns', TableRegistry::getTableLocator()->get('Incidents')->summarizableFields);
376 4
        $relatedEntries = [];
377
378 4
        foreach (TableRegistry::getTableLocator()->get('Incidents')->summarizableFields as $field) {
379
            [$entriesWithCount, $totalEntries] =
380 4
                    $this->Reports->getRelatedByField($field, 25, true);
381 4
            $relatedEntries[$field] = $entriesWithCount;
382 4
            $this->set("${field}_distinct_count", $totalEntries);
383
        }
384
        //error_log(json_encode($relatedEntries));
385
        $this->set('related_entries', $relatedEntries);
386
    }
387
388
    /**
389
     * @param array|mixed $results The row
390
     * @param string      $key     The search in the row
391
     * @return array Results
392
     */
393
    protected function findArrayList($results, string $key): array
394
    {
395 4
        $output = [];
396 4
        foreach ($results as $row) {
397 4
            $output[] = $row[$key];
398
        }
399
400 4
        return $output;
401
    }
402
403
    /**
404
     * @param mixed $results
405
     * @return array
406
     */
407
    protected function findAllDataTable($results): array
408
    {
409 4
        $output = [];
410 4
        foreach ($results as $row) {
411 4
            $output_row = [];
412 4
            $row = $row->toArray();
413 4
            foreach ($row as $key => $value) {
414 4
                $output_row[] = $value;
415
            }
416 4
            $output[] = $output_row;
417
        }
418
419 4
        return $output;
420
    }
421
}
422