Completed
Push — master ( c9c188...858b2f )
by Deven
03:01
created

ReportsTable::_relatedReportsConditions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2.0438

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
ccs 7
cts 9
cp 0.7778
rs 9.4285
cc 2
eloc 9
nc 2
nop 0
crap 2.0438
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 = array(
39
        'Incidents' => array(
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 = array(
52
        'error_message' => array(
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 = array(
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 = array(
76
        'new' => 'New',
77
        'fixed' => 'Fixed',
78
        'wontfix' => "Won't Fix",
79
        'open' => 'Open',
80
        'pending' => 'Pending',
81
        'resolved' => 'Resolved',
82
        'invalid' => 'Invalid',
83
        'duplicate' => 'Duplicate',
84
        'works-for-me' => 'Works for me',
85
        'out-of-date' => 'Out of Date',
86
    );
87
88 15
    public function initialize(array $config)
89
    {
90 15
        $this->hasMany('Incidents', array(
91 15
            'dependent' => true,
92
        ));
93 15
    }
94
95
    /**
96
     * Retrieves the incident records that are related to the current report.
97
     *
98
     * @return array the list of incidents ordered by creation date desc
99
     */
100 4
    public function getIncidents()
101
    {
102 4
        $incidents = TableRegistry::get('Incidents')->find('all', array(
103 4
            'limit' => 50,
104 4
            'conditions' => $this->_relatedIncidentsConditions(),
105 4
            'order' => 'Incidents.created desc',
106
        ));
107
108 4
        return $incidents;
109
    }
110
111
    /**
112
     * Retrieves the report records that are related to the current report.
113
     *
114
     * @return array the list of related reports
115
     */
116 1
    public function getRelatedReports()
117
    {
118 1
        return $this->find('all', array(
119 1
            'conditions' => $this->_relatedReportsConditions(),
120
        ));
121
    }
122
123
    /**
124
     * Retrieves the incident records that are related to the current report that
125
     * also have a description.
126
     *
127
     * @return array the list of incidents ordered by description lenght desc
128
     */
129 2
    public function getIncidentsWithDescription()
130
    {
131 2
        return TableRegistry::get('Incidents')->find('all', array(
132 2
            'conditions' => array(
133
                'NOT' => array(
134
                    'Incidents.steps is null',
135
                ),
136 2
                $this->_relatedIncidentsConditions(),
137
            ),
138 2
            'order' => 'Incidents.steps desc',
139
        ));
140
    }
141
142
    /**
143
     * Retrieves the incident records that are related to the current report that
144
     * that have a different stacktrace.
145
     *
146
     * @return array the list of incidents
147
     */
148 2
    public function getIncidentsWithDifferentStacktrace()
149
    {
150 2
        return TableRegistry::get('Incidents')->find('all', array(
151 2
            'fields' => array('DISTINCT Incidents.stackhash', 'Incidents.stacktrace',
152
                    'Incidents.full_report', 'Incidents.exception_type', ),
153 2
            'conditions' => $this->_relatedIncidentsConditions(),
154 2
            'group' => 'Incidents.stackhash',
155
        ));
156
    }
157
158
    /**
159
     * Removes a report from a group of related reports.
160
     *
161
     * @param mixed $report
162
     */
163 1
    public function removeFromRelatedGroup($report)
164
    {
165 1
        $report->related_to = null;
166 1
        $this->save($report);
167
168 1
        $rel_report = $this->findByRelatedTo($report->id)->first();
0 ignored issues
show
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...
169 1
        if ($rel_report) {
170
            $this->updateAll(
171
                array('related_to' => $rel_report->id),
172
                array('related_to' => $report->id)
173
            );
174
        }
175
176
        // remove all redundant self-groupings
177 1
        $this->updateAll(
178 1
            array('related_to' => null),
179 1
            array('reports.related_to = reports.id')
180
        );
181 1
    }
182
183
    /**
184
     * Adds a report to a group of related reports.
185
     *
186
     * @param mixed $report
187
     * @param mixed $related_to
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;
197
        }
198 1
        $this->save($report);
199 1
    }
200
201
    /**
202
     * Returns the full url to the current report.
203
     *
204
     * @return string url
205
     */
206 1
    public function getUrl()
207
    {
208 1
        return Router::url(array('controller' => 'reports', 'action' => 'view',
209 1
                $this->id, ), true);
210
    }
211
212
    /**
213
     * groups related incidents by distinct values of a field. It may also provide
214
     * the number of groups, whether to only include incidents that are related
215
     * to the current report and also to only limit the search to incidents
216
     * submited after a certain date.
217
     *
218
     * @param string $fieldName the name of the field to group by
219
     * @param int    $limit     the max number of groups to return
220
     * @param bool   $count     whether to return the number of distinct groups
221
     * @param bool   $related   whether to limit the search to only related incidents
222
     * @param Date   $timeLimit the date at which to start the search
223
     *
224
     * @return array the groups with the count of each group and possibly the number
225
     *               of groups. Ex: array('Apache' => 2) or array(array('Apache' => 2), 1)
226
     */
227 2
    public function getRelatedByField($fieldName, $limit = 10, $count = false,
228
        $related = true, $timeLimit = null)
229
    {
230 2
        $fieldAlias = "Incidents__$fieldName";
231
        $queryDetails = array(
232
            'conditions' => array(
233
                'NOT' => array(
234 2
                    "Incidents.$fieldName is null",
235
                ),
236
            ),
237 2
            'limit' => $limit,
238
        );
239
240 2
        if ($related) {
241 2
            $queryDetails['conditions'][] = $this->_relatedIncidentsConditions();
242
        }
243
244 2
        if ($timeLimit) {
245 1
            $queryDetails['conditions'][] = array(
246 1
                'Incidents.created >=' => $timeLimit,
247
            );
248
        }
249
250 2
        $groupedCount = TableRegistry::get('Incidents')->find('all', $queryDetails);
251
252
        /* Ommit version number in case of browser and server_software fields.
253
         * In case of browser field, version number is seperated by space,
254
         * for example,'FIREFOX 47', hence split the value using space.
255
         * In case of server_software field, version number is seperated by /
256
         * for example, 'nginx/1.7', hence split the value using /.
257
         * 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
258
         * for how to use Sql functions with cake
259
         */
260
        switch ($fieldName) {
261 2 View Code Duplication
            case 'browser':
262
                // SUBSTRING(browser, 1, LOCATE(' ', Incidents.browser)-1))
263 1
                $field = $groupedCount->func()->substring(array(
264 1
                    $fieldName => 'literal',
265 1
                    '1' => 'literal',
266 1
                    "Locate(' ', Incidents.browser)-1" => 'literal',
267
                    ));
268 1
                break;
269 2 View Code Duplication
            case 'server_software':
270
                // SUBSTRING(server_software, 1, LOCATE('/', Incidents.server_software)-1))
271 1
                $field = $groupedCount->func()->substring(array(
272 1
                    $fieldName => 'literal', '1' => 'literal',
273 1
                    "Locate('/', Incidents.server_software)-1" => 'literal',
274
                    ));
275 1
                break;
276
            default:
277 2
                $field = $fieldName;
278
        }
279 2
        $groupedCount->select(array(
280 2
            'count' => $groupedCount->func()->count('*'),
281 2
            $fieldAlias => $field,
282 2
        ))->group($fieldAlias)->distinct(array("$fieldAlias"))
283 2
          ->order('count')->toArray();
284
285 2
        if ($count) {
286 2
            $queryDetails['fields'] = array("$fieldName");
287 2
            $queryDetails['limit'] = null;
288 2
            $queryDetails['group'] = "Incidents.$fieldName";
289 2
            $totalCount = TableRegistry::get('Incidents')->find('all', $queryDetails)->count();
290
291 2
            return array($groupedCount, $totalCount);
292
        }
293
294 1
        return $groupedCount;
295
    }
296
297
    /**
298
     * returns an array of conditions that would return all related incidents to the
299
     * current report.
300
     *
301
     * @return array the related incidents conditions
302
     */
303 7
    protected function _relatedIncidentsConditions()
304
    {
305
        $conditions = array(
306 7
            array('Incidents.report_id = ' . $this->id),
307
        );
308 7
        $report = $this->get($this->id);
309 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...
310 1
            $conditions[] = array('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...
311
        }
312
313 7
        return array('OR' => $conditions);
314
    }
315
316
    /**
317
     * returns an array of conditions that would return all related reports to the
318
     * current report.
319
     *
320
     * @return array the related reports conditions
321
     */
322 1
    protected function _relatedReportsConditions()
323
    {
324 1
        $conditions = array(array('related_to' => $this->id));
325 1
        $report = $this->get($this->id);
326 1
        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...
327
            $conditions[] = array('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...
328
            $conditions[] = array('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...
329
        }
330 1
        $conditions = array(array('OR' => $conditions));
331 1
        $conditions[] = array('Reports.id !=' => $this->id);
332
333 1
        return $conditions;
334
    }
335
}
336