Completed
Push — master ( 740836...6931a9 )
by Ivan
01:50
created

TableQueryIterator   C

Complexity

Total Complexity 55

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 81.75%

Importance

Changes 0
Metric Value
wmc 55
lcom 1
cbo 2
dl 0
loc 214
ccs 103
cts 126
cp 0.8175
rs 6.8
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A key() 0 4 1
C current() 0 79 26
B values() 0 13 6
A rewind() 0 6 1
C next() 0 29 7
A valid() 0 4 1
B offsetGet() 0 16 5
B offsetExists() 0 16 5
A offsetSet() 0 4 1
A offsetUnset() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like TableQueryIterator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TableQueryIterator, and based on these observations, apply Extract Interface, too.

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 array[]
27
     */
28
    protected $aliases;
29
    /**
30
     * @var string|null
31
     */
32
    protected $primary = null;
33
    /**
34
     * @var int
35
     */
36
    protected $fetched = 0;
37
38 11
    public function __construct(Collection $result, array $pkey, array $relations = [], array $aliases = [])
39
    {
40 11
        $this->pkey = $pkey;
41 11
        $this->result = $result;
42 11
        $this->relations = $relations;
43 11
        $this->aliases = $aliases;
44 11
    }
45
46 11
    public function key()
47
    {
48 11
        return $this->fetched;
49
    }
50 11
    public function current()
51
    {
52 11
        $result = null;
53 11
        $remove = [];
54 11
        while ($this->result->valid()) {
55 11
            $row = $this->result->current();
56 11
            $pk = [];
57 11
            foreach ($this->pkey as $field) {
58 11
                $pk[$field] = $row[$field];
59
            }
60 11
            $pk = json_encode($pk);
61 11
            if ($this->primary !== null && $pk !== $this->primary) {
62 8
                break;
63
            }
64 11
            $this->primary = $pk;
65 11
            if (!$result) {
66 11
                $result = $row;
67
            }
68 11
            foreach ($this->relations as $name => $relation) {
69 4
                $relation = $relation[0];
70 4
                $fields = [];
71 4
                $exists = false;
72 4
                foreach ($relation->table->getColumns() as $column) {
73 4
                    $nm = $name . static::SEP . $column;
74 4
                    if (isset($this->aliases[$nm])) {
75 4
                        $nm = $this->aliases[$nm];
76
                    }
77 4
                    $fields[$column] = $row[$nm];
78 4
                    if (!$exists && $row[$nm] !== null) {
79 4
                        $exists = true;
80
                    }
81 4
                    $remove[] = $nm; // $name . static::SEP . $column;
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
82
                }
83 4
                $temp  = &$result;
84 4
                $parts = explode(static::SEP, $name);
85 4
                $name  = array_pop($parts);
86 4
                if (!$exists && !count($parts) && !isset($temp[$name])) {
87 2
                    $temp[$name] = $relation->many ? [ '___clean' => true ] : null;
88
                }
89 4
                if ($exists) {
90 4
                    $full  = '';
91 4
                    foreach ($parts as $item) {
92 1
                        $full = $full ? $full . static::SEP . $item : $item;
93 1
                        $temp = &$temp[$item];
94 1
                        $rpk = [];
95 1
                        foreach ($this->relations[$full][0]->table->getPrimaryKey() as $pkey) {
96 1
                            $nm = $full . static::SEP . $pkey;
97 1
                            if (isset($this->aliases[$nm])) {
98 1
                                $nm = $this->aliases[$nm];
99
                            }
100 1
                            $rpk[$pkey] = $row[$nm];
101
                        }
102 1
                        $temp = &$temp[json_encode($rpk)];
103
                    }
104 4
                    if (!isset($temp[$name])) {
105 4
                        $temp[$name] = $relation->many ? [ '___clean' => true ] : null;
106
                    }
107 4
                    $temp = &$temp[$name];
108 4
                    if ($relation->many) {
109 4
                        $rpk = [];
110 4
                        foreach ($relation->table->getPrimaryKey() as $field) {
111 4
                            $rpk[$field] = $fields[$field];
112
                        }
113 4
                        $temp[json_encode($rpk)] = array_merge($temp[json_encode($rpk)] ?? [], $fields);
114
                    } else {
115 4
                        $temp = array_merge($temp ?? [], $fields);
116
                    }
117
                }
118
            }
119 11
            $this->result->next();
120
        }
121 11
        if ($result) {
122 11
            foreach ($remove as $name) {
123 4
                unset($result[$name]);
124
            }
125 11
            $result = $this->values($result);
126
        }
127 11
        return $result;
128
    }
129 11
    protected function values(array $data)
130
    {
131 11
        foreach ($data as $k => $v) {
132 11
            if (is_array($v) && isset($v['___clean']) && $v['___clean'] === true) {
133 4
                unset($v['___clean']);
134 4
                $data[$k] = array_values($v);
135 4
                foreach ($data[$k] as $kk => $vv) {
136 11
                    $data[$k][$kk] = $this->values($vv);
137
                }
138
            }
139
        }
140 11
        return $data;
141
    }
142
143 11
    public function rewind()
144
    {
145 11
        $this->fetched = 0;
146 11
        $this->primary = null;
147 11
        return $this->result->rewind();
148
    }
149 11
    public function next()
150
    {
151 11
        if ($this->primary === null) {
152
            $this->result->next();
153
            if ($this->result->valid()) {
154
                $row = $this->result->current();
155
                $temp = [];
156
                foreach ($this->pkey as $field) {
157
                    $temp[$field] = $row[$field];
158
                }
159
                $this->primary = json_encode($temp);
160
                return;
161
            }
162
        }
163 11
        $this->fetched ++;
164 11
        while ($this->result->valid()) {
165 8
            $row = $this->result->current();
166 8
            $pk = [];
167 8
            foreach ($this->pkey as $field) {
168 8
                $pk[$field] = $row[$field];
169
            }
170 8
            $pk = json_encode($pk);
171 8
            if ($this->primary !== $pk) {
172 8
                $this->primary = $pk;
173 8
                break;
174
            }
175
            $this->result->next();
176
        }
177 11
    }
178 11
    public function valid()
179
    {
180 11
        return $this->result->valid();
181
    }
182
183 9
    public function offsetGet($offset)
184
    {
185 9
        $index = $this->fetched;
186 9
        $item = null;
187 9
        foreach ($this as $k => $v) {
188 9
            if ($k === $offset) {
189 9
                $item = $v;
190
            }
191
        }
192 9
        foreach ($this as $k => $v) {
193 9
            if ($k === $index) {
194 9
                break;
195
            }
196
        }
197 9
        return $item;
198
    }
199
    public function offsetExists($offset)
200
    {
201
        $index = $this->fetched;
202
        $exists = false;
203
        foreach ($this as $k => $v) {
204
            if ($k === $offset) {
205
                $exists = true;
206
            }
207
        }
208
        foreach ($this as $k => $v) {
209
            if ($k === $index) {
210
                break;
211
            }
212
        }
213
        return $exists;
214
    }
215
    public function offsetSet($offset, $value)
216
    {
217
        throw new DBException('Invalid call to offsetSet');
218
    }
219
    public function offsetUnset($offset)
220
    {
221
        throw new DBException('Invalid call to offsetUnset');
222
    }
223
}
224