Completed
Push — master ( aa8ceb...740836 )
by Ivan
04:53
created

TableQueryIterator::values()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 8
cts 8
cp 1
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 8
nc 4
nop 1
crap 6
1
<?php
2
namespace vakata\database\schema;
3
4
use vakata\collection\Collection;
5
use vakata\database\DBException;
6
7
/**
8
 * A table query iterator
9
 */
10
class TableQueryIterator implements \Iterator, \ArrayAccess
11
{
12
    const SEP = '___';
13
    /**
14
     * @var array
15
     */
16
    protected $pkey;
17
    /**
18
     * @var Collection
19
     */
20
    protected $result;
21
    /**
22
     * @var array[]
23
     */
24
    protected $relations;
25
    /**
26
     * @var string|null
27
     */
28
    protected $primary = null;
29
    /**
30
     * @var int
31
     */
32
    protected $fetched = 0;
33
34 11
    public function __construct(Collection $result, array $pkey, array $relations = [])
35
    {
36 11
        $this->pkey = $pkey;
37 11
        $this->result = $result;
38 11
        $this->relations = $relations;
39 11
    }
40
41 11
    public function key()
42
    {
43 11
        return $this->fetched;
44
    }
45 11
    public function current()
46
    {
47 11
        $result = null;
48 11
        $remove = [];
49 11
        while ($this->result->valid()) {
50 11
            $row = $this->result->current();
51 11
            $pk = [];
52 11
            foreach ($this->pkey as $field) {
53 11
                $pk[$field] = $row[$field];
54
            }
55 11
            $pk = json_encode($pk);
56 11
            if ($this->primary !== null && $pk !== $this->primary) {
57 8
                break;
58
            }
59 11
            $this->primary = $pk;
60 11
            if (!$result) {
61 11
                $result = $row;
62
            }
63 11
            foreach ($this->relations as $name => $relation) {
64 4
                $relation = $relation[0];
65 4
                $fields = [];
66 4
                $exists = false;
67 4
                foreach ($relation->table->getColumns() as $column) {
68 4
                    $fields[$column] = $row[$name . static::SEP . $column];
69 4
                    if (!$exists && $row[$name . static::SEP . $column] !== null) {
70 4
                        $exists = true;
71
                    }
72 4
                    $remove[] = $name . static::SEP . $column;
73
                }
74 4
                $temp  = &$result;
75 4
                $parts = explode(static::SEP, $name);
76 4
                $name  = array_pop($parts);
77 4
                if (!$exists && !count($parts) && !isset($temp[$name])) {
78 2
                    $temp[$name] = $relation->many ? [ '___clean' => true ] : null;
79
                }
80 4
                if ($exists) {
81 4
                    $full  = '';
82 4
                    foreach ($parts as $item) {
83 1
                        $full = $full ? $full . static::SEP . $item : $item;
84 1
                        $temp = &$temp[$item];
85 1
                        $rpk = [];
86 1
                        foreach ($this->relations[$full][0]->table->getPrimaryKey() as $pkey) {
87 1
                            $rpk[$pkey] = $row[$full . static::SEP . $pkey];
88
                        }
89 1
                        $temp = &$temp[json_encode($rpk)];
90
                    }
91 4
                    if (!isset($temp[$name])) {
92 4
                        $temp[$name] = $relation->many ? [ '___clean' => true ] : null;
93
                    }
94 4
                    $temp = &$temp[$name];
95 4
                    if ($relation->many) {
96 4
                        $rpk = [];
97 4
                        foreach ($relation->table->getPrimaryKey() as $field) {
98 4
                            $rpk[$field] = $fields[$field];
99
                        }
100 4
                        $temp[json_encode($rpk)] = array_merge($temp[json_encode($rpk)] ?? [], $fields);
101
                    } else {
102 4
                        $temp = array_merge($temp ?? [], $fields);
103
                    }
104
                }
105
            }
106 11
            $this->result->next();
107
        }
108 11
        if ($result) {
109 11
            foreach ($remove as $name) {
110 4
                unset($result[$name]);
111
            }
112 11
            $result = $this->values($result);
113
        }
114 11
        return $result;
115
    }
116 11
    protected function values(array $data)
117
    {
118 11
        foreach ($data as $k => $v) {
119 11
            if (is_array($v) && isset($v['___clean']) && $v['___clean'] === true) {
120 4
                unset($v['___clean']);
121 4
                $data[$k] = array_values($v);
122 4
                foreach ($data[$k] as $kk => $vv) {
123 11
                    $data[$k][$kk] = $this->values($vv);
124
                }
125
            }
126
        }
127 11
        return $data;
128
    }
129
130 11
    public function rewind()
131
    {
132 11
        $this->fetched = 0;
133 11
        $this->primary = null;
134 11
        return $this->result->rewind();
135
    }
136 11
    public function next()
137
    {
138 11
        if ($this->primary === null) {
139
            $this->result->next();
140
            if ($this->result->valid()) {
141
                $row = $this->result->current();
142
                $temp = [];
143
                foreach ($this->pkey as $field) {
144
                    $temp[$field] = $row[$field];
145
                }
146
                $this->primary = json_encode($temp);
147
                return;
148
            }
149
        }
150 11
        $this->fetched ++;
151 11
        while ($this->result->valid()) {
152 8
            $row = $this->result->current();
153 8
            $pk = [];
154 8
            foreach ($this->pkey as $field) {
155 8
                $pk[$field] = $row[$field];
156
            }
157 8
            $pk = json_encode($pk);
158 8
            if ($this->primary !== $pk) {
159 8
                $this->primary = $pk;
160 8
                break;
161
            }
162
            $this->result->next();
163
        }
164 11
    }
165 11
    public function valid()
166
    {
167 11
        return $this->result->valid();
168
    }
169
170 9
    public function offsetGet($offset)
171
    {
172 9
        $index = $this->fetched;
173 9
        $item = null;
174 9
        foreach ($this as $k => $v) {
175 9
            if ($k === $offset) {
176 9
                $item = $v;
177
            }
178
        }
179 9
        foreach ($this as $k => $v) {
180 9
            if ($k === $index) {
181 9
                break;
182
            }
183
        }
184 9
        return $item;
185
    }
186
    public function offsetExists($offset)
187
    {
188
        $index = $this->fetched;
189
        $exists = false;
190
        foreach ($this as $k => $v) {
191
            if ($k === $offset) {
192
                $exists = true;
193
            }
194
        }
195
        foreach ($this as $k => $v) {
196
            if ($k === $index) {
197
                break;
198
            }
199
        }
200
        return $exists;
201
    }
202
    public function offsetSet($offset, $value)
203
    {
204
        throw new DBException('Invalid call to offsetSet');
205
    }
206
    public function offsetUnset($offset)
207
    {
208
        throw new DBException('Invalid call to offsetUnset');
209
    }
210
}
211