Passed
Push — master ( 76b08e...5cd6b2 )
by Ryuichi
58:40 queued 56:20
created

ResultEntity   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 238
Duplicated Lines 0 %

Test Coverage

Coverage 54.17%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 61
c 1
b 0
f 0
dl 0
loc 238
ccs 39
cts 72
cp 0.5417
rs 10
wmc 28

16 Methods

Rating   Name   Duplication   Size   Complexity  
A offsetUnSet() 0 3 1
A next() 0 6 2
A toArray() 0 7 1
A offsetGet() 0 7 2
A seek() 0 11 3
A count() 0 14 3
A __construct() 0 6 1
A getColumnMeta() 0 15 3
A __destruct() 0 4 1
A initialize() 0 4 1
A current() 0 7 3
A rewind() 0 6 2
A offsetSet() 0 3 1
A offsetExists() 0 7 2
A key() 0 3 1
A valid() 0 3 1
1
<?php
2
3
namespace WebStream\Database;
4
5
use WebStream\DI\Injector;
0 ignored issues
show
Bug introduced by
The type WebStream\DI\Injector was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use WebStream\Exception\Extend\CollectionException;
0 ignored issues
show
Bug introduced by
The type WebStream\Exception\Extend\CollectionException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
8
/**
9
 * ResultEntity
10
 * @author Ryuichi TANAKA.
11
 * @since 2015/01/11
12
 * @version 0.7
13
 */
14
class ResultEntity implements \Iterator, \SeekableIterator, \ArrayAccess, \Countable
15
{
16
    use Injector;
17
18
    /**
19
     * @var Doctrine\DBAL\Statement ステートメント
0 ignored issues
show
Bug introduced by
The type WebStream\Database\Doctrine\DBAL\Statement was not found. Did you mean Doctrine\DBAL\Statement? If so, make sure to prefix the type with \.
Loading history...
20
     */
21
    private $stmt;
22
23
    /**
24
     * @var array<mixed> 列データ
25
     */
26
    private $row;
27
28
    /**
29
     * @var array<mixed> キャッシュ化列データ
30
     */
31
    private $rowCache;
32
33
    /**
34
     * @var int インデックス位置
35
     */
36
    private $position;
37
38
    /**
39
     * @var EntityManager エンティティマネージャ
40
     */
41
    private $entityManager;
42
43
    /**
44
     * コンストラクタ
45
     * @param Doctrine\DBAL\Driver\Statement ステートメントオブジェクト
0 ignored issues
show
Documentation Bug introduced by
The doc comment ステートメントオブジェクト at position 0 could not be parsed: Unknown type name 'ステートメントオブジェクト' at position 0 in ステートメントオブジェクト.
Loading history...
46
     * @param string エンティティクラスパス
47
     */
48 16
    public function __construct(\Doctrine\DBAL\Driver\Statement $stmt, $classpath)
49
    {
50 16
        $this->stmt = $stmt;
0 ignored issues
show
Documentation Bug introduced by
It seems like $stmt of type Doctrine\DBAL\Driver\Statement is incompatible with the declared type WebStream\Database\Doctrine\DBAL\Statement of property $stmt.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
51 16
        $this->position = 0;
52 16
        $this->rowCache = [];
53 16
        $this->entityManager = new EntityManager($classpath);
54 16
    }
55
56
    /**
57
     * デストラクタ
58
     */
59 16
    public function __destruct()
60
    {
61 16
        $this->stmt = null;
62 16
        $this->rowCache = null;
63 16
    }
64
65
    /**
66
     * 初期処理
67
     */
68 16
    public function initialize()
69
    {
70 16
        $this->entityManager->inject('logger', $this->logger)
71 16
            ->setColumnMeta($this->getColumnMeta());
72 16
    }
73
74
    /**
75
     * Implements Countable#count
76
     * @return integer 結果件数
77
     */
78
    public function count()
79
    {
80
        $count = 0;
81
        if ($this->stmt === null) {
82
            $count = count($this->rowCache);
83
        } else {
84
            $count = $this->stmt->rowCount();
85
            if ($count === 0) {
86
                $this->toArray();
87
                $count = count($this->rowCache);
88
            }
89
        }
90
91
        return $count;
92
    }
93
94
    /**
95
     * Implements SeekableIterator#seek
96
     * カーソル位置を移動する
97
     * @param mixed オフセット
0 ignored issues
show
Documentation Bug introduced by
The doc comment オフセット at position 0 could not be parsed: Unknown type name 'オフセット' at position 0 in オフセット.
Loading history...
98
     */
99
    public function seek($offset)
100
    {
101
        if ($this->stmt !== null) {
102
            // Mysql does not support scrollable cursor.
103
            // but if statement to array, it is accessable.
104
            $this->toArray();
105
        }
106
        if (array_key_exists($offset, $this->rowCache)) {
107
            return $this->rowCache[$offset];
108
        } else {
109
            throw new \OutOfBoundsException("Current cursor is out of range: " . $offset);
110
        }
111
    }
112
113
    /**
114
     * Implements Iterator#current
115
     * 現在の要素を返却する
116
     * @return array<string> 列データ
117
     */
118 16
    public function current()
119
    {
120 16
        if ($this->stmt === null) {
121
            return array_key_exists($this->position, $this->rowCache) ? $this->rowCache[$this->position] : null;
122
        }
123
124 16
        return $this->entityManager->getEntity($this->row);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->entityMana...->getEntity($this->row) returns the type object which is incompatible with the documented return type string[].
Loading history...
125
    }
126
127
    /**
128
     * Implements Iterator#key
129
     * 現在の要素のキーを返却する
130
     * @return integer キー
131
     */
132 16
    public function key()
133
    {
134 16
        return $this->position;
135
    }
136
137
    /**
138
     * Implements Iterator#next
139
     * 次の要素に進む
140
     */
141 16
    public function next()
142
    {
143 16
        if ($this->stmt !== null) {
144 16
            $this->row = $this->stmt->fetch(\PDO::FETCH_ASSOC);
145
        }
146 16
        $this->position++;
147 16
    }
148
149
    /**
150
     * Implements Iterator#rewind
151
     * イテレータを先頭に巻き戻す
152
     */
153 16
    public function rewind()
154
    {
155 16
        if ($this->stmt !== null) {
156 16
            $this->row = $this->stmt->fetch(\PDO::FETCH_ASSOC, \PDO::FETCH_ORI_FIRST);
157
        }
158 16
        $this->position = 0;
159 16
    }
160
161
    /**
162
     * Implements Iterator#valid
163
     * 現在位置が有効かどうかを調べる
164
     * @return boolean 有効かどうか
165
     */
166 16
    public function valid()
167
    {
168 16
        return $this->row !== false;
169
    }
170
171
    /**
172
     * Implements ArrayAccess#offsetExists
173
     * オフセットの位置に値が存在するかどうか返却する
174
     * @return boolean 値が存在するかどうか
175
     */
176
    public function offsetExists($offset)
177
    {
178
        if ($this->stmt !== null) {
179
            $this->toArray();
180
        }
181
182
        return array_key_exists($offset, $this->rowCache);
183
    }
184
185
    /**
186
     * Implements ArrayAccess#offsetGet
187
     * オフセットの位置の値を返却する
188
     * @return mixed 値
189
     */
190
    public function offsetGet($offset)
191
    {
192
        if ($this->stmt !== null) {
193
            $this->toArray();
194
        }
195
196
        return $this->rowCache[$offset];
197
    }
198
199
    /**
200
     * Implements ArrayAccess#offsetSet
201
     * オフセットの位置に値を設定する
202
     * @param mixed オフセット
0 ignored issues
show
Documentation Bug introduced by
The doc comment オフセット at position 0 could not be parsed: Unknown type name 'オフセット' at position 0 in オフセット.
Loading history...
203
     * @param mixed 値
204
     */
205
    public function offsetSet($offset, $value)
206
    {
207
        throw new CollectionException("Database results are read only.");
208
    }
209
210
    /**
211
     * Implements ArrayAccess#offsetUnSet
212
     * オフセットの設定を解除する
213
     * @param mixed オフセット
0 ignored issues
show
Documentation Bug introduced by
The doc comment オフセット at position 0 could not be parsed: Unknown type name 'オフセット' at position 0 in オフセット.
Loading history...
214
     */
215
    public function offsetUnSet($offset)
216
    {
217
        throw new CollectionException("Database results are read only.");
218
    }
219
220
    /**
221
     * 検索結果を全て配列として返却する
222
     * @return array<string> 検索結果
223
     */
224
    public function toArray()
225
    {
226
        $this->rowCache = $this->stmt->fetchAll(\PDO::FETCH_ASSOC);
227
        $this->logger->debug("All results to array and cached.");
228
        $this->stmt = null;
229
230
        return $this->rowCache;
231
    }
232
233
    /**
234
     * テーブルのメタデータを返却する
235
     * @return array<string> メタデータ
236
     */
237 16
    private function getColumnMeta()
238
    {
239 16
        $columnMeta = [];
240 16
        for ($index = 0; $index < $this->stmt->columnCount(); $index++) {
241 16
            $column = $this->stmt->getColumnMeta($index);
242 16
            if (array_key_exists('sqlite:decl_type', $column)) {
243
                // sqlite
244 4
                $columnMeta[$column['name']] = $column['sqlite:decl_type'];
245
            } else {
246
                // mysql, postgresql
247 12
                $columnMeta[$column['name']] = $column['native_type'];
248
            }
249
        }
250
251 16
        return $columnMeta;
252
    }
253
}
254