1
|
|
|
<?php |
2
|
|
|
namespace Cassandra\Response; |
3
|
|
|
use Cassandra\Protocol\Frame; |
4
|
|
|
use Cassandra\Type; |
5
|
|
|
|
6
|
|
|
class Result extends Response { |
7
|
|
|
const VOID = 0x0001; |
8
|
|
|
const ROWS = 0x0002; |
9
|
|
|
const SET_KEYSPACE = 0x0003; |
10
|
|
|
const PREPARED = 0x0004; |
11
|
|
|
const SCHEMA_CHANGE = 0x0005; |
12
|
|
|
|
13
|
|
|
const ROWS_FLAG_GLOBAL_TABLES_SPEC = 0x0001; |
14
|
|
|
const ROWS_FLAG_HAS_MORE_PAGES = 0x0002; |
15
|
|
|
const ROWS_FLAG_NO_METADATA = 0x0004; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* |
19
|
|
|
* @var int |
20
|
|
|
*/ |
21
|
|
|
protected $_kind; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* |
25
|
|
|
* @var array |
26
|
|
|
*/ |
27
|
|
|
protected $_metadata; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* |
31
|
|
|
* @var string |
32
|
|
|
*/ |
33
|
|
|
protected $_rowClass; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @return \SplFixedArray|string|array|null |
37
|
|
|
*/ |
38
|
|
|
public function getData() { |
39
|
|
|
$this->_stream->offset(4); |
40
|
|
|
switch($this->getKind()) { |
41
|
|
|
case self::VOID: |
42
|
|
|
return null; |
43
|
|
|
|
44
|
|
|
case self::ROWS: |
45
|
|
|
return $this->fetchAll(); |
46
|
|
|
|
47
|
|
|
case self::SET_KEYSPACE: |
48
|
|
|
return $this->_stream->readString(); |
49
|
|
|
|
50
|
|
|
case self::PREPARED: |
51
|
|
|
return [ |
52
|
|
|
'id' => $this->_stream->readString(), |
53
|
|
|
'metadata' => $this->_readMetadata(), |
54
|
|
|
'result_metadata' => $this->_readMetadata(), |
55
|
|
|
]; |
56
|
|
|
|
57
|
|
|
case self::SCHEMA_CHANGE: |
58
|
|
|
return [ |
59
|
|
|
'change' => $this->_stream->readString(), |
60
|
|
|
'keyspace' => $this->_stream->readString(), |
61
|
|
|
'table' => $this->_stream->readString() |
62
|
|
|
]; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
return null; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
public function getKind(){ |
69
|
|
|
if ($this->_kind === null){ |
70
|
|
|
$this->_stream->offset(0); |
71
|
|
|
$this->_kind = $this->_stream->readInt(); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
return $this->_kind; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
/** |
78
|
|
|
* |
79
|
|
|
* @param array $metadata |
80
|
|
|
* @return self |
81
|
|
|
*/ |
82
|
|
|
public function setMetadata(array $metadata) { |
83
|
|
|
$this->_metadata = $metadata; |
84
|
|
|
|
85
|
|
|
return $this; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* |
90
|
|
|
* @return array |
91
|
|
|
*/ |
92
|
|
|
public function getMetadata(){ |
93
|
|
|
if (empty($this->_metadata)){ |
94
|
|
|
$this->_stream->offset(4); |
95
|
|
|
$this->_metadata = $this->_readMetadata(); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
return $this->_metadata; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* |
103
|
|
|
* @param string $rowClass |
104
|
|
|
* @return self |
105
|
|
|
*/ |
106
|
|
|
public function setRowClass($rowClass) { |
107
|
|
|
$this->_rowClass = $rowClass; |
108
|
|
|
|
109
|
|
|
return $this; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Return metadata |
114
|
|
|
* @return array |
115
|
|
|
*/ |
116
|
|
|
protected function _readMetadata() { |
117
|
|
|
$metadata = [ |
118
|
|
|
'flags' => $this->_stream->readInt(), |
119
|
|
|
'columns_count' => $this->_stream->readInt(), |
120
|
|
|
]; |
121
|
|
|
$flags = $metadata['flags']; |
122
|
|
|
|
123
|
|
|
if ($flags & self::ROWS_FLAG_HAS_MORE_PAGES) |
124
|
|
|
$metadata['page_state'] = $this->_stream->readBytes(); |
125
|
|
|
|
126
|
|
|
if (!($flags & self::ROWS_FLAG_NO_METADATA)) { |
127
|
|
|
$metadata['columns'] = []; |
128
|
|
|
|
129
|
|
|
if ($flags & self::ROWS_FLAG_GLOBAL_TABLES_SPEC) { |
130
|
|
|
$keyspace = $this->_stream->readString(); |
131
|
|
|
$tableName = $this->_stream->readString(); |
132
|
|
|
|
133
|
|
|
for ($i = 0; $i < $metadata['columns_count']; ++$i) { |
134
|
|
|
$metadata['columns'][] = [ |
135
|
|
|
'keyspace' => $keyspace, |
136
|
|
|
'tableName' => $tableName, |
137
|
|
|
'name' => $this->_stream->readString(), |
138
|
|
|
'type' => $this->_stream->readType() |
139
|
|
|
]; |
140
|
|
|
} |
141
|
|
|
} |
142
|
|
|
else { |
143
|
|
|
for ($i = 0; $i < $metadata['columns_count']; ++$i) { |
144
|
|
|
$metadata['columns'][] = [ |
145
|
|
|
'keyspace' => $this->_stream->readString(), |
146
|
|
|
'tableName' => $this->_stream->readString(), |
147
|
|
|
'name' => $this->_stream->readString(), |
148
|
|
|
'type' => $this->_stream->readType() |
149
|
|
|
]; |
150
|
|
|
} |
151
|
|
|
} |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
return $metadata; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
/** |
158
|
|
|
* |
159
|
|
|
* @param string $rowClass |
160
|
|
|
* @throws Exception |
161
|
|
|
* @return \SplFixedArray |
162
|
|
|
*/ |
163
|
|
|
public function fetchAll($rowClass = null){ |
164
|
|
|
if ($this->getKind() !== self::ROWS){ |
165
|
|
|
throw new Exception('Unexpected Response: ' . $this->getKind()); |
166
|
|
|
} |
167
|
|
|
$this->_stream->offset(4); |
168
|
|
|
$this->_metadata = $this->_metadata ? array_merge($this->_metadata, $this->_readMetadata()) : $this->_readMetadata(); |
169
|
|
|
|
170
|
|
|
if (!isset($this->_metadata['columns'])) |
171
|
|
|
throw new Exception('Missing Result Metadata'); |
172
|
|
|
|
173
|
|
|
$rowCount = $this->_stream->readInt(); |
174
|
|
|
$rows = new \SplFixedArray($rowCount); |
175
|
|
|
|
176
|
|
|
if ($rowClass === null) |
177
|
|
|
$rowClass = $this->_rowClass; |
178
|
|
|
|
179
|
|
|
for ($i = 0; $i < $rowCount; ++$i) { |
180
|
|
|
$data = []; |
181
|
|
|
|
182
|
|
View Code Duplication |
foreach ($this->_metadata['columns'] as $column) |
|
|
|
|
183
|
|
|
$data[$column['name']] = $this->_stream->readValue($column['type']); |
184
|
|
|
|
185
|
|
|
$rows[$i] = $rowClass === null ? $data : new $rowClass($data); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
return $rows; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* |
193
|
|
|
* @param int $index |
194
|
|
|
* @throws Exception |
195
|
|
|
* @return \SplFixedArray |
196
|
|
|
*/ |
197
|
|
|
public function fetchCol($index = 0){ |
198
|
|
|
if ($this->getKind() !== self::ROWS){ |
199
|
|
|
throw new Exception('Unexpected Response: ' . $this->getKind()); |
200
|
|
|
} |
201
|
|
|
$this->_stream->offset(4); |
202
|
|
|
$this->_metadata = $this->_metadata ? array_merge($this->_metadata, $this->_readMetadata()) : $this->_readMetadata(); |
203
|
|
|
|
204
|
|
|
if (!isset($this->_metadata['columns'])) |
205
|
|
|
throw new Exception('Missing Result Metadata'); |
206
|
|
|
|
207
|
|
|
$rowCount = $this->_stream->readInt(); |
208
|
|
|
|
209
|
|
|
$array = new \SplFixedArray($rowCount); |
210
|
|
|
|
211
|
|
|
for($i = 0; $i < $rowCount; ++$i){ |
212
|
|
|
foreach($this->_metadata['columns'] as $j => $column){ |
213
|
|
|
$value = $this->_stream->readValue($column['type']); |
214
|
|
|
|
215
|
|
|
if ($j == $index) |
216
|
|
|
$array[$i] = $value; |
217
|
|
|
} |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
return $array; |
221
|
|
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* |
225
|
|
|
* @throws Exception |
226
|
|
|
* @return array |
227
|
|
|
*/ |
228
|
|
|
public function fetchPairs(){ |
229
|
|
|
if ($this->getKind() !== self::ROWS){ |
230
|
|
|
throw new Exception('Unexpected Response: ' . $this->getKind()); |
231
|
|
|
} |
232
|
|
|
$this->_stream->offset(4); |
233
|
|
|
$this->_metadata = $this->_metadata ? array_merge($this->_metadata, $this->_readMetadata()) : $this->_readMetadata(); |
234
|
|
|
|
235
|
|
|
if (!isset($this->_metadata['columns'])) |
236
|
|
|
throw new Exception('Missing Result Metadata'); |
237
|
|
|
|
238
|
|
|
$rowCount = $this->_stream->readInt(); |
239
|
|
|
|
240
|
|
|
$map = []; |
241
|
|
|
|
242
|
|
|
for($i = 0; $i < $rowCount; ++$i){ |
243
|
|
|
foreach($this->_metadata['columns'] as $j => $column){ |
244
|
|
|
$value = $this->_stream->readValue($column['type']); |
245
|
|
|
|
246
|
|
|
if ($j === 0){ |
247
|
|
|
$key = $value; |
248
|
|
|
} |
249
|
|
|
elseif($j === 1){ |
250
|
|
|
$map[$key] = $value; |
|
|
|
|
251
|
|
|
} |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
return $map; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* |
260
|
|
|
* @param string $rowClass |
261
|
|
|
* @throws Exception |
262
|
|
|
* @return \ArrayObject |
263
|
|
|
*/ |
264
|
|
|
public function fetchRow($rowClass = null){ |
265
|
|
|
if ($this->getKind() !== self::ROWS){ |
266
|
|
|
throw new Exception('Unexpected Response: ' . $this->getKind()); |
267
|
|
|
} |
268
|
|
|
$this->_stream->offset(4); |
269
|
|
|
$this->_metadata = $this->_metadata ? array_merge($this->_metadata, $this->_readMetadata()) : $this->_readMetadata(); |
270
|
|
|
|
271
|
|
|
if (!isset($this->_metadata['columns'])) |
272
|
|
|
throw new Exception('Missing Result Metadata'); |
273
|
|
|
|
274
|
|
|
$rowCount = $this->_stream->readInt(); |
275
|
|
|
|
276
|
|
|
if ($rowCount === 0) |
277
|
|
|
return null; |
278
|
|
|
|
279
|
|
|
if ($rowClass === null) |
280
|
|
|
$rowClass = $this->_rowClass; |
281
|
|
|
|
282
|
|
|
$data = []; |
283
|
|
View Code Duplication |
foreach ($this->_metadata['columns'] as $column) |
|
|
|
|
284
|
|
|
$data[$column['name']] = $this->_stream->readValue($column['type']); |
285
|
|
|
|
286
|
|
|
return $rowClass === null ? $data : new $rowClass($data); |
|
|
|
|
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
/** |
290
|
|
|
* |
291
|
|
|
* @throws Exception |
292
|
|
|
* @return mixed |
293
|
|
|
*/ |
294
|
|
|
public function fetchOne(){ |
295
|
|
|
if ($this->getKind() !== self::ROWS){ |
296
|
|
|
throw new Exception('Unexpected Response: ' . $this->getKind()); |
297
|
|
|
} |
298
|
|
|
$this->_stream->offset(4); |
299
|
|
|
$this->_metadata = $this->_metadata ? array_merge($this->_metadata, $this->_readMetadata()) : $this->_readMetadata(); |
300
|
|
|
|
301
|
|
|
if (!isset($this->_metadata['columns'])) |
302
|
|
|
throw new Exception('Missing Result Metadata'); |
303
|
|
|
|
304
|
|
|
$rowCount = $this->_stream->readInt(); |
305
|
|
|
|
306
|
|
|
if ($rowCount === 0) |
307
|
|
|
return null; |
308
|
|
|
|
309
|
|
|
foreach ($this->_metadata['columns'] as $column) |
310
|
|
|
return $this->_stream->readValue($column['type']); |
311
|
|
|
|
312
|
|
|
return null; |
313
|
|
|
} |
314
|
|
|
} |
315
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.