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