Completed
Push — master ( 667317...f33c3d )
by William
09:54
created

getIncidentsWithDifferentStacktrace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
ccs 5
cts 5
cp 1
cc 1
nc 1
nop 0
crap 1
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;
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 method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

This method 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 method will be removed from the class and what other method or class 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;
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', [
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 method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
126
            'conditions' => [
127
                'NOT' => [
128 3
                    '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
Deprecated Code introduced by
The method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
145
            'fields' => [
146 3
                '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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
165 1
        $this->save($report);
166
167 1
        $rel_report = $this->findByRelatedTo($report->id)->first();
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Documentation Bug introduced by
The method findByRelatedTo does not exist on object<App\Model\Table\ReportsTable>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
168 1
        if ($rel_report) {
169
            $this->updateAll(
170
                ['related_to' => $rel_report->id],
171
                ['related_to' => $report->id]
0 ignored issues
show
Bug introduced by
Accessing id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
194
            $report->related_to = $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
195
        } else {
196 1
            $report->related_to = $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
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,
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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $timeLimit of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
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 method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

This method 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 method will be removed from the class and what other method or class 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 4
        switch ($fieldName) {
268 4 View Code Duplication
            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 View Code Duplication
            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 method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

This method 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 method will be removed from the class and what other method or class to use instead.

Loading history...
298
299
            return [
300 3
                $groupedCount,
301 3
                $totalCount,
302
            ];
303
        }
304
305 2
        return $groupedCount;
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],
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
341 1
            $conditions[] = ['Incidents.report_id = ' . $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
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]];
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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
358
            $conditions[] = ['related_to' => $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
359
            $conditions[] = ['id' => $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?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
360
        }
361 2
        $conditions = [['OR' => $conditions]];
362 2
        $conditions[] = ['Reports.id !=' => $this->id];
363
364 2
        return $conditions;
365
    }
366
}
367