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