Completed
Push — master ( bc825a...1aba9a )
by William
06:03
created

ReportsTable::getIncidents()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* vim: set expandtab sw=4 ts=4 sts=4: */
4
/**
5
 * Report model representing a group of incidents.
6
 *
7
 * phpMyAdmin Error reporting server
8
 * Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
9
 *
10
 * Licensed under The MIT License
11
 * For full copyright and license information, please see the LICENSE.txt
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @copyright Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
15
 * @license   https://opensource.org/licenses/mit-license.php MIT License
16
 *
17
 * @see      https://www.phpmyadmin.net/
18
 */
19
20
namespace App\Model\Table;
21
22
use Cake\Model\Model;
0 ignored issues
show
Bug introduced by
The type Cake\Model\Model was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use Cake\ORM\Table;
24
use Cake\ORM\TableRegistry;
25
use Cake\Routing\Router;
26
27
/**
28
 * A report a representing a group of incidents.
29
 */
30
class ReportsTable extends Table
31
{
32
    /**
33
     * @var array
34
     *
35
     * @see http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany
36
     * @see Cake::Model::$hasMany
37
     */
38
    public $hasMany = [
39
        'Incidents' => [
40
            'dependant' => true,
41
        ],
42
    ];
43
44
    /**
45
     * @var array
46
     *
47
     * @see http://book.cakephp.org/2.0/en/models/model-attributes.html#validate
48
     * @see http://book.cakephp.org/2.0/en/models/data-validation.html
49
     * @see Model::$validate
50
     */
51
    public $validate = [
52
        'error_message' => [
53
            'rule' => 'notEmpty',
54
            'required' => true,
55
        ],
56
    ];
57
58
    /**
59
     * List of valid finder method options, supplied as the first parameter to find().
60
     *
61
     * @var array
62
     *
63
     * @see Model::$findMethods
64
     */
65
    public $findMethods = [
66
        'allDataTable' => true,
67
        'arrayList' => true,
68
    ];
69
70
    /**
71
     * List of valid finder method options, supplied as the first parameter to find().
72
     *
73
     * @var array
74
     */
75
    public $status = [
76
        'new' => 'New',
77
        'invalid' => 'Invalid',
78
        'resolved' => 'Resolved',
79
        'forwarded' => 'Forwarded',
80
    ];
81
82 25
    public function initialize(array $config)
83
    {
84 25
        $this->hasMany('Incidents', [
85 25
            'dependent' => true,
86
        ]);
87 25
    }
88
89
    /**
90
     * Retrieves the incident records that are related to the current report.
91
     *
92
     * @return array the list of incidents ordered by creation date desc
93
     */
94 4
    public function getIncidents()
95
    {
96 4
        $incidents = TableRegistry::get('Incidents')->find('all', [
0 ignored issues
show
Deprecated Code introduced by
The function Cake\ORM\TableRegistry::get() has been deprecated: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead. ( Ignorable by Annotation )

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

96
        $incidents = /** @scrutinizer ignore-deprecated */ TableRegistry::get('Incidents')->find('all', [

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...
97 4
            'limit' => 50,
98 4
            'conditions' => $this->_relatedIncidentsConditions(),
99 4
            'order' => 'Incidents.created desc',
100
        ]);
101
102 4
        return $incidents;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $incidents returns the type Cake\ORM\Query which is incompatible with the documented return type array.
Loading history...
103
    }
104
105
    /**
106
     * Retrieves the report records that are related to the current report.
107
     *
108
     * @return array the list of related reports
109
     */
110 2
    public function getRelatedReports()
111
    {
112 2
        return $this->find('all', [
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->find('all'...edReportsConditions())) returns the type Cake\ORM\Query which is incompatible with the documented return type array.
Loading history...
113 2
            'conditions' => $this->_relatedReportsConditions(),
114
        ]);
115
    }
116
117
    /**
118
     * Retrieves the incident records that are related to the current report that
119
     * also have a description.
120
     *
121
     * @return array the list of incidents ordered by description lenght desc
122
     */
123 3
    public function getIncidentsWithDescription()
124
    {
125 3
        return TableRegistry::get('Incidents')->find('all', [
0 ignored issues
show
Deprecated Code introduced by
The function Cake\ORM\TableRegistry::get() has been deprecated: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead. ( Ignorable by Annotation )

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

125
        return /** @scrutinizer ignore-deprecated */ TableRegistry::get('Incidents')->find('all', [

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...
Bug Best Practice introduced by
The expression return Cake\ORM\TableReg...Incidents.steps desc')) returns the type Cake\ORM\Query which is incompatible with the documented return type array.
Loading history...
126 3
            'conditions' => [
127
                'NOT' => [
128
                    'Incidents.steps is null',
129
                ],
130 3
                $this->_relatedIncidentsConditions(),
131
            ],
132 3
            'order' => 'Incidents.steps desc',
133
        ]);
134
    }
135
136
    /**
137
     * Retrieves the incident records that are related to the current report that
138
     * that have a different stacktrace.
139
     *
140
     * @return array the list of incidents
141
     */
142 3
    public function getIncidentsWithDifferentStacktrace()
143
    {
144 3
        return TableRegistry::get('Incidents')->find('all', [
0 ignored issues
show
Bug Best Practice introduced by
The expression return Cake\ORM\TableReg...'Incidents.stackhash')) returns the type Cake\ORM\Query which is incompatible with the documented return type array.
Loading history...
Deprecated Code introduced by
The function Cake\ORM\TableRegistry::get() has been deprecated: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead. ( Ignorable by Annotation )

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

144
        return /** @scrutinizer ignore-deprecated */ TableRegistry::get('Incidents')->find('all', [

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...
145 3
            'fields' => [
146
                'DISTINCT Incidents.stackhash',
147
                'Incidents.stacktrace',
148
                'Incidents.full_report',
149
                'Incidents.exception_type',
150
            ],
151 3
            'conditions' => $this->_relatedIncidentsConditions(),
152 3
            'group' => 'Incidents.stackhash',
153
        ]);
154
    }
155
156
    /**
157
     * Removes a report from a group of related reports.
158
     *
159
     * @param \Cake\Datasource\EntityInterface $report The report instance
160
     * @return void
161
     */
162 1
    public function removeFromRelatedGroup($report)
163
    {
164 1
        $report->related_to = null;
0 ignored issues
show
Bug introduced by
Accessing related_to on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
165 1
        $this->save($report);
166
167 1
        $rel_report = $this->findByRelatedTo($report->id)->first();
0 ignored issues
show
Bug introduced by
The method findByRelatedTo() does not exist on App\Model\Table\ReportsTable. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

167
        $rel_report = $this->/** @scrutinizer ignore-call */ findByRelatedTo($report->id)->first();
Loading history...
168 1
        if ($rel_report) {
169
            $this->updateAll(
170
                ['related_to' => $rel_report->id],
171
                ['related_to' => $report->id]
172
            );
173
        }
174
175
        // remove all redundant self-groupings
176 1
        $this->updateAll(
177 1
            ['related_to' => null],
178 1
            ['reports.related_to = reports.id']
179
        );
180 1
    }
181
182
    /**
183
     * Adds a report to a group of related reports.
184
     *
185
     * @param \Cake\Datasource\EntityInterface $report     The report instance
186
     * @param int                              $related_to The report Id
187
     * @return void
188
     */
189 1
    public function addToRelatedGroup($report, $related_to)
190
    {
191 1
        $dup_report = $this->get($related_to);
192
193 1
        if ($dup_report && $dup_report->related_to) {
0 ignored issues
show
Bug introduced by
Accessing related_to on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
194
            $report->related_to = $dup_report->related_to;
195
        } else {
196 1
            $report->related_to = $related_to;
197
        }
198 1
        $report->status = $dup_report->status;
0 ignored issues
show
Bug introduced by
Accessing status on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
199
200 1
        $this->save($report);
201 1
    }
202
203
    /**
204
     * Returns the full url to the current report.
205
     *
206
     * @return string url
207
     */
208 1
    public function getUrl()
209
    {
210 1
        return Router::url(['controller' => 'reports', 'action' => 'view',
211 1
            $this->id,
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on App\Model\Table\ReportsTable. Since you implemented __get, consider adding a @property annotation.
Loading history...
212 1
        ], true);
213
    }
214
215
    /**
216
     * groups related incidents by distinct values of a field. It may also provide
217
     * the number of groups, whether to only include incidents that are related
218
     * to the current report and also to only limit the search to incidents
219
     * submited after a certain date.
220
     *
221
     * @param string $fieldName the name of the field to group by
222
     * @param int    $limit     the max number of groups to return
223
     * @param bool   $count     whether to return the number of distinct groups
224
     * @param bool   $related   whether to limit the search to only related incidents
225
     * @param string $timeLimit the date at which to start the search
226
     *
227
     * @return array the groups with the count of each group and possibly the number
228
     *               of groups. Ex: array('Apache' => 2) or array(array('Apache' => 2), 1)
229
     */
230 4
    public function getRelatedByField(
231
        $fieldName,
232
        $limit = 10,
233
        $count = false,
234
        $related = true,
235
        $timeLimit = null
236
    ) {
237 4
        $fieldAlias = "Incidents__$fieldName";
238
        $queryDetails = [
239
            'conditions' => [
240
                'NOT' => [
241 4
                    "Incidents.$fieldName is null",
242
                ],
243
            ],
244 4
            'limit' => $limit,
245
        ];
246
247 4
        if ($related) {
248 3
            $queryDetails['conditions'][] = $this->_relatedIncidentsConditions();
249
        }
250
251 4
        if ($timeLimit) {
252 2
            $queryDetails['conditions'][] = [
253 2
                'Incidents.created >=' => $timeLimit,
254
            ];
255
        }
256
257 4
        $groupedCount = TableRegistry::get('Incidents')->find('all', $queryDetails);
0 ignored issues
show
Deprecated Code introduced by
The function Cake\ORM\TableRegistry::get() has been deprecated: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead. ( Ignorable by Annotation )

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

257
        $groupedCount = /** @scrutinizer ignore-deprecated */ TableRegistry::get('Incidents')->find('all', $queryDetails);

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...
258
259
        /* Ommit version number in case of browser and server_software fields.
260
         * In case of browser field, version number is seperated by space,
261
         * for example,'FIREFOX 47', hence split the value using space.
262
         * In case of server_software field, version number is seperated by /
263
         * for example, 'nginx/1.7', hence split the value using /.
264
         * See http://book.cakephp.org/3.0/en/orm/query-builder.html#using-sql-functionsp://book.cakephp.org/3.0/en/orm/query-builder.html#using-sql-functions
265
         * for how to use Sql functions with cake
266
         */
267
        switch ($fieldName) {
268 4
            case 'browser':
269
                // SUBSTRING(browser, 1, LOCATE(' ', Incidents.browser)-1))
270 3
                $field = $groupedCount->func()->substring([
271 3
                    $fieldName => 'literal',
272 3
                    '1' => 'literal',
273 3
                    "Locate(' ', Incidents.browser)-1" => 'literal',
274
                ]);
275 3
                break;
276 4
            case 'server_software':
277
                // SUBSTRING(server_software, 1, LOCATE('/', Incidents.server_software)-1))
278 3
                $field = $groupedCount->func()->substring([
279 3
                    $fieldName => 'literal',
280 3
                    '1' => 'literal',
281 3
                    "Locate('/', Incidents.server_software)-1" => 'literal',
282
                ]);
283 3
                break;
284
            default:
285 4
                $field = $fieldName;
286
        }
287 4
        $groupedCount->select([
288 4
            'count' => $groupedCount->func()->count('*'),
289 4
            $fieldAlias => $field,
290 4
        ])->group($fieldAlias)->distinct(["$fieldAlias"])
291 4
          ->order('count')->toArray();
292
293 4
        if ($count) {
294 3
            $queryDetails['fields'] = ["$fieldName"];
295 3
            $queryDetails['limit'] = null;
296 3
            $queryDetails['group'] = "Incidents.$fieldName";
297 3
            $totalCount = TableRegistry::get('Incidents')->find('all', $queryDetails)->count();
0 ignored issues
show
Deprecated Code introduced by
The function Cake\ORM\TableRegistry::get() has been deprecated: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead. ( Ignorable by Annotation )

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

297
            $totalCount = /** @scrutinizer ignore-deprecated */ TableRegistry::get('Incidents')->find('all', $queryDetails)->count();

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...
298
299
            return [
300 3
                $groupedCount,
301 3
                $totalCount,
302
            ];
303
        }
304
305 2
        return $groupedCount;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $groupedCount returns the type Cake\ORM\Query which is incompatible with the documented return type array.
Loading history...
306
    }
307
308
    /**
309
     * Updates the linked reports to a Github issue to newly received status
310
     *
311
     * @param string $issueNumber Github Issue number
312
     * @param string $status      New status to be set
313
     *
314
     * @return int Number of Linked reports updated
315
     */
316 1
    public function setLinkedReportStatus($issueNumber, $status)
317
    {
318
        $conditions = [
319 1
            'sourceforge_bug_id' =>  $issueNumber,
320
        ];
321
        $fields = [
322 1
            'status' => $status,
323
        ];
324
325 1
        return $this->updateAll($fields, $conditions);
326
    }
327
328
    /**
329
     * returns an array of conditions that would return all related incidents to the
330
     * current report.
331
     *
332
     * @return array the related incidents conditions
333
     */
334 7
    protected function _relatedIncidentsConditions()
335
    {
336
        $conditions = [
337 7
            ['Incidents.report_id = ' . $this->id],
0 ignored issues
show
Bug introduced by
Are you sure $this->id of type Cake\ORM\Association can be used in concatenation? Consider adding a __toString()-method. ( Ignorable by Annotation )

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

337
            ['Incidents.report_id = ' . /** @scrutinizer ignore-type */ $this->id],
Loading history...
Bug Best Practice introduced by
The property id does not exist on App\Model\Table\ReportsTable. Since you implemented __get, consider adding a @property annotation.
Loading history...
338
        ];
339 7
        $report = $this->get($this->id);
340 7
        if ($report->related_to) { //TODO: fix when fix related reports
0 ignored issues
show
Bug introduced by
Accessing related_to on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
341 1
            $conditions[] = ['Incidents.report_id = ' . $report->related_to];
342
        }
343
344 7
        return ['OR' => $conditions];
345
    }
346
347
    /**
348
     * returns an array of conditions that would return all related reports to the
349
     * current report.
350
     *
351
     * @return array the related reports conditions
352
     */
353 2
    protected function _relatedReportsConditions()
354
    {
355 2
        $conditions = [['related_to' => $this->id]];
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on App\Model\Table\ReportsTable. Since you implemented __get, consider adding a @property annotation.
Loading history...
356 2
        $report = $this->get($this->id);
357 2
        if ($report->related_to) { //TODO: fix related to
0 ignored issues
show
Bug introduced by
Accessing related_to on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
358
            $conditions[] = ['related_to' => $report->related_to];
359
            $conditions[] = ['id' => $report->related_to];
360
        }
361 2
        $conditions = [['OR' => $conditions]];
362 2
        $conditions[] = ['Reports.id !=' => $this->id];
363
364 2
        return $conditions;
365
    }
366
}
367