Completed
Push — master ( 1e9ef5...3740bc )
by Richard
05:53 queued 29s
created

ResultDB::begin_new_run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 9
nc 1
nop 1
crap 1
1
<?php
2
/******************************************************************************
3
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
4
 *
5
 * Copyright (c) 2016, 2015 Richard Klees <[email protected]>
6
 *
7
 * This software is licensed under The MIT License. You should have received
8
 * a copy of the license along with the code.
9
 */
10
11
namespace Lechimp\Dicto\App;
12
13
use Lechimp\Dicto\Analysis\ReportGenerator;
14
use Lechimp\Dicto\Analysis\Violation;
15
use Lechimp\Dicto\Rules\Ruleset;
16
use Lechimp\Dicto\Rules\Rule;
17
use Lechimp\Dicto\Variables\Variable;
18
use Doctrine\DBAL\Schema;
19
use Doctrine\DBAL\Types\Type;
20
use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer;
21
22
class ResultDB extends DB implements ReportGenerator {
23
    /**
24
     * @var int|null
25
     */
26
    private $current_run_id = null;
27
28
    /**
29
     * @var int|null
30
     */
31
    private $current_rule_id = null;
32
33
    // ReportGenerator implementation
34
35
    /**
36
     * Announce to start a new run of the analysis now.
37
     *
38
     * @param   string  $commit_hash
39
     * @return  null
40
     */
41 14
    public function begin_run($commit_hash) {
42 14
        assert('is_string($commit_hash)');
43 14
        $this->builder()
44 14
            ->insert($this->run_table())
45 14
            ->values(array
46
                ( "commit_hash" => "?"
47 14
                ))
48 14
            ->setParameter(0, $commit_hash)
49 14
            ->execute();
50 14
        $this->current_run_id = (int)$this->connection->lastInsertId();
51 14
    }
52
53
    /**
54
     * @inheritdoc
55
     */
56
    public function end_run() {
57
    }
58
59
    /**
60
     * @inheritdoc
61
     */
62
    public function begin_ruleset(Ruleset $rule) {
63
        // Nothing to do here...
64
    }
65
66
    /**
67
     * @inheritdoc
68
     */
69
    public function end_ruleset() {
70
        // Nothing to do here...
71
    }
72
73
    /**
74
     * @inheritdoc
75
     */
76 12
    public function begin_rule(Rule $rule) {
77 12
        assert('$this->current_run_id !== null');
78 12
        $rule_id = $this->rule_id($rule);
79 12
        if ($rule_id === null) {
80 12
            $this->builder()
81 12
                ->insert($this->rule_table())
82 12
                ->values(array
83
                    ( "rule" => "?"
84 12
                    , "first_seen" => "?"
85 12
                    , "last_seen" => "?"
86 12
                    ))
87 12
                ->setParameter(0, $rule->pprint())
88 12
                ->setParameter(1, $this->current_run_id)
89 12
                ->setParameter(2, $this->current_run_id)
90 12
                ->execute();
91 12
            $rule_id = (int)$this->connection->lastInsertId();
92 12
        }
93 1 View Code Duplication
        else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
94 7
            $this->builder()
95 7
                ->update($this->rule_table())
96 7
                ->set("last_seen", "?")
97 7
                ->where("id = ?")
98 7
                ->setParameter(0, $this->current_run_id)
99 7
                ->setParameter(1, $rule_id)
100 7
                ->execute();
101
        }
102 12
        foreach ($rule->variables() as $variable) {
103 12
            $this->upsert_variable($variable);
104 12
        } 
105 12
        $this->current_rule_id = $rule_id;
106 12
    }
107
108
    /**
109
     * @inheritdoc
110
     */
111
    public function end_rule() {
112
        $this->current_rule_id = null;
113
    }
114
115
    /**
116
     * @inheritdoc
117
     */
118 7
    public function report_violation(Violation $violation) {
119 7
        assert('$this->current_run_id !== null');
120 7
        assert('$this->current_rule_id !== null');
121 7
        $violation_id = $this->violation_id($violation);
122 7
        if ($violation_id === null) {
123 7
            $this->builder()
124 7
                ->insert($this->violation_table())
125 7
                ->values(array
126
                    ( "rule_id" => "?"
127 7
                    , "file" => "?"
128 7
                    , "line" => "?"
129 7
                    , "first_seen" => "?"
130 7
                    , "last_seen" => "?"
131 7
                    ))
132 7
                ->setParameter(0, $this->current_rule_id)
133 7
                ->setParameter(1, $violation->filename())
134 7
                ->setParameter(2, $violation->line())
135 7
                ->setParameter(3, $this->current_run_id)
136 7
                ->setParameter(4, $this->current_run_id)
137 7
                ->execute();
138 7
            $violation_id = (int)$this->connection->lastInsertId();
139 7
        }
140 View Code Duplication
        else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
141 3
            $this->builder()
142 3
                ->update($this->violation_table())
143 3
                ->set("last_seen", "?")
144 3
                ->where("id = ?")
145 3
                ->setParameter(0, $this->current_run_id)
146 3
                ->setParameter(1, $violation_id)
147 3
                ->execute();
148
        }
149
150 7
        $this->builder()
151 7
            ->insert($this->violation_location_table())
152 7
            ->values(array
153
                ( "violation_id" => "?"
154 7
                , "run_id"  => "?"
155 7
                , "line_no" => "?"
156 7
                ))
157 7
            ->setParameter(0, $violation_id)
158 7
            ->setParameter(1, $this->current_run_id)
159 7
            ->setParameter(2, $violation->line_no())
160 7
            ->execute();
161 7
    }
162
163
    // Helpers
164
165
166
    /**
167
     * @param   Rule    $rule
168
     * @return  int|null
169
     */
170 12
    protected function rule_id(Rule $rule) {
171 12
        $res = $this->builder()
172 12
            ->select("id")
173 12
            ->from($this->rule_table())
174 12
            ->where("rule = ?")
175 12
            ->setParameter(0, $rule->pprint())
176 12
            ->execute()
177 12
            ->fetch();
178 12
        if ($res) {
179 7
            return (int)$res["id"];
180
        }
181
        else {
182 12
            return null;
183
        }
184
    }
185
186
    /**
187
     * @param   Variable $var
188
     * @return  int|null
189
     */
190 12 View Code Duplication
    protected function variable_id(Variable $var) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
191 12
        $res = $this->builder()
192 12
            ->select("id")
193 12
            ->from($this->variable_table())
194 12
            ->where($this->builder()->expr()->andX
195 12
                ( "name = ?"
196 12
                , "meaning = ?"
197 12
                ))
198 12
            ->setParameter(0, $var->name())
199 12
            ->setParameter(1, $var->meaning())
200 12
            ->execute()
201 12
            ->fetch();
202 12
        if ($res) {
203 7
            return (int)$res["id"];
204
        }
205
        else {
206 12
            return null;
207
        }
208
    }
209
210 12
    protected function upsert_variable(Variable $var) {
211 12
        $var_id = $this->variable_id($var);
212 12
        if ($var_id === null) {
213 12
            $var_id = $this->insert_variable($var);            
214 12
        }
215
        else {
216 7
            $this->update_variable($var_id);
217
        }
218 12
        return $var_id;
219
    }
220
221 12
    protected function insert_variable(Variable $var) {
222 12
        assert('$this->current_run_id !== null');
223 12
        $this->builder()
224 12
            ->insert($this->variable_table())
225 12
            ->values(array
226
                ( "name" => "?"
227 12
                , "meaning" => "?"
228 12
                , "first_seen" => "?"
229 12
                , "last_seen" => "?"
230 12
                ))
231 12
            ->setParameter(0, $var->name())
232 12
            ->setParameter(1, $var->meaning())
233 12
            ->setParameter(2, $this->current_run_id)
234 12
            ->setParameter(3, $this->current_run_id)
235 12
            ->execute();
236 12
        return (int)$this->connection->lastInsertId();
237
    }
238
239 7
    protected function update_variable($var_id) {
240 7
        assert('is_integer($var_id)');
241 7
        assert('$this->current_run_id !== null');
242 7
        $this->builder()
243 7
            ->update($this->variable_table())
244 7
            ->set("last_seen", "?")
245 7
            ->where("id = ?")
246 7
            ->setParameter(0, $this->current_run_id)
247 7
            ->setParameter(1, $var_id)
248 7
            ->execute();
249 7
    }
250
251
    /**
252
     * @param   Violation   $violation
253
     * @return  int|null
254
     */
255 7 View Code Duplication
    protected function violation_id(Violation $violation) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
256 7
        $res = $this->builder()
257 7
            ->select("id")
258 7
            ->from($this->violation_table())
259 7
            ->where($this->builder()->expr()->andX
260 7
                ( "rule_id = ?"
261 7
                , "file = ?"
262 7
                , "line = ?"
263 7
                ))
264 7
            ->setParameter(0, $this->current_rule_id)
265 7
            ->setParameter(1, $violation->filename())
266 7
            ->setParameter(2, $violation->line())
267 7
            ->execute()
268 7
            ->fetch();
269 7
        if ($res) {
270 3
            return (int)$res["id"];
271
        }
272
        else {
273 7
            return null;
274
        }
275
    }
276
277
    // Names
278
279 17
    public function run_table() {
280 17
        return "runs";    
281
    }
282
283 17
    public function variable_table() {
284 17
        return "variables";
285
    }
286
287 17
    public function rule_table() {
288 17
        return "rules";
289
    }
290
291 17
    public function violation_table() {
292 17
        return "violations";
293
    }
294
295 17
    public function violation_location_table() {
296 17
        return "violation_locations";
297
    }
298
299
    // Creation of database.
300
301 17
    public function init_database_schema() {
302 17
        $schema = new Schema\Schema();
303
304 17
        $run_table = $schema->createTable($this->run_table());
305 17
        $run_table->addColumn
306 17
            ("id", "integer"
307 17
            , array("notnull" => true, "unsigned" => true, "autoincrement" => true)
308 17
            );
309 17
        $run_table->addColumn
310 17
            ( "commit_hash", "string"
311 17
            , array("notnull" => true)
312 17
            );
313
        // TODO: maybe add time
314
        // TODO: do we need some other meta information per run of the analysis? 
315 17
        $run_table->setPrimaryKey(array("id"));
316
317
318 17
        $rule_table = $schema->createTable($this->rule_table());
319 17
        $rule_table->addColumn
320 17
            ( "id", "integer"
321 17
            , array("notnull" => true, "unsigned" => true, "autoincrement" => true)
322 17
            );
323 17
        $rule_table->addColumn
324 17
            ( "rule", "string"
325 17
            , array("notnull" => true)
326 17
            );
327 17
        $rule_table->addColumn
328 17
            ( "first_seen", "integer"
329 17
            , array("notnull" => true)
330 17
            );
331 17
        $rule_table->addColumn
332 17
            ( "last_seen", "integer"
333 17
            , array("notnull" => true)
334 17
            );
335 17
        $rule_table->setPrimaryKey(array("id"));
336 17
        $rule_table->addUniqueIndex(array("rule"));
337 17
        $rule_table->addForeignKeyConstraint
338 17
            ( $run_table
339 17
            , array("first_seen")
340 17
            , array("id")
341 17
            );
342 17
        $rule_table->addForeignKeyConstraint
343 17
            ( $run_table
344 17
            , array("last_seen")
345 17
            , array("id")
346 17
            );
347
348
        
349 17
        $variable_table = $schema->createTable($this->variable_table());
350 17
        $variable_table->addColumn
351 17
            ( "id", "integer"
352 17
            , array("notnull" => true)
353 17
            );
354 17
        $variable_table->addColumn
355 17
            ( "name", "string"
356 17
            , array("notnull" => true)
357 17
            );
358 17
        $variable_table->addColumn
359 17
            ( "meaning", "string"
360 17
            , array("notnull" => true)
361 17
            );
362 17
        $variable_table->addColumn
363 17
            ( "first_seen", "integer"
364 17
            , array("notnull" => true)
365 17
            );
366 17
        $variable_table->addColumn
367 17
            ( "last_seen", "integer"
368 17
            , array("notnull" => true)
369 17
            );
370 17
        $variable_table->setPrimaryKey(array("id"));
371
372
373 17
        $violation_table = $schema->createTable($this->violation_table());
374 17
        $violation_table->addColumn
375 17
            ( "id", "integer"
376 17
            , array("notnull" => true, "unsigned" => true, "autoincrement" => true)
377 17
            );
378 17
        $violation_table->addColumn
379 17
            ( "rule_id", "integer"
380 17
            , array("notnull" => true)
381 17
            );
382 17
        $violation_table->addColumn
383 17
            ( "file", "string"
384 17
            , array("notnull" => true)
385 17
            );
386 17
        $violation_table->addColumn
387 17
            ( "line", "string"
388 17
            , array("notnull" => true)
389 17
            );
390 17
        $violation_table->addColumn
391 17
            ( "first_seen", "integer"
392 17
            , array("notnull" => true)
393 17
            );
394 17
        $violation_table->addColumn
395 17
            ( "last_seen", "integer"
396 17
            , array("notnull" => true)
397 17
            );
398 17
        $violation_table->setPrimaryKey(array("id"));
399 17
        $violation_table->addUniqueIndex(array("rule_id", "file", "line"));
400 17
        $violation_table->addForeignKeyConstraint
401 17
            ( $rule_table
402 17
            , array("rule_id")
403 17
            , array("id")
404 17
            );
405 17
        $violation_table->addForeignKeyConstraint
406 17
            ( $run_table
407 17
            , array("first_seen")
408 17
            , array("id")
409 17
            );
410 17
        $violation_table->addForeignKeyConstraint
411 17
            ( $run_table
412 17
            , array("last_seen")
413 17
            , array("id")
414 17
            );
415
416
417 17
        $violation_location_table = $schema->createTable($this->violation_location_table());
418
419 17
        $violation_location_table->addColumn
420 17
            ( "id", "integer"
421 17
            , array("notnull" => true, "unsigned" => true, "autoincrement" => true)
422 17
            );
423 17
        $violation_location_table->addColumn
424 17
            ( "violation_id", "integer"
425 17
            , array("notnull" => true)
426 17
            );
427 17
        $violation_location_table->addColumn
428 17
            ( "run_id", "integer"
429 17
            , array("notnull" => true)
430 17
            );
431 17
        $violation_location_table->addColumn
432 17
            ( "line_no", "integer"
433 17
            , array("notnull" => true)
434 17
            );
435 17
        $violation_location_table->setPrimaryKey(array("id"));
436 17
        $violation_location_table->addForeignKeyConstraint
437 17
            ( $violation_table
438 17
            , array("violation_id")
439 17
            , array("id")
440 17
            );
441 17
        $violation_location_table->addForeignKeyConstraint
442 17
            ( $run_table
443 17
            , array("run_id")
444 17
            , array("id")
445 17
            );
446
447 17
        $sync = new SingleDatabaseSynchronizer($this->connection);
448 17
        $sync->createSchema($schema);
449 17
    }
450
}
451