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