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