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