Completed
Pull Request — master (#99)
by Deven
14:25
created

ReportsTable::getRelatedReports()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
ccs 4
cts 4
cp 1
rs 9.4286
cc 1
eloc 3
nc 1
nop 0
crap 1
1
<?php
2
/* vim: set noexpandtab sw=2 ts=2 sts=2: */
3
namespace App\Model\Table;
4
5
use Cake\ORM\Table;
6
use App\Model\AppModel;
7
use Cake\Model\Model;
8
use Cake\Routing\Router;
9
use Cake\ORM\TableRegistry;
10
/**
11
 * Report model representing a group of incidents.
12
 *
13
 * phpMyAdmin Error reporting server
14
 * Copyright (c) phpMyAdmin project (http://www.phpmyadmin.net)
15
 *
16
 * Licensed under The MIT License
17
 * For full copyright and license information, please see the LICENSE.txt
18
 * Redistributions of files must retain the above copyright notice.
19
 *
20
 * @copyright     Copyright (c) phpMyAdmin project (http://www.phpmyadmin.net)
21
 * @package       Server.Model
22
 * @link          http://www.phpmyadmin.net
23
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
24
 */
25
26
27
/**
28
 * A report a representing a group of incidents
29
 *
30
 * @package       Server.Model
31
 */
32
class ReportsTable extends Table {
33
34
    /**
35
 * @var array
36
 * @link http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasmany
37
 * @see Cake::Model::$hasMany
38
 */
39
	public $hasMany = array(
40
		'Incidents' => array(
41
			'dependant' => true
42
		)
43
	);
44
45
/**
46
 * @var Array
47
 * @link http://book.cakephp.org/2.0/en/models/model-attributes.html#validate
48
 * @link 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
 * @see Model::$findMethods
63
 */
64
	public $findMethods = array(
65
		'allDataTable' =>	true,
66
		'arrayList' => true,
67
	);
68
69
/**
70
 * List of valid finder method options, supplied as the first parameter to find().
71
 *
72
 * @var array
73
 */
74
	public $status = array(
75
		'new' =>	'New',
76
		'fixed' =>	'Fixed',
77
		'wontfix' =>	"Won't Fix",
78
		'open' => 	"Open",
79
		'pending' =>	"Pending",
80
		'resolved' =>	"Resolved",
81
		'invalid' => "Invalid",
82
		'duplicate' => "Duplicate",
83
		'works-for-me' => "Works for me",
84
		'out-of-date' => "Out of Date"
85
	);
86
87 1
    public function initialize(array $config)
88
    {
89 1
        $this->hasMany('Incidents', [
90
            'dependent' => true
91 1
        ]);
92 1
    }
93
/**
94
 * Retrieves the incident records that are related to the current report
95
 *
96
 * @return Array the list of incidents ordered by creation date desc
97
 */
98 3
	public function getIncidents() {
99 3
		$incidents = TableRegistry::get('Incidents')->find('all', array(
100 3
			'limit' => 50,
101 3
			'conditions' => $this->_relatedIncidentsConditions(),
102
			'order' => 'Incidents.created desc'
103 3
		));
104 3
        return $incidents;
105
	}
106
107
/**
108
 * Retrieves the report records that are related to the current report
109
 *
110
 * @return Array the list of related reports
111
 */
112 1
	public function getRelatedReports() {
113 1
		return $this->find("all", array(
114 1
			'conditions' => $this->_relatedReportsConditions(),
115 1
		));
116
	}
117
118
/**
119
 * Retrieves the incident records that are related to the current report that
120
 * also have a description
121
 *
122
 * @return Array the list of incidents ordered by description lenght desc
123
 */
124 2
	public function getIncidentsWithDescription() {
125 2
		return TableRegistry::get('Incidents')->find('all', array(
126
			'conditions' => array(
127
				'NOT' => array(
128
					'Incidents.steps is null'
129 2
				),
130 2
				$this->_relatedIncidentsConditions(),
131 2
			),
132
			'order' => 'Incidents.steps desc'
133 2
		));
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 2
	public function getIncidentsWithDifferentStacktrace() {
143 2
		return TableRegistry::get('Incidents')->find('all', array(
144 2
			'fields' => array('DISTINCT Incidents.stackhash', 'Incidents.stacktrace',
145 2
					'Incidents.full_report', 'Incidents.exception_type'),
146 2
			'conditions' => $this->_relatedIncidentsConditions(),
147 2
			'group' => "Incidents.stackhash",
148 2
		));
149
	}
150
151
/**
152
 * Removes a report from a group of related reports
153
 *
154
 * @return void
155
 */
156
	public function removeFromRelatedGroup($report) {
157
		$report->related_to = null;
158
		$this->save($report);
159
160
		$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...
161
		if ($rel_report) {
162
			$this->updateAll(
163
				array("related_to" => $rel_report->id),
164
				array("related_to" => $report->id)
165
			);
166
		}
167
168
		// remove all redundant self-groupings
169
		$this->updateAll(
170
			array("related_to" => null),
171
			array("reports.related_to = reports.id")
172
		);
173
	}
174
175
/**
176
 * Adds a report to a group of related reports
177
 *
178
 * @return void
179
 */
180
	public function addToRelatedGroup($report, $related_to) {
181
		$dup_report = $this->get($related_to);
182
183
		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...
184
			$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...
185
		} else {
186
			$report->related_to = $related_to;
187
		}
188
		$this->save($report);
189
	}
190
191
/**
192
 * Returns the full url to the current report
193
 *
194
 * @return String url
195
 */
196 1
	public function getUrl() {
197 1
		return Router::url(array("controller" => "reports", "action" => "view",
198 1
				$this->id), true);
199
	}
200
201
/**
202
 * groups related incidents by distinct values of a field. It may also provide
203
 * the number of groups, whether to only include incidents that are related
204
 * to the current report and also to only limit the search to incidents
205
 * submited after a certain date
206
 *
207
 * @param String $fieldName the name of the field to group by
208
 * @param Integer $limit the max number of groups to return
209
 * @param Boolean $count whether to return the number of distinct groups
210
 * @param Boolean $related whether to limit the search to only related incidents
211
 * @param Date $timeLimit the date at which to start the search
212
 * @return Array the groups with the count of each group and possibly the number
213
 *		of groups. Ex: array('Apache' => 2) or array(array('Apache' => 2), 1)
214
 */
215 2
	public function getRelatedByField($fieldName, $limit = 10, $count = false,
216
		$related = true, $timeLimit = null) {
217
		$queryDetails = [
218 2
			'fields' => ["$fieldName"],
219
			'conditions' => [
220
				'NOT' => [
221 2
					"Incidents.$fieldName is null"
222 2
				]
223 2
			],
224 2
			'limit' => $limit,
225 2
			'group' => "Incidents.$fieldName"
226 2
		];
227
228 2
		if ($related) {
229 2
			$queryDetails["conditions"][] = $this->_relatedIncidentsConditions();
230 2
		}
231
232 2
		if ($timeLimit) {
233 1
			$queryDetails["conditions"][] = [
234
				'Incidents.created >=' => $timeLimit
235 1
			];
236 1
		}
237
238 2
		$groupedCount = TableRegistry::get('Incidents')->find("all", $queryDetails);
239 2
        $groupedCount->select([
240 2
            'count' => $groupedCount->func()->count('*')
241 2
        ])->distinct(["$fieldName"])->order('count')->toArray();
242
243 2
		if ($count) {
244 2
			$queryDetails['limit'] = null;
245 2
			$totalCount = TableRegistry::get('Incidents')->find("all", $queryDetails)->count();
246 2
			return array($groupedCount, $totalCount);
247
		} else {
248 1
			return $groupedCount;
249
		}
250
	}
251
252
/**
253
 * returns an array of conditions that would return all related incidents to the
254
 * current report
255
 *
256
 * @return Array the related incidents conditions
257
 */
258 6
	protected function _relatedIncidentsConditions() {
259 6
		$conditions = array(array('Incidents.report_id = '.$this->id));
260 6
        $report = $this->get($this->id);
261 6
		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...
262
			$conditions[] = array('Incidents.report_id = '.
263
					$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...
264
		}
265 6
		return array('OR' => $conditions);
266
	}
267
268
/**
269
 * returns an array of conditions that would return all related reports to the
270
 * current report
271
 *
272
 * @return Array the related reports conditions
273
 */
274 1
	protected function _relatedReportsConditions() {
275 1
		$conditions = array(array('related_to' => $this->id));
276 1
        $report = $this->get($this->id);
277 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...
278
			$conditions[] = array('related_to' =>
279
					$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...
280
			$conditions[] = array('id' =>
281
					$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...
282
		}
283 1
		$conditions = array(array('OR' => $conditions));
284 1
		$conditions[] = array("Reports.id !=" => $this->id);
285 1
		return $conditions;
286
	}
287
}
288