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