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

IndexDB::init_table()   C

Complexity

Conditions 21
Paths 198

Size

Total Lines 69
Code Lines 54

Duplication

Lines 12
Ratio 17.39 %

Code Coverage

Tests 56
CRAP Score 21.6047

Importance

Changes 0
Metric Value
dl 12
loc 69
ccs 56
cts 63
cp 0.8889
rs 5.1708
c 0
b 0
f 0
cc 21
eloc 54
nc 198
nop 4
crap 21.6047

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Graph;
14
use Lechimp\Dicto\Indexer\Insert;
15
use Doctrine\DBAL\Schema;
16
use Doctrine\DBAL\Types\Type;
17
use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer;
18
use Doctrine\DBAL\Statement;
19
20
class IndexDB extends DB implements Insert {
21
    protected $nodes_per_insert = 200;
22
23
    /**
24
     * @var array
25
     */
26
    protected $tables =
27
        [ "files" => ["_file",
28
            ["id", "path", "source"]]
29
        , "namespaces" => ["_namespace",
30
            ["id", "name"]]
31
        , "classes" => ["_class",
32
            ["id", "name", "file_id", "start_line", "end_line", "namespace_id"]]
33
        , "interfaces" => ["_interface",
34
            ["id", "name", "file_id", "start_line", "end_line", "namespace_id"]]
35
        , "traits" => ["_trait",
36
            ["id", "name", "file_id", "start_line", "end_line", "namespace_id"]]
37
        , "methods" => ["_method",
38
            ["id", "name", "class_id", "file_id", "start_line", "end_line"]]
39
        , "functions" => ["_function",
40
            ["id", "name", "file_id", "start_line", "end_line", "namespace_id"]]
41
        , "globals" => ["_global",
42
            ["id", "name"]]
43
        , "language_constructs" => ["_language_construct",
44
            ["id", "name"]]
45
        , "method_references" => ["_method_reference",
46
            ["id", "name", "file_id", "line", "column"]]
47
        , "function_references" => ["_function_reference",
48
            ["id", "name", "file_id", "line", "column"]]
49
        , "relations" => ["_relation",
50
            ["left_id", "relation", "right_id", "file_id", "line"]]
51
        ];
52
53
    /**
54
     * Lists of fields that contain an id.
55
     *
56
     * @var array<string,int>
57
     */
58
    protected $id_fields =
59
        [ "file_id" => 0
60
        , "namespace_id" => 0
61
        , "class_id" => 0
62
        , "left_id" => 0
63
        , "right_id" => 0
64
        ];
65
66
    /**
67
     * List of all fields that contain an integer.
68
     *
69
     * @var array<string,0>
70
     */
71
    protected $int_fields =
72
        [ "start_line" => 0
73
        , "end_line" => 0
74
        , "line" => 0
75
        , "column" => 0
76
        ];
77
78
    /**
79
     * @var array[]
80
     */
81
    protected $caches = [];
82
83
    /**
84
     * @var integer
85
     */
86
    protected $id_counter = 0;
87
88 1
    public function __construct($connection) {
89 1
        parent::__construct($connection);
90 1
        foreach ($this->tables as $table => $_) {
91 1
            $this->caches[$table] = [];
92 1
        }
93 1
    }
94
95
    /**
96
     * @inheritdocs
97
     */
98 1
    public function _file($path, $source) {
99 1
        return $this->append_and_maybe_flush("files",
100 1
            [null, $this->esc_str($path), $this->esc_str($source)]);
101
    }
102
103
    /**
104
     * @inheritdocs
105
     */
106 1
    public function _namespace($name) {
107 1
        return $this->append_and_maybe_flush("namespaces",
108 1
            [null, $this->esc_str($name)]);
109
    }
110
111
    /**
112
     * @inheritdocs
113
     */
114 1
    public function _class($name, $file, $start_line, $end_line, $namespace = null) {
115 1
        return $this->append_and_maybe_flush("classes",
116 1
            [null, $this->esc_str($name), $file, $start_line, $end_line, $this->esc_maybe_null($namespace)]);
117
    }
118
119
    /**
120
     * @inheritdocs
121
     */
122
    public function _interface($name, $file, $start_line, $end_line, $namespace = null) {
123
        return $this->append_and_maybe_flush("interfaces",
124
            [null, $this->esc_str($name), $file, $start_line, $end_line, $this->esc_maybe_null($namespace)]);
125
    }
126
127
    /**
128
     * @inheritdocs
129
     */
130
    public function _trait($name, $file, $start_line, $end_line, $namespace = null) {
131
        return $this->append_and_maybe_flush("traits",
132
            [null, $this->esc_str($name), $file, $start_line, $end_line, $this->esc_maybe_null($namespace)]);
133
    }
134
135
    /**
136
     * @inheritdocs
137
     */
138 1
    public function _method($name, $class, $file, $start_line, $end_line) {
139 1
        return $this->append_and_maybe_flush("methods",
140 1
            [null, $this->esc_str($name), $class, $file, $start_line, $end_line]);
141
    }
142
143
    /**
144
     * @inheritdocs
145
     */
146 1
    public function _function($name, $file, $start_line, $end_line, $namespace = null) {
147 1
        return $this->append_and_maybe_flush("functions",
148 1
            [null, $this->esc_str($name), $file, $start_line, $end_line, $this->esc_maybe_null($namespace)]);
149
    }
150
151
    /**
152
     * @inheritdocs
153
     */
154 1
    public function _global($name) {
155 1
        return $this->append_and_maybe_flush("globals",
156 1
            [null, $this->esc_str($name)]);
157
    }
158
159
    /**
160
     * @inheritdocs
161
     */
162 1
    public function _language_construct($name) {
163 1
        return $this->append_and_maybe_flush("language_constructs",
164 1
            [null, $this->esc_str($name)]);
165
    }
166
167
    /**
168
     * @inheritdocs
169
     */
170 1
    public function _method_reference($name, $file, $line, $column) {
171 1
        return $this->append_and_maybe_flush("method_references",
172 1
            [null, $this->esc_str($name), $file, $line, $column]);
173
    }
174
175
    /**
176
     * @inheritdocs
177
     */
178 1
    public function _function_reference($name, $file, $line, $column) {
179 1
        return $this->append_and_maybe_flush("function_references",
180 1
            [null, $this->esc_str($name), $file, $line, $column]);
181
    }
182
183
    /**
184
     * @inheritdocs
185
     */
186 1
    public function _relation($left_entity, $relation, $right_entity, $file, $line) {
187 1
        $this->append_and_maybe_flush("relations",
188 1
            [$left_entity, $this->esc_str($relation), $right_entity, $file, $line]);
189 1
    }
190
191 1
    protected function insert_cache($table) {
192 1
        assert('array_key_exists($table, $this->tables)');
193 1
        $fields = $this->tables[$table][1];
194 1
        $which = &$this->caches[$table];
195 1
        if (count($which) == 0) {
196 1
            return;
197
        }
198 1
        $stmt = "INSERT INTO $table (".implode(", ", $fields).") VALUES\n";
199 1
        $values = [];
200 1
        foreach ($which as $v) {
201 1
            $values[] = "(".implode(", ", $v).")";
202 1
        }
203 1
        $stmt .= implode(",\n", $values).";";
204 1
        $this->connection->exec($stmt);
205 1
        $which = [];
206 1
    }
207
208 1
    protected function append_and_maybe_flush($table, $values) {
209 1
        if ($values[0] === null) {
210 1
            $id = $this->id_counter++;
211 1
            $values[0] = $id;
212 1
        }
213
        else {
214 1
            $id = null;
215
        }
216
217 1
        $which = &$this->caches[$table];
218 1
        $which[] = $values;
219 1
        if (count($which) > $this->nodes_per_insert) {
220
            $this->insert_cache($table);
221
        }
222
223 1
        return $id;
224
    }
225 1
    protected function esc_str($str) {
226 1
        assert('is_string($str)');
227 1
        return '"'.str_replace('"', '""', $str).'"';
228
    }
229
230 1
    protected function esc_maybe_null($val) {
231 1
        assert('!is_string($val)');
232 1
        if ($val === null) {
233 1
            return "NULL";
234
        }
235 1
        return $val;
236
    }
237
238
    /**
239
     * Write everything that currently is in cache to the database.
240
     *
241
     * @return null
242
     */
243 1
    public function write_cached_inserts() {
244 1
        foreach ($this->tables as $table => $_) {
245 1
            $this->insert_cache($table);
246 1
        }
247 1
    }
248
249
    /**
250
     * Read the index from the database.
251
     *
252
     * @return  Graph\IndexDB   $index
253
     */
254 1
    public function to_graph_index() {
255 1
        $index = $this->build_graph_index_db();
256
        $reader = new IndexDBReader
257 1
            ( $this->tables
258 1
            , $this->id_fields
259 1
            , $this->int_fields
260
            , function () { return $this->builder(); }
261 1
            , $index
262 1
            );
263 1
        $reader->run();
264 1
        return $index;
265
    }
266
267
    protected function build_graph_index_db() {
268
        return new Graph\IndexDB();
269
    }
270
271
    // INIT DATABASE
272
273 1
    public function init_table($name, Schema\Schema $schema, Schema\Table $file_table = null, Schema\Table $namespace_table = null) {
274 1
        assert('array_key_exists($name, $this->tables)');
275 1
        $table = $schema->createTable($name);
276 1
        foreach ($this->tables[$name][1] as $field) {
277
            switch ($field) {
278 1
                case "id":
279 1
                case "file_id":
280 1
                case "class_id":
281 1
                case "left_id":
282 1
                case "right_id":
283 1
                case "start_line":
284 1
                case "end_line":
285 1
                case "line":
286 1 View Code Duplication
                case "column":
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...
287 1
                    $table->addColumn
288 1
                        ($field, "integer"
289 1
                        , ["notnull" => true, "unsigned" => true]
290 1
                        );
291 1
                    break;
292 1 View Code Duplication
                case "namespace_id":
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...
293 1
                    $table->addColumn
294 1
                        ($field, "integer"
295 1
                        , ["notnull" => false, "unsigned" => true]
296 1
                        );
297 1
                   break;
298 1
                case "path":
299 1
                case "source":
300 1
                case "name":
301 1
                case "relation":
302 1
                    $table->addColumn
303 1
                        ($field, "string"
304 1
                        , ["notnull" => true]
305 1
                        );
306 1
                    break;
307
                default:
308
                    throw new \LogicException("Unknown field '$field'");
309
            }
310 1
            if ($field == "id") {
311 1
                $table->setPrimaryKey(["id"]);
312 1
            }
313 1
            if ($field == "file_id") {
314 1
                if ($file_table instanceof Schema\Table) {
315 1
                    $table->addForeignKeyConstraint
316 1
                        ( $file_table
317 1
                        , array("file_id")
318 1
                        , array("id")
319 1
                        );
320 1
                }
321
                else {
322
                    throw new \LogicException(
323
                        "Expected \$file_table to be a schema when file_id is used.");
324
                }
325 1
            }
326 1
            if ($field == "namespace_id") {
327 1
                if ($namespace_table instanceof Schema\Table) {
328 1
                    $table->addForeignKeyConstraint
329 1
                        ( $namespace_table
330 1
                        , array("namespace_id")
331 1
                        , array("id")
332 1
                        );
333 1
                }
334
                else {
335
                    throw new \LogicException(
336
                        "Expected \$namespace_table to be a schema when namespace_id is used.");
337
                }
338 1
            }
339 1
        }
340 1
        return $table;
341
    }
342
343 1
    public function init_database_schema() {
344 1
        $schema = new Schema\Schema();
345
346 1
        $file_table = $this->init_table("files", $schema);
347 1
        $namespace_table = $this->init_table("namespaces", $schema);
348 1
        $this->init_table("classes", $schema, $file_table, $namespace_table);
349 1
        $this->init_table("interfaces", $schema, $file_table, $namespace_table);
350 1
        $this->init_table("traits", $schema, $file_table, $namespace_table);
351 1
        $this->init_table("methods", $schema, $file_table);
352 1
        $this->init_table("functions", $schema, $file_table, $namespace_table);
353 1
        $this->init_table("globals", $schema);
354 1
        $this->init_table("language_constructs", $schema);
355 1
        $this->init_table("method_references", $schema, $file_table);
356 1
        $this->init_table("function_references", $schema, $file_table);
357 1
        $relation_table = $this->init_table("relations", $schema, $file_table);
358 1
        $relation_table->setPrimaryKey(["left_id", "relation", "right_id"]);
359
360 1
        $sync = new SingleDatabaseSynchronizer($this->connection);
361 1
        $sync->createSchema($schema);
362 1
    }
363
}
364