flush
[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 bool $txn
103 * @return \pq\Gateway\Rowset
104 * @throws Exception
105 */
106 function create($txn = true) {
107 $txn = $txn ? $this->table->getConnection()->startTransaction() : false;
108 try {
109 foreach ($this->rows as $row) {
110 $row->create();
111 }
112 } catch (\Exception $e) {
113 if ($txn) {
114 $txn->rollback();
115 }
116 throw $e;
117 }
118 if ($txn) {
119 $txn->commit();
120 }
121 return $this;
122 }
123
124 /**
125 * Update all rows of this rowset
126 * @param bool $txn
127 * @return \pq\Gateway\Rowset
128 * @throws \Exception
129 */
130 function update($txn = true) {
131 $txn = $txn ? $this->table->getConnection()->startTransaction() : false;
132 try {
133 foreach ($this->rows as $row) {
134 $row->update();
135 }
136 } catch (\Exception $e) {
137 if ($txn) {
138 $txn->rollback();
139 }
140 throw $e;
141 }
142 if ($txn) {
143 $txn->commit();
144 }
145 return $this;
146 }
147
148 /**
149 * Delete all rows of this rowset
150 * @param type $txn
151 * @return \pq\Gateway\Rowset
152 * @throws \Exception
153 */
154 function delete($txn = true) {
155 $txn = $txn ? $this->table->getConnection()->startTransaction() : false;
156 try {
157 foreach ($this->rows as $row) {
158 $row->delete();
159 }
160 } catch (\Exception $e) {
161 if ($txn) {
162 $txn->rollback();
163 }
164 throw $e;
165 }
166 if ($txn) {
167 $txn->commit();
168 }
169 return $this;
170 }
171
172 /**
173 * @implements JsonSerilaizable
174 */
175 function jsonSerialize() {
176 return array_map(function($row) {
177 return $row->jsonSerialize();
178 }, $this->rows);
179 }
180
181 /**
182 * @implements \Iterator
183 */
184 function rewind() {
185 $this->index = 0;
186 }
187
188 /**
189 * @implements \Iterator
190 */
191 function next() {
192 ++$this->index;
193 }
194
195 /**
196 * @implements \Iterator
197 * @return bool
198 */
199 function valid() {
200 return $this->index < count($this->rows);
201 }
202
203 /**
204 * @implements \Iterator
205 * @return \pq\Gateway\Row
206 */
207 function current() {
208 if (!$this->valid()) {
209 throw new OutOfBoundsException("Invalid row index {$this->index}");
210 }
211 return $this->rows[$this->index];
212 }
213
214 /**
215 * @implements \Iterator
216 * @return int
217 */
218 function key() {
219 return $this->index;
220 }
221
222 /**
223 * @implements SeekableIterator
224 * @param mixed $pos
225 */
226 function seek($pos) {
227 /* only index for now */
228 $this->index = $pos;
229
230 if (!$this->valid()) {
231 throw new \OutOfBoundsException("Invalid seek position ($pos)");
232 }
233
234 return $this;
235 }
236
237 /**
238 * @implements \Countable
239 * @return int
240 */
241 function count() {
242 return count($this->rows);
243 }
244
245 /**
246 * Get the rows of this rowset
247 * @return array
248 */
249 function getRows() {
250 return $this->rows;
251 }
252
253 /**
254 * Apply a callback on each row of this rowset
255 * @param callable $cb
256 * @return \pq\Gateway\Rowset
257 */
258 function apply(callable $cb) {
259 array_walk($this->rows, $cb, $this);
260 return $this;
261 }
262
263 /**
264 * Filter by callback
265 * @param callable $cb
266 * @return \pq\Gateway\Rowset
267 */
268 function filter(callable $cb) {
269 $rowset = clone $this;
270 $rowset->index = 0;
271 $rowset->rows = array_filter($this->rows, $cb);
272 return $rowset;
273 }
274
275 /**
276 * Append a row to the rowset
277 * @param \pq\Gateway\Row $row
278 */
279 function append(Row $row) {
280 $this->rows[] = $row;
281 return $this;
282 }
283 }