Completed
Push — master ( addc16...69f641 )
by Richard
05:18
created

IndexDB::init_method_table()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 32
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 25
nc 1
nop 3
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 Doctrine\DBAL\Schema;
15
use Doctrine\DBAL\Types\Type;
16
use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer;
17
use Doctrine\DBAL\Statement;
18
19
class IndexDB extends DB {
20
    /**
21
     * Write the index to the database.
22
     *
23
     * @param   Graph\IndexDB   $index
24
     * @return  null
25
     */
26 1
    public function write_index(Graph\IndexDB $index) {
27 1
        $this->prepare_insert_statements();
28 1
        $max_id = $this->serialize_nodes($index);
29 1
        $this->serialize_relations($index, $max_id);
30 1
    }
31
32
    /**
33
     * Read the index from the database.
34
     *
35
     * @return  Graph\IndexDB   $index
36
     */
37 1
    public function read_index() {
38 1
        $index = $this->build_graph_index_db();
39 1
        $this->deserialize_nodes_to($index);
40 1
        $this->deserialize_relations_to($index);
41 1
        return $index;
42
    }
43
44
    protected function build_graph_index_db() {
45
        return new Graph\IndexDB();
46
    }
47
48
    // WRITE
49
50 1
    protected function serialize_nodes(Graph\IndexDB $index) {
51 1
        $max_id = 0;
52 1
        foreach ($index->nodes() as $node) {
53 1
            $id = $node->id();
54 1
            $this->insert_entity_stmt->execute([$node->id(), $node->type()]);
55 1
            $max_id = max($max_id, $id);
56 1
            $this->insert_properties($id, $node);
57 1
        }
58 1
        return $max_id;
59
    }
60
61 1
    protected function serialize_relations(Graph\IndexDB $index, $id) {
62 1
        foreach ($index->nodes() as $node) {
63 1
            foreach ($node->relations() as $relation) {
64 1
                $id++;
65 1
                $this->insert_entity_stmt->execute([$id, $relation->type()]);
66 1
                $this->insert_properties($id, $relation);
67 1
                $this->insert_relation_stmt->execute([$node->id(), $id, $relation->target()->id()]);
68 1
            }
69 1
        }
70 1
    }
71
72
    protected $insert_entity_stmt;
73
    protected $insert_property_stmt;
74
    protected $insert_relation_stmt;
75
76 1
    protected function prepare_insert_statements() {
77 1
        $this->insert_entity_stmt = $this->connection->prepare
78 1
            ( "INSERT INTO entities (id, type)\n"
79
            . "VALUES (?, ?)"
80 1
            );
81 1
        $this->insert_property_stmt = $this->connection->prepare
82 1
            ( "INSERT INTO properties (entity_id, key, is_entity, value)\n"
83
            . "VALUES (?, ?, ?, ?)"
84 1
            );
85 1
        $this->insert_relation_stmt = $this->connection->prepare
86 1
            ( "INSERT INTO relations (source_id, entity_id, target_id)\n"
87
            . "VALUES (?, ?, ?)"
88 1
            );
89 1
    }
90
91 1
    protected function insert_properties($id, Graph\Entity $e) {
92 1
        foreach ($e->properties() as $key => $value) {
93 1
            $this->insert_property($id, $key, $value);
94 1
        }
95 1
    }
96
97 1
    protected function insert_property($entity_id, $key, $value) {
98 1
        $is_entity = false;
99 1
        if ($value instanceof Graph\Node) {
100 1
            $is_entity = true;
101 1
            $value = $value->id();
102 1
        }
103 1
        if ($value instanceof Graph\Relation) {
104
            throw new \LogicException("Can't serialize Relation properties (NYI!)");
105
        }
106 1
        $value = serialize($value);
107 1
        $this->insert_property_stmt->execute([$entity_id, $key, $is_entity, $value]);
108 1
    }
109
110
    // READ
111
112 1
    protected function deserialize_nodes_to(Graph\IndexDB $index) {
113 1
        $res = $this->connection->executeQuery
114 1
            ( "SELECT entities.id, entities.type FROM entities\n"
115
            . "LEFT JOIN relations ON entities.id = relations.entity_id\n"
116 1
            . "WHERE relations.source_id IS NULL"
117 1
            );
118 1
        while ($row = $res->fetch()) {
119 1
            $properties = $this->select_properties($row["id"], $index);
120 1
            $node = $index->create_node($row["type"], $properties);
0 ignored issues
show
Unused Code introduced by
$node is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
121 1
            assert('$row["id"] == $node->id()');
122 1
        }
123 1
    }
124
125 1
    protected function deserialize_relations_to(Graph\IndexDB $index) {
126 1
        $res = $this->connection->executeQuery
127 1
            ( "SELECT source_id, entity_id, target_id, type FROM relations\n"
128
            . "JOIN entities ON entities.id = relations.entity_id\n"
129 1
            . "ORDER BY source_id, entity_id"
130 1
            );
131 1
        $node = null;
132 1
        while ($row = $res->fetch()) {
133 1
            if ($node === null || $node->id() != $row["source_id"]) {
134 1
                $node = $index->node((int)$row["source_id"]);
135 1
            }
136 1
            $other = $index->node((int)$row["target_id"]);
137 1
            $properties = $this->select_properties($row["entity_id"], $index);
138 1
            $node->add_relation($row["type"], $properties, $other);
139 1
        }
140 1
    }
141
142
143 1
    protected function select_properties($id, $index) {
144 1
        $id = (int)$id;
145 1
        $res = $this->connection->executeQuery
146 1
            ( "SELECT key, is_entity, value FROM properties\n"
147 1
            . "WHERE entity_id = $id"
148 1
            );
149 1
        $props = [];
150 1
        while ($row = $res->fetch()) {
151 1
            $value = unserialize($row["value"]);
152 1
            if ($row["is_entity"]) {
153 1
                $value = $index->node($value);
154 1
            }
155 1
            $props[$row["key"]] = $value;
156 1
        }
157 1
        return $props;
158
    }
159
160
    // INIT
161
162 1
    public function init_database_schema() {
163 1
        $schema = new Schema\Schema();
164
165 1
        $entity_table = $schema->createTable("entities");
166 1
        $entity_table->addColumn
167 1
            ("id", "integer"
168 1
            , ["notnull" => true, "unsigned" => true]
169 1
            );
170 1
        $entity_table->addColumn
171 1
            ( "type", "string"
172 1
            , ["notnull" => true]
173 1
            );
174 1
        $entity_table->setPrimaryKey(["id"]);
175
176 1
        $property_table = $schema->createTable("properties");
177 1
        $property_table->addColumn
178 1
            ("entity_id", "integer"
179 1
            , ["notnull" => true, "unsigned" => true]
180 1
            );
181 1
        $property_table->addColumn
182 1
            ( "key", "string"
183 1
            , ["notnull" => true]
184 1
            );
185 1
        $property_table->addColumn
186 1
            ( "is_entity", "boolean"
187 1
            , ["notnull" => true]
188 1
            );
189 1
        $property_table->addColumn
190 1
            ( "value", "string"
191 1
            , ["notnull" => true]
192 1
            );
193 1
        $property_table->addForeignKeyConstraint
194 1
            ( $entity_table
195 1
            , array("entity_id")
196 1
            , array("id")
197 1
            );
198 1
        $property_table->setPrimaryKey(["entity_id", "key"]);
199
200 1
        $relation_table = $schema->createTable("relations");
201 1
        $relation_table->addColumn
202 1
            ( "source_id", "integer"
203 1
            , ["notnull" => true, "unsigned" => true]
204 1
            );
205 1
        $relation_table->addColumn
206 1
            ( "entity_id", "integer"
207 1
            , ["notnull" => true, "unsigned" => true]
208 1
            );
209 1
        $relation_table->addColumn
210 1
            ( "target_id", "integer"
211 1
            , ["notnull" => true, "unsigned" => true]
212 1
            );
213 1
        $relation_table->addForeignKeyConstraint
214 1
            ( $entity_table
215 1
            , array("source_id")
216 1
            , array("id")
217 1
            );
218 1
        $relation_table->addForeignKeyConstraint
219 1
            ( $entity_table
220 1
            , array("entity_id")
221 1
            , array("id")
222 1
            );
223 1
        $relation_table->addForeignKeyConstraint
224 1
            ( $entity_table
225 1
            , array("target_id")
226 1
            , array("id")
227 1
            );
228 1
        $relation_table->setPrimaryKey(["entity_id"]);
229
230 1
        $sync = new SingleDatabaseSynchronizer($this->connection);
231 1
        $sync->createSchema($schema);
232 1
    }
233
}
234