1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20: 21:
22: class TableRow extends Object implements IteratorAggregate, ArrayAccess
23: {
24:
25: private $table;
26:
27:
28: private $data;
29:
30:
31: private $dataRefreshed = FALSE;
32:
33:
34: private $modified = array();
35:
36:
37: public function __construct(array $data, TableSelection $table)
38: {
39: $this->data = $data;
40: $this->table = $table;
41: }
42:
43:
44: 45: 46: 47:
48: public function setTable(TableSelection $table)
49: {
50: $this->table = $table;
51: }
52:
53:
54: 55: 56: 57:
58: public function getTable()
59: {
60: return $this->table;
61: }
62:
63:
64: public function __toString()
65: {
66: try {
67: return (string) $this->getPrimary();
68: } catch (Exception $e) {
69: trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
70: }
71: }
72:
73:
74: 75: 76:
77: public function toArray()
78: {
79: $this->accessColumn(NULL);
80: return $this->data;
81: }
82:
83:
84: 85: 86: 87: 88:
89: public function getPrimary($need = TRUE)
90: {
91: $primary = $this->table->getPrimary($need);
92: if ($primary === NULL) {
93: return NULL;
94:
95: } elseif (!is_array($primary)) {
96: if (isset($this->data[$primary])) {
97: return $this->data[$primary];
98: } elseif ($need) {
99: throw new InvalidStateException("Row does not contain primary $primary column data.");
100: } else {
101: return NULL;
102: }
103:
104: } else {
105: $primaryVal = array();
106: foreach ($primary as $key) {
107: if (!isset($this->data[$key])) {
108: if ($need) {
109: throw new InvalidStateException("Row does not contain primary $key column data.");
110: } else {
111: return NULL;
112: }
113: }
114: $primaryVal[$key] = $this->data[$key];
115: }
116: return $primaryVal;
117: }
118: }
119:
120:
121: 122: 123: 124: 125:
126: public function getSignature($need = TRUE)
127: {
128: return implode('|', (array) $this->getPrimary($need));
129: }
130:
131:
132: 133: 134: 135: 136: 137:
138: public function ref($key, $throughColumn = NULL)
139: {
140: if (!$throughColumn) {
141: list($key, $throughColumn) = $this->table->getConnection()->getDatabaseReflection()->getBelongsToReference($this->table->getName(), $key);
142: }
143:
144: return $this->getReference($key, $throughColumn);
145: }
146:
147:
148: 149: 150: 151: 152: 153:
154: public function related($key, $throughColumn = NULL)
155: {
156: if (strpos($key, '.') !== FALSE) {
157: list($key, $throughColumn) = explode('.', $key);
158: } elseif (!$throughColumn) {
159: list($key, $throughColumn) = $this->table->getConnection()->getDatabaseReflection()->getHasManyReference($this->table->getName(), $key);
160: }
161:
162: return $this->table->getReferencingTable($key, $throughColumn, $this[$this->table->getPrimary()]);
163: }
164:
165:
166: 167: 168: 169: 170:
171: public function update($data = NULL)
172: {
173: if ($data instanceof Traversable) {
174: $data = iterator_to_array($data);
175: }
176: if ($data === NULL) {
177: $data = $this->modified;
178: }
179: return $this->table->getConnection()
180: ->table($this->table->getName())
181: ->wherePrimary($this->getPrimary())
182: ->update($data);
183: }
184:
185:
186: 187: 188: 189:
190: public function delete()
191: {
192: $res = $this->table->getConnection()
193: ->table($this->table->getName())
194: ->wherePrimary($this->getPrimary())
195: ->delete();
196:
197: if ($res > 0 && ($signature = $this->getSignature(FALSE))) {
198: unset($this->table[$signature]);
199: }
200:
201: return $res;
202: }
203:
204:
205:
206:
207:
208: public function getIterator()
209: {
210: $this->accessColumn(NULL);
211: return new ArrayIterator($this->data);
212: }
213:
214:
215:
216:
217:
218: 219: 220: 221: 222: 223:
224: public function offsetSet($key, $value)
225: {
226: $this->__set($key, $value);
227: }
228:
229:
230: 231: 232: 233: 234:
235: public function offsetGet($key)
236: {
237: return $this->__get($key);
238: }
239:
240:
241: 242: 243: 244: 245:
246: public function offsetExists($key)
247: {
248: return $this->__isset($key);
249: }
250:
251:
252: 253: 254: 255: 256:
257: public function offsetUnset($key)
258: {
259: $this->__unset($key);
260: }
261:
262:
263: public function __set($key, $value)
264: {
265: $this->data[$key] = $value;
266: $this->modified[$key] = $value;
267: }
268:
269:
270: public function &__get($key)
271: {
272: $this->accessColumn($key);
273: if (array_key_exists($key, $this->data)) {
274: return $this->data[$key];
275: }
276:
277: try {
278: list($table, $column) = $this->table->getConnection()->getDatabaseReflection()->getBelongsToReference($this->table->getName(), $key);
279: $referenced = $this->getReference($table, $column);
280: if ($referenced !== FALSE) {
281: $this->accessColumn($key, FALSE);
282: return $referenced;
283: }
284: } catch(MissingReferenceException $e) {}
285:
286: $this->removeAccessColumn($key);
287: throw new MemberAccessException("Cannot read an undeclared column \"$key\".");
288: }
289:
290:
291: public function __isset($key)
292: {
293: $this->accessColumn($key);
294: if (array_key_exists($key, $this->data)) {
295: return isset($this->data[$key]);
296: }
297: $this->removeAccessColumn($key);
298: return FALSE;
299: }
300:
301:
302: public function __unset($key)
303: {
304: unset($this->data[$key]);
305: unset($this->modified[$key]);
306: }
307:
308:
309: protected function accessColumn($key, $selectColumn = TRUE)
310: {
311: if (isset($this->modified[$key])) {
312: return;
313: }
314:
315: $this->table->accessColumn($key, $selectColumn);
316: if ($this->table->getDataRefreshed() && !$this->dataRefreshed) {
317: $this->data = $this->table[$this->getSignature()]->data;
318: $this->dataRefreshed = TRUE;
319: }
320: }
321:
322:
323: protected function removeAccessColumn($key)
324: {
325: $this->table->removeAccessColumn($key);
326: }
327:
328:
329: protected function getReference($table, $column)
330: {
331: $this->accessColumn($column);
332: if (array_key_exists($column, $this->data)) {
333: $value = $this->data[$column];
334: $value = $value instanceof TableRow ? $value->getPrimary() : $value;
335:
336: $referenced = $this->table->getReferencedTable($table, $column, !empty($this->modified[$column]));
337: $referenced = isset($referenced[$value]) ? $referenced[$value] : NULL;
338:
339: if (!empty($this->modified[$column])) {
340: $this->modified[$column] = 0;
341: }
342:
343: return $referenced;
344: }
345:
346: return FALSE;
347: }
348:
349: }
350: