Completed
Push — master ( 202fc5...08d342 )
by Richard
04:51
created

Engine::run()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 32
Code Lines 24

Duplication

Lines 8
Ratio 25 %

Code Coverage

Tests 20
CRAP Score 5.1158

Importance

Changes 0
Metric Value
dl 8
loc 32
ccs 20
cts 24
cp 0.8333
rs 8.439
c 0
b 0
f 0
cc 5
eloc 24
nc 7
nop 0
crap 5.1158
1
<?php
2
/******************************************************************************
3
 * An implementation of dicto (scg.unibe.ch/dicto) in and for PHP.
4
 * 
5
 * Copyright (c) 2016 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\Indexer\InsertTwice;
14
use Lechimp\Dicto\Indexer\IndexerFactory;
15
use Lechimp\Dicto\Analysis\ReportGenerator;
16
use Lechimp\Dicto\Analysis\AnalyzerFactory;
17
use Lechimp\Dicto\Analysis\Index;
18
use Lechimp\Dicto\Indexer\Insert;
19
use Lechimp\Dicto\Graph;
20
use Psr\Log\LoggerInterface as Log;
21
22
/**
23
 * The Engine of the App drives the analysis process.
24
 */
25
class Engine {
26
    /**
27
     * @var Log
28
     */
29
    protected $log;
30
31
    /**
32
     * @var Config
33
     */
34
    protected $config;
35
36
    /**
37
     * @var DBFactory
38
     */
39
    protected $db_factory;
40
41
    /**
42
     * @var IndexerFactory
43
     */
44
    protected $indexer_factory;
45
46
    /**
47
     * @var AnalyzerFactory
48
     */
49
    protected $analyzer_factory;
50
51
    /**
52
     * @var ReportGenerator
53
     */
54
    protected $report_generator;
55
56
    /**
57
     * @var SourceStatus
58
     */
59
    protected $source_status;
60
61 9
    public function __construct( Log $log
62
                               , Config $config
63
                               , DBFactory $db_factory
64
                               , IndexerFactory $indexer_factory
65
                               , AnalyzerFactory $analyzer_factory
66
                               , ReportGenerator $report_generator
67
                               , SourceStatus $source_status
68
                               ) {
69 9
        $this->log = $log;
70 9
        $this->config = $config;
71 9
        $this->db_factory = $db_factory;
72 9
        $this->indexer_factory = $indexer_factory;
73 9
        $this->analyzer_factory = $analyzer_factory;
74 9
        $this->report_generator = $report_generator;
75 9
        $this->source_status = $source_status;
76 9
    }
77
78
    /**
79
     * Run the analysis.
80
     * 
81
     * @return null
82
     */
83 8
    public function run() {
84 8
        $index_db_path = $this->index_database_path();
85 8
        if (!$this->db_factory->index_db_exists($index_db_path)) {
86 7
            $index = $this->build_index();
87 7
            $this->run_indexing($index);
88 7
            if ($this->config->analysis_store_index()) {
89 1
                $index_db = $index->second();
0 ignored issues
show
Bug introduced by
The method second does only exist in Lechimp\Dicto\Indexer\InsertTwice, but not in Lechimp\Dicto\Graph\IndexDB.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
90 1
                if ($index_db instanceof IndexDB) {
91 1
                    $index_db->write_cached_inserts();
92 1
                }
93
                else {
94
                    throw new \LogicException(
95
                        "Expected index_db to be of type App\IndexDB, but it is '".
96
                        get_class($index_db)."'");
97
                }
98 1
                $index = $index->first();
0 ignored issues
show
Bug introduced by
The method first does only exist in Lechimp\Dicto\Indexer\InsertTwice, but not in Lechimp\Dicto\Graph\IndexDB.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
99 1
            }
100 7
        }
101
        else {
102 1
            $index_db = $this->db_factory->load_index_db($index_db_path);
103 1
            $this->log->notice("Reading index from database '$index_db_path'...");
104 1
            $index = $this->read_index_from($index_db);
105
        }
106 8 View Code Duplication
        if ($index instanceof Graph\IndexDB) {
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...
107 8
            $this->run_analysis($index);
108 8
        }
109
        else {
110
            throw new \LogicException(
111
                "Expected index to be of type Graph\IndexDB, but it is '".
112
                get_class($index)."'");
113
        }
114 8
    }
115
116 8
    protected function index_database_path() {
117 8
        $commit_hash = $this->source_status->commit_hash();
118 8
        return $this->config->project_storage()."/$commit_hash.sqlite";
119
    }
120
121 7
    protected function run_indexing(Insert $index) {
122 7
        $this->log->notice("Building index...");
123 7
        $indexer = $this->indexer_factory->build($index);
124 7
        $this->with_time_measurement
125
            ( function ($s) { return "Indexing took $s seconds to run."; }
126
            , function () use ($indexer) {
127 7
                $indexer->index_directory
128 7
                    ( $this->config->project_root()
129 7
                    , $this->config->analysis_ignore()
130 7
                    );
131 7
            });
132 7
    }
133
134 8
    protected function run_analysis(Index $index) {
135 8
        $this->log->notice("Running analysis...");
136 8
        $commit_hash = $this->source_status->commit_hash();
137 8
        $this->report_generator->begin_run($commit_hash);
138 8
        $analyzer = $this->analyzer_factory->build($index, $this->report_generator);
139 8
        $this->with_time_measurement
140
            ( function ($s) { return "Analysis took $s seconds to run."; }
141
            , function () use ($analyzer) {
142 8
                $analyzer->run();
143 8
            });
144 8
        $this->report_generator->end_run();
145 8
    }
146
147 7
    protected function build_index() {
148 7
        if ($this->config->analysis_store_index()) {
149 1
            $index_db_path = $this->index_database_path();
150 1
            $index_db = $this->db_factory->build_index_db($index_db_path);
151 1
            $this->log->notice("Writing index to database '$index_db_path'...");
152 1
            return new InsertTwice(new Graph\IndexDB, $index_db);
153
        }
154
155 6
        return new Graph\IndexDB;
156
    }
157
158
    /**
159
     * @return  Graph\IndexDB
160
     */
161
    protected function read_index_from(IndexDB $db) {
162
        $index = null;
163
        $this->with_time_measurement
164
            ( function ($s) { return "Loading the index took $s seconds."; }
165
            , function () use ($db, &$index) {
166
                $index = $db->to_graph_index();
167
            });
168 View Code Duplication
        if ($index instanceof Graph\IndexDB) {
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...
169
            return $index;
170
        }
171
        else {
172
            throw new \LogicException(
173
                "Expected index to be of type Graph\IndexDB, but it is '".
174
                get_class($index)."'");
175
        }
176
    }
177
178 8
    protected function with_time_measurement(\Closure $message, \Closure $what) {
179 8
        $start_time = microtime(true);
180 8
        $what();
181 8
        $time_elapsed_secs = microtime(true) - $start_time;
182 8
        $this->log->notice($message($time_elapsed_secs));
183 8
    }
184
}
185