trigger mirror
[m6w6/pq-gateway] / lib / pq / Gateway / Rowset.php
1 <?php
2
3 namespace pq\Gateway;
4
5 class Rowset implements \SeekableIterator, \Countable, \JsonSerializable
6 {
7 /**
8 * @var \pq\Gateway\Table
9 */
10 protected $table;
11
12 /**
13 * @var int
14 */
15 protected $index = 0;
16
17 /**
18 * @var array
19 */
20 protected $rows;
21
22 /**
23 * @var mixed
24 */
25 protected $row = "\\pq\\Gateway\\Row";
26
27 /**
28 * @param \pq\Gateway\Table $table
29 * @param \pq\Result $result
30 */
31 function __construct(Table $table, \pq\Result $result = null) {
32 $this->table = $table;
33 $this->hydrate($result);
34 }
35
36 /**
37 * Copy constructor
38 * @param \pq\Result $result
39 * @return \pq\Gateway\Rowset
40 */
41 function __invoke(\pq\Result $result = null) {
42 $that = clone $this;
43 $that->hydrate($result);
44 return $that;
45 }
46
47 /**
48 *
49 * @param \pq\Result $result
50 * @return array
51 */
52 protected function hydrate(\pq\Result $result = null) {
53 $this->index = 0;
54 $this->rows = array();
55
56 if ($result) {
57 $row = $this->getRowPrototype();
58
59 if (is_callable($row)) {
60 while (($data = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
61 $this->rows[] = $row($data);
62 }
63 } elseif ($row) {
64 while (($data = $result->fetchRow(\pq\Result::FETCH_ASSOC))) {
65 $this->rows[] = new $row($this->table, $data);
66 }
67 } else {
68 $this->rows = $result->fetchAll(\pq\Result::FETCH_OBJECT);
69 }
70 }
71
72 return $this;
73 }
74
75 /**
76 * Set the row prototype
77 * @param mixed $row
78 * @return \pq\Gateway\Table
79 */
80 function setRowPrototype($row) {
81 $this->row = $row;
82 return $this;
83 }
84
85 /**
86 * Get the row prototype
87 * @return mixed
88 */
89 function getRowPrototype() {
90 return $this->row;
91 }
92
93 /**
94 * @return \pq\Gateway\Table
95 */
96 function getTable() {
97 return $this->table;
98 }
99
100 /**
101 * Create all rows of this rowset
102 * @param mixed $txn
103 * @return \pq\Gateway\Rowset
104 * @throws Exception
105 */
106 function create($txn = true) {
107 if ($txn && !($txn instanceof pq\Transaction)) {
108 $txn = $this->table->getConnection()->startTransaction();
109 }
110 try {
111 foreach ($this->rows as $row) {
112 $row->create();
113 }
114 } catch (\Exception $e) {
115 if ($txn) {
116 $txn->rollback();
117 }
118 throw $e;
119 }
120 if ($txn) {
121 $txn->commit();
122 }
123 return $this;
124 }
125
126 /**
127 * Update all rows of this rowset
128 * @param mixed $txn
129 * @return \pq\Gateway\Rowset
130 * @throws \Exception
131 */
132 function update($txn = true) {
133 if ($txn && !($txn instanceof pq\Transaction)) {
134 $txn = $this->table->getConnection()->startTransaction();
135 }
136 try {
137 foreach ($this->rows as $row) {
138 $row->update();
139 }
140 } catch (\Exception $e) {
141 if ($txn) {
142 $txn->rollback();
143 }
144 throw $e;
145 }
146 if ($txn) {
147 $txn->commit();
148 }
149 return $this;
150 }
151
152 /**
153 * Delete all rows of this rowset
154 * @param mixed $txn
155 * @return \pq\Gateway\Rowset
156 * @throws \Exception
157 */
158 function delete($txn = true) {
159 if ($txn && !($txn instanceof pq\Transaction)) {
160 $txn = $this->table->getConnection()->startTransaction();
161 }
162 try {
163 foreach ($this->rows as $row) {
164 $row->delete();
165 }
166 } catch (\Exception $e) {
167 if ($txn) {
168 $txn->rollback();
169 }
170 throw $e;
171 }
172 if ($txn) {
173 $txn->commit();
174 }
175 return $this;
176 }
177
178 /**
179 * @implements JsonSerilaizable
180 */
181 function jsonSerialize() {
182 return array_map(function($row) {
183 return $row->jsonSerialize();
184 }, $this->rows);
185 }
186
187 /**
188 * @implements \Iterator
189 */
190 function rewind() {
191 $this->index = 0;
192 }
193
194 /**
195 * @implements \Iterator
196 */
197 function next() {
198 ++$this->index;
199 }
200
201 /**
202 * @implements \Iterator
203 * @return bool
204 */
205 function valid() {
206 return $this->index < count($this->rows);
207 }
208
209 /**
210 * @implements \Iterator
211 * @return \pq\Gateway\Row
212 */
213 function current() {
214 if (!$this->valid()) {
215 throw new \OutOfBoundsException("Invalid row index {$this->index}");
216 }
217 return $this->rows[$this->index];
218 }
219
220 /**
221 * @implements \Iterator
222 * @return int
223 */
224 function key() {
225 return $this->index;
226 }
227
228 /**
229 * @implements SeekableIterator
230 * @param mixed $pos
231 */
232 function seek($pos) {
233 /* only index for now */
234 $this->index = $pos;
235
236 if (!$this->valid()) {
237 throw new \OutOfBoundsException("Invalid seek position ($pos)");
238 }
239
240 return $this;
241 }
242
243 /**
244 * @implements \Countable
245 * @return int
246 */
247 function count() {
248 return count($this->rows);
249 }
250
251 /**
252 * Get the rows of this rowset
253 * @return array
254 */
255 function getRows() {
256 return $this->rows;
257 }
258
259 /**
260 * Apply a callback on each row of this rowset
261 * @param callable $cb
262 * @return \pq\Gateway\Rowset
263 */
264 function apply(callable $cb) {
265 array_walk($this->rows, $cb, $this);
266 return $this;
267 }
268
269 /**
270 * Filter by callback
271 * @param callable $cb
272 * @return \pq\Gateway\Rowset
273 */
274 function filter(callable $cb) {
275 $rowset = clone $this;
276 $rowset->index = 0;
277 $rowset->rows = array_filter($this->rows, $cb);
278 return $rowset;
279 }
280
281 /**
282 * Append a row to the rowset
283 * @param \pq\Gateway\Row $row
284 */
285 function append(Row $row) {
286 $this->rows[] = $row;
287 return $this;
288 }
289 }