/vendor/nette/nette/Nette/Database/Table/ActiveRow.php

https://bitbucket.org/iiic/iszp · PHP · 370 lines · 191 code · 96 blank · 83 comment · 20 complexity · c9c01a7c0f2b9594cfc6534489ce792d MD5 · raw file

  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (http://nette.org)
  4. *
  5. * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6. *
  7. * For the full copyright and license information, please view
  8. * the file license.txt that was distributed with this source code.
  9. */
  10. namespace Nette\Database\Table;
  11. use Nette,
  12. Nette\Database\Reflection\MissingReferenceException;
  13. /**
  14. * Single row representation.
  15. * ActiveRow is based on the great library NotORM http://www.notorm.com written by Jakub Vrana.
  16. *
  17. * @author Jakub Vrana
  18. */
  19. class ActiveRow extends Nette\Object implements \IteratorAggregate, \ArrayAccess
  20. {
  21. /** @var Selection */
  22. private $table;
  23. /** @var array of row data */
  24. private $data;
  25. /** @var bool */
  26. private $dataRefreshed = FALSE;
  27. /** @var array of new values {@see ActiveRow::update()} */
  28. private $modified = array();
  29. public function __construct(array $data, Selection $table)
  30. {
  31. $this->data = $data;
  32. $this->table = $table;
  33. }
  34. /**
  35. * @internal
  36. * @ignore
  37. */
  38. public function setTable(Selection $table)
  39. {
  40. $this->table = $table;
  41. }
  42. /**
  43. * @internal
  44. * @ignore
  45. */
  46. public function getTable()
  47. {
  48. return $this->table;
  49. }
  50. public function __toString()
  51. {
  52. try {
  53. return (string) $this->getPrimary();
  54. } catch (\Exception $e) {
  55. trigger_error("Exception in " . __METHOD__ . "(): {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}", E_USER_ERROR);
  56. }
  57. }
  58. /**
  59. * @return array
  60. */
  61. public function toArray()
  62. {
  63. $this->accessColumn(NULL);
  64. return $this->data;
  65. }
  66. /**
  67. * Returns primary key value.
  68. * @param bool
  69. * @return mixed
  70. */
  71. public function getPrimary($need = TRUE)
  72. {
  73. $primary = $this->table->getPrimary();
  74. if (!is_array($primary)) {
  75. if (isset($this->data[$primary])) {
  76. return $this->data[$primary];
  77. } elseif ($need) {
  78. throw new Nette\InvalidStateException("Row does not contain primary $primary column data.");
  79. } else {
  80. return NULL;
  81. }
  82. } else {
  83. $primaryVal = array();
  84. foreach ($primary as $key) {
  85. if (!isset($this->data[$key])) {
  86. if ($need) {
  87. throw new Nette\InvalidStateException("Row does not contain primary $key column data.");
  88. } else {
  89. return NULL;
  90. }
  91. }
  92. $primaryVal[$key] = $this->data[$key];
  93. }
  94. return $primaryVal;
  95. }
  96. }
  97. /**
  98. * Returns row signature (composition of primary keys)
  99. * @param bool
  100. * @return string
  101. */
  102. public function getSignature($need = TRUE)
  103. {
  104. return implode('|', (array) $this->getPrimary($need));
  105. }
  106. /**
  107. * Returns referenced row.
  108. * @param string
  109. * @param string
  110. * @return ActiveRow or NULL if the row does not exist
  111. */
  112. public function ref($key, $throughColumn = NULL)
  113. {
  114. if (!$throughColumn) {
  115. list($key, $throughColumn) = $this->table->getConnection()->getDatabaseReflection()->getBelongsToReference($this->table->getName(), $key);
  116. }
  117. return $this->getReference($key, $throughColumn);
  118. }
  119. /**
  120. * Returns referencing rows.
  121. * @param string
  122. * @param string
  123. * @return GroupedSelection
  124. */
  125. public function related($key, $throughColumn = NULL)
  126. {
  127. if (strpos($key, '.') !== FALSE) {
  128. list($key, $throughColumn) = explode('.', $key);
  129. } elseif (!$throughColumn) {
  130. list($key, $throughColumn) = $this->table->getConnection()->getDatabaseReflection()->getHasManyReference($this->table->getName(), $key);
  131. }
  132. return $this->table->getReferencingTable($key, $throughColumn, $this[$this->table->getPrimary()]);
  133. }
  134. /**
  135. * Updates row.
  136. * @param array or NULL for all modified values
  137. * @return int number of affected rows or FALSE in case of an error
  138. */
  139. public function update($data = NULL)
  140. {
  141. if ($data === NULL) {
  142. $data = $this->modified;
  143. }
  144. return $this->table->getConnection()
  145. ->table($this->table->getName())
  146. ->wherePrimary($this->getPrimary())
  147. ->update($data);
  148. }
  149. /**
  150. * Deletes row.
  151. * @return int number of affected rows or FALSE in case of an error
  152. */
  153. public function delete()
  154. {
  155. $res = $this->table->getConnection()
  156. ->table($this->table->getName())
  157. ->wherePrimary($this->getPrimary())
  158. ->delete();
  159. if ($res > 0 && ($signature = $this->getSignature(FALSE))) {
  160. unset($this->table[$signature]);
  161. }
  162. return $res;
  163. }
  164. /********************* interface IteratorAggregate ****************d*g**/
  165. public function getIterator()
  166. {
  167. $this->accessColumn(NULL);
  168. return new \ArrayIterator($this->data);
  169. }
  170. /********************* interface ArrayAccess & magic accessors ****************d*g**/
  171. /**
  172. * Stores value in column.
  173. * @param string column name
  174. * @param string value
  175. * @return void
  176. */
  177. public function offsetSet($key, $value)
  178. {
  179. $this->__set($key, $value);
  180. }
  181. /**
  182. * Returns value of column.
  183. * @param string column name
  184. * @return string
  185. */
  186. public function offsetGet($key)
  187. {
  188. return $this->__get($key);
  189. }
  190. /**
  191. * Tests if column exists.
  192. * @param string column name
  193. * @return bool
  194. */
  195. public function offsetExists($key)
  196. {
  197. return $this->__isset($key);
  198. }
  199. /**
  200. * Removes column from data.
  201. * @param string column name
  202. * @return void
  203. */
  204. public function offsetUnset($key)
  205. {
  206. $this->__unset($key);
  207. }
  208. public function __set($key, $value)
  209. {
  210. $this->data[$key] = $value;
  211. $this->modified[$key] = $value;
  212. }
  213. public function &__get($key)
  214. {
  215. $this->accessColumn($key);
  216. if (array_key_exists($key, $this->data)) {
  217. return $this->data[$key];
  218. }
  219. try {
  220. list($table, $column) = $this->table->getConnection()->getDatabaseReflection()->getBelongsToReference($this->table->getName(), $key);
  221. $referenced = $this->getReference($table, $column);
  222. if ($referenced !== FALSE) {
  223. $this->accessColumn($key, FALSE);
  224. return $referenced;
  225. }
  226. } catch(MissingReferenceException $e) {}
  227. $this->removeAccessColumn($key);
  228. throw new Nette\MemberAccessException("Cannot read an undeclared column \"$key\".");
  229. }
  230. public function __isset($key)
  231. {
  232. $this->accessColumn($key);
  233. if (array_key_exists($key, $this->data)) {
  234. return isset($this->data[$key]);
  235. }
  236. $this->removeAccessColumn($key);
  237. return FALSE;
  238. }
  239. public function __unset($key)
  240. {
  241. unset($this->data[$key]);
  242. unset($this->modified[$key]);
  243. }
  244. protected function accessColumn($key, $selectColumn = TRUE)
  245. {
  246. if (isset($this->modified[$key])) {
  247. return;
  248. }
  249. $this->table->accessColumn($key, $selectColumn);
  250. if ($this->table->getDataRefreshed() && !$this->dataRefreshed) {
  251. $this->data = $this->table[$this->getSignature()]->data;
  252. $this->dataRefreshed = TRUE;
  253. }
  254. }
  255. protected function removeAccessColumn($key)
  256. {
  257. $this->table->removeAccessColumn($key);
  258. }
  259. protected function getReference($table, $column)
  260. {
  261. $this->accessColumn($column);
  262. if (array_key_exists($column, $this->data)) {
  263. $value = $this->data[$column];
  264. $value = $value instanceof ActiveRow ? $value->getPrimary() : $value;
  265. $referenced = $this->table->getReferencedTable($table, $column, !empty($this->modified[$column]));
  266. $referenced = isset($referenced[$value]) ? $referenced[$value] : NULL; // referenced row may not exist
  267. if (!empty($this->modified[$column])) { // cause saving changed column and prevent regenerating referenced table for $column
  268. $this->modified[$column] = 0; // 0 fails on empty, pass on isset
  269. }
  270. return $referenced;
  271. }
  272. return FALSE;
  273. }
  274. }