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