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