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