1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Lechimp\Dicto\Report; |
4
|
|
|
|
5
|
|
|
/** |
6
|
|
|
* Queries on the ResultDB. |
7
|
|
|
*/ |
8
|
|
|
class Queries { |
9
|
|
|
/** |
10
|
|
|
* @var ResultDB |
11
|
|
|
*/ |
12
|
|
|
protected $result_db; |
13
|
|
|
|
14
|
|
|
public function __construct(ResultDB $result_db) { |
15
|
|
|
$this->result_db = $result_db; |
16
|
|
|
} |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Get the id of the current run. |
20
|
|
|
* |
21
|
|
|
* @return int |
22
|
|
|
*/ |
23
|
|
|
public function current_run() { |
24
|
|
|
$b = $this->result_db->builder(); |
25
|
|
|
$res = $b |
26
|
|
|
->select("id") |
27
|
|
|
->from("runs") |
28
|
|
|
->orderBy("id", "DESC") |
29
|
|
|
->setMaxResults(1) |
30
|
|
|
->execute() |
31
|
|
|
->fetch(); |
32
|
|
|
if ($res) { |
33
|
|
|
return (int)$res["id"]; |
34
|
|
|
} |
35
|
|
|
throw new \RuntimeException("Result database contains no runs."); |
36
|
|
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Get the id of the previous run. |
40
|
|
|
* |
41
|
|
|
* @return int |
42
|
|
|
*/ |
43
|
|
View Code Duplication |
public function previous_run() { |
|
|
|
|
44
|
|
|
$b = $this->result_db->builder(); |
45
|
|
|
$res = $b |
46
|
|
|
->select("id") |
47
|
|
|
->from("runs") |
48
|
|
|
->orderBy("id", "DESC") |
49
|
|
|
->setMaxResults(2) |
50
|
|
|
->execute(); |
51
|
|
|
// Drop current |
52
|
|
|
$res->fetch(); |
53
|
|
|
$res = $res->fetch(); |
54
|
|
|
if ($res) { |
55
|
|
|
return (int)$res["id"]; |
56
|
|
|
} |
57
|
|
|
throw new \RuntimeException("Result database contains no previous run."); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Get the id of previous run with another commit id as current run. |
62
|
|
|
* |
63
|
|
|
* @return int |
64
|
|
|
*/ |
65
|
|
|
public function previous_run_with_different_commit() { |
66
|
|
|
$cur = $this->current_run(); |
67
|
|
|
$commit_hash = $this->run_info($cur)["commit_hash"]; |
68
|
|
|
$b = $this->result_db->builder(); |
69
|
|
|
$res = $b |
70
|
|
|
->select("id") |
71
|
|
|
->from("runs") |
72
|
|
|
->where("commit_hash <> ?") |
73
|
|
|
->setParameter(0, $commit_hash) |
74
|
|
|
->orderBy("id", "DESC") |
75
|
|
|
->setMaxResults(1) |
76
|
|
|
->execute() |
77
|
|
|
->fetch(); |
78
|
|
|
if ($res) { |
79
|
|
|
return (int)$res["id"]; |
80
|
|
|
} |
81
|
|
|
throw new \RuntimeException("Result database contains previous run with a different commit."); |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Get the id of the last run for a certain commit. |
86
|
|
|
* |
87
|
|
|
* @param string $commit_hash |
88
|
|
|
* @return int|null |
89
|
|
|
*/ |
90
|
|
View Code Duplication |
public function last_run_for($commit_hash) { |
|
|
|
|
91
|
|
|
$b = $this->result_db->builder(); |
92
|
|
|
$res = $b |
93
|
|
|
->select("id") |
94
|
|
|
->from("runs") |
95
|
|
|
->where("commit_hash = ?") |
96
|
|
|
->setParameter(0, $commit_hash) |
97
|
|
|
->orderBy("id", "DESC") |
98
|
|
|
->setMaxResults(1) |
99
|
|
|
->execute() |
100
|
|
|
->fetch(); |
101
|
|
|
if ($res) { |
102
|
|
|
return (int)$res["id"]; |
103
|
|
|
} |
104
|
|
|
throw new \RuntimeException("Result database contains no runs."); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Get information about a run. |
109
|
|
|
* |
110
|
|
|
* @param int $run |
111
|
|
|
* @return array<string,string> with keys 'commit_hash' |
112
|
|
|
*/ |
113
|
|
View Code Duplication |
public function run_info($run) { |
|
|
|
|
114
|
|
|
$b = $this->result_db->builder(); |
115
|
|
|
$res = $b |
116
|
|
|
->select("commit_hash") |
117
|
|
|
->from("runs") |
118
|
|
|
->where("id = ?") |
119
|
|
|
->setParameter(0, $run) |
120
|
|
|
->execute() |
121
|
|
|
->fetch(); |
122
|
|
|
if ($res) { |
123
|
|
|
return $res; |
124
|
|
|
} |
125
|
|
|
throw new \RuntimeException("Result database contains no run with id '$run'."); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Get the amount of violations in a run. |
130
|
|
|
* |
131
|
|
|
* @param int $run |
132
|
|
|
* @param int|null $rule |
133
|
|
|
* @return int |
134
|
|
|
*/ |
135
|
|
|
public function count_violations_in($run, $rule = null) { |
136
|
|
|
$b = $this->result_db->builder(); |
137
|
|
|
$q = $b |
138
|
|
|
->select("COUNT(*) cnt") |
139
|
|
|
->from("runs", "rs") |
140
|
|
|
->innerJoin("rs", "violations", "vs", |
141
|
|
|
"rs.id >= vs.first_seen AND rs.id <= vs.last_seen") |
142
|
|
|
->innerJoin("vs", "violation_locations", "vls", |
143
|
|
|
"vs.id = vls.violation_id AND rs.id = vls.run_id") |
144
|
|
|
->where("rs.id = ?") |
145
|
|
|
->setParameter(0, $run); |
146
|
|
|
if ($rule !== null) { |
147
|
|
|
$q = $q |
148
|
|
|
->andWhere("vs.rule_id = ?") |
149
|
|
|
->setParameter(1, $rule); |
150
|
|
|
} |
151
|
|
|
$res = $q |
152
|
|
|
->execute() |
153
|
|
|
->fetch(); |
154
|
|
|
if ($res) { |
155
|
|
|
return (int)$res["cnt"]; |
156
|
|
|
} |
157
|
|
|
throw new \RuntimeException("Result database contains no run with id '$run'."); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* Get the amount of violations that were added in a run. |
162
|
|
|
* |
163
|
|
|
* @param int $run_former |
164
|
|
|
* @param int $run_latter |
165
|
|
|
* @param int|null $rule |
166
|
|
|
* @return int |
167
|
|
|
*/ |
168
|
|
View Code Duplication |
public function count_added_violations($run_former, $run_latter, $rule = null) { |
|
|
|
|
169
|
|
|
$b = $this->result_db->builder(); |
170
|
|
|
$q = $b |
171
|
|
|
->select( |
172
|
|
|
"(SELECT COUNT (*) ". |
173
|
|
|
"FROM violation_locations vls ". |
174
|
|
|
"WHERE vls.run_id = :former AND vls.violation_id = vs.id) cnt_former") |
175
|
|
|
->addSelect( |
176
|
|
|
"(SELECT COUNT (*) ". |
177
|
|
|
"FROM violation_locations vls ". |
178
|
|
|
"WHERE vls.run_id = :latter AND vls.violation_id = vs.id) cnt_latter") |
179
|
|
|
->from("violations", "vs") |
180
|
|
|
->where("cnt_former < cnt_latter") |
181
|
|
|
->setParameter("former", $run_former) |
182
|
|
|
->setParameter("latter", $run_latter); |
183
|
|
|
if ($rule !== null) { |
184
|
|
|
$q = $q |
185
|
|
|
->andWhere("vs.rule_id = :rule") |
186
|
|
|
->setParameter("rule", $rule); |
187
|
|
|
} |
188
|
|
|
$rows = $q->execute(); |
189
|
|
|
$res = 0; |
190
|
|
|
while($r = $rows->fetch()) { |
191
|
|
|
if ((int)$r["cnt_latter"] > (int)$r["cnt_former"]) { |
192
|
|
|
$res += (int)$r["cnt_latter"] - (int)$r["cnt_former"]; |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
return $res; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Get the amount of violations that were resolved in a run. |
200
|
|
|
* |
201
|
|
|
* @param int $run_former |
202
|
|
|
* @param int $run_latter |
203
|
|
|
* @param int|null $rule |
204
|
|
|
* @return int |
205
|
|
|
*/ |
206
|
|
View Code Duplication |
public function count_resolved_violations($run_former, $run_latter, $rule = null) { |
|
|
|
|
207
|
|
|
$b = $this->result_db->builder(); |
208
|
|
|
$q = $b |
209
|
|
|
->select( |
210
|
|
|
"(SELECT COUNT (*) ". |
211
|
|
|
"FROM violation_locations vls ". |
212
|
|
|
"WHERE vls.run_id = :former AND vls.violation_id = vs.id) cnt_former") |
213
|
|
|
->addSelect( |
214
|
|
|
"(SELECT COUNT (*) ". |
215
|
|
|
"FROM violation_locations vls ". |
216
|
|
|
"WHERE vls.run_id = :latter AND vls.violation_id = vs.id) cnt_latter") |
217
|
|
|
->from("violations", "vs") |
218
|
|
|
->where("cnt_former > cnt_latter") |
219
|
|
|
->setParameter("former", $run_former) |
220
|
|
|
->setParameter("latter", $run_latter); |
221
|
|
|
if ($rule !== null) { |
222
|
|
|
$q = $q |
223
|
|
|
->andWhere("vs.rule_id = :rule") |
224
|
|
|
->setParameter("rule", $rule); |
225
|
|
|
} |
226
|
|
|
$rows = $q->execute(); |
227
|
|
|
$res = 0; |
228
|
|
|
while($r = $rows->fetch()) { |
229
|
|
|
if ((int)$r["cnt_former"] > (int)$r["cnt_latter"]) { |
230
|
|
|
$res += (int)$r["cnt_former"] - (int)$r["cnt_latter"]; |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
return $res; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
/** |
237
|
|
|
* Get the rules that were analyzed in a run. |
238
|
|
|
* |
239
|
|
|
* @param int $run |
240
|
|
|
* @return int[] |
241
|
|
|
*/ |
242
|
|
View Code Duplication |
public function analyzed_rules($run) { |
|
|
|
|
243
|
|
|
$b = $this->result_db->builder(); |
244
|
|
|
$res = $b |
245
|
|
|
->select("rrs.id") |
246
|
|
|
->from("runs", "rs") |
247
|
|
|
->innerJoin("rs", "rules", "rrs", |
248
|
|
|
"rs.id >= rrs.first_seen AND rs.id <= rrs.last_seen") |
249
|
|
|
->where("rs.id = ?") |
250
|
|
|
->setParameter(0, $run) |
251
|
|
|
->execute() |
252
|
|
|
->fetchAll(); |
253
|
|
|
return array_map(function($r) { return $r["id"]; }, $res); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
/** |
257
|
|
|
* Get information about a rule. |
258
|
|
|
* |
259
|
|
|
* @param int $rule |
260
|
|
|
* @return array<string,string> with keys 'rule', 'explanation' |
261
|
|
|
*/ |
262
|
|
View Code Duplication |
public function rule_info($rule) { |
|
|
|
|
263
|
|
|
$b = $this->result_db->builder(); |
264
|
|
|
$res = $b |
265
|
|
|
->select("rule", "explanation") |
266
|
|
|
->from("rules") |
267
|
|
|
->where("rules.id = ?") |
268
|
|
|
->setParameter(0, $rule) |
269
|
|
|
->execute() |
270
|
|
|
->fetch(); |
271
|
|
|
if ($res) { |
272
|
|
|
return $res; |
273
|
|
|
} |
274
|
|
|
throw new \RuntimeException("Result database contains no rule with id '$rule'."); |
275
|
|
|
} |
276
|
|
|
|
277
|
|
|
/** |
278
|
|
|
* Get the violations of a rule. |
279
|
|
|
* |
280
|
|
|
* @param int $rule |
281
|
|
|
* @param int $run |
282
|
|
|
* @return array<string,string|int>[] with keys 'file', 'line_no', 'introduced_in' |
|
|
|
|
283
|
|
|
*/ |
284
|
|
|
public function violations_of($rule, $run) { |
285
|
|
|
$b = $this->result_db->builder(); |
286
|
|
|
return $b |
287
|
|
|
->select("vs.file", "vls.line_no", "vs.first_seen introduced_in") |
288
|
|
|
->from("runs", "rs") |
289
|
|
|
->innerJoin("rs", "violations", "vs", |
290
|
|
|
"rs.id >= vs.first_seen AND rs.id <= vs.last_seen") |
291
|
|
|
->innerJoin("vs", "violation_locations", "vls", |
292
|
|
|
"vs.id = vls.violation_id AND rs.id = vls.run_id") |
293
|
|
|
->where("rs.id = ?") |
294
|
|
|
->andWhere("vs.rule_id = ?") |
295
|
|
|
->setParameter(0, $run) |
296
|
|
|
->setParameter(1, $rule) |
297
|
|
|
->execute() |
298
|
|
|
->fetchAll(); |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.