Completed
Push — master ( 2dcac2...cce771 )
by Richard
03:44
created

IndexDBReader::select_all_from()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 9
nc 1
nop 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\Indexer\Insert;
14
15
/**
16
 * Reads in an sql IndexDB to another Index.
17
 */
18
class IndexDBReader {
19
    /**
20
     * @var array
21
     */
22
    protected $tables;
23
24
    /**
25
     * Lists of fields that contain an id.
26
     *
27
     * @var array<string,int>
28
     */
29
    protected $id_fields;
30
31
    /**
32
     * List of all fields that contain an integer.
33
     *
34
     * @var array<string,0>
35
     */
36
    protected $int_fields;
37
38
    /**
39
     * @var \Closure
40
     */
41
    protected $get_query_builder;
42
43
    /**
44
     * @var Insert
45
     */
46
    protected $other;
47
48
    /**
49
     * @var bool
50
     */
51
    protected $already_run;
52
53
    /**
54
     * @param   array   $tables     list of tables and fields according to IndexDB
55
     * @param   array   $id_fields  list of fields that contain a id
56
     * @param   array   $int_fields list of fields that contain an int
57
     * @param   \Closure    $get_query_builder  to get a QueryBuilder
58
     */
59
    public function __construct($tables, $id_fields, $int_fields, \Closure $get_query_builder, Insert $insert) {
60
        $this->tables = $tables;
61
        $this->id_fields = $id_fields;
62
        $this->int_fields = $int_fields;
63
        $this->get_query_builder = $get_query_builder;
64
        $this->other = $insert;
65
        $this->already_run = false;
66
    }
67
68
69
    /**
70
     * Read the index from the database and put it to insert.
71
     */
72
    public function run() {
73
        assert('!$this->already_run');
74
75
        $this->id_map = [null => null];
0 ignored issues
show
Bug introduced by
The property id_map does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
76
77
        $inserts = $this->get_inserts();
78
        $this->write_inserts($inserts);
79
80
        $this->already_run = true;
81
    }
82
83
    /**
84
     * Builds a list of inserts ordered by the id.
85
     *
86
     * @return  \Iterator   $table => $values
87
     */
88
    protected function get_inserts() {
89
        $results = $this->build_results_with_id();
90
91
        $count = count($results);
92
        $i = 0;
93
        $expected_id = 0;
94
        // TODO: This will loop forever if there are (unexpected) holes
95
        // in the sequence of ids.
96
        while ($count > 0) {
97
            if ($i >= $count) {
98
                $i = 0;
99
            }
100
101
            $current_res = $results[$i][1];
102
            if ($current_res !== null) {
103
                if ($current_res["id"] != $expected_id) {
104
                    $i++;
105
                    continue;
106
                }
107
108
                yield $results[$i][0] => $this->transform_results($current_res);
109
                $results[$i][1] = null;
110
                $expected_id++;
111
            }
112
113
            $rs = $results[$i][2];
114
            if ($rs->valid()) {
115
                $results[$i][1] = $rs->current();
116
                $rs->next();
117
            }
118
            else {
119
                $count--;
120
                unset($results[$i]);
121
                $results = array_values($results);
122
            }
123
        }
124
125
        $rs = $this->select_all_from("relations");
126
        while ($rs->valid()) {
127
            yield "relations" => $this->transform_results($rs->current());
128
            $rs->next();
129
        }
130
    }
131
132
    /**
133
     * Initialize all tables that contain an id with their results.
134
     *
135
     * @return  array[] containing [$table_name, null, $results]
136
     */
137
    protected function build_results_with_id() {
138
        $results = [];
139
        foreach ($this->tables as $key => $_) {
140
            if ($key == "relations") {
141
                continue;
142
            }
143
            $results[] = [$key, null, $this->select_all_from($key)];
144
        }
145
        return $results;
146
    }
147
148
    /**
149
     * @param   string  $table
150
     * @return  \Iterator
151
     */
152
    protected function select_all_from($table) {
153
        $get_query_builder = $this->get_query_builder;
154
        $query_result = $get_query_builder()
155
            ->select($this->tables[$table][1])
156
            ->from($table)
157
            ->execute();
158
        return (function() use ($query_result) {
159
            while ($res = $query_result->fetch()) {
160
                yield $res;
161
            }
162
        })();
163
    }
164
165
    /**
166
     * Transforms results as retreived from sql to their appropriate internal
167
     * representation.
168
     *
169
     * @param   array   $results    from database
170
     * @return  array
171
     */
172
    public function transform_results(array $results) {
173
        foreach (array_keys($results) as $field) {
174
            if (isset($this->id_fields[$field])) {
175
                $results[$field] = $this->id_map[$results[$field]];
176
            }
177
            else if (isset($this->int_fields[$field])) {
178
                $results[$field] = (int)$results[$field];
179
            }
180
        }
181
        return $results;
182
    }
183
184
    /**
185
     * @param   \Iterator       $inserts
186
     * @return  null
187
     */
188
    protected function write_inserts(\Iterator $inserts) {
189
        foreach ($inserts as $table => $insert) {
190
            assert('array_key_exists($table, $this->tables)');
191
            $method = $this->tables[$table][0];
192
            if (isset($insert["id"])) {
193
                $id = $insert["id"];
194
                unset($insert["id"]);
195
                $this->id_map[$id] = call_user_func_array([$this->other, $method], $insert);
196
            }
197
            else {
198
                call_user_func_array([$this->other, $method], $insert);
199
            }
200
        }
201
    }
202
}
203