/lib/Fz/Db/Table/Row/Abstract.php

https://github.com/ianbogda/FileZ · PHP · 305 lines · 142 code · 40 blank · 123 comment · 19 complexity · 2bbd97c7ebf1cf9adbec5c49490c4be6 MD5 · raw file

  1. <?php
  2. /**
  3. * @file
  4. * Short description.
  5. *
  6. * Long description.
  7. *
  8. * @package FileZ
  9. */
  10. /**
  11. * Fz_Db_Table_Row_Abstract
  12. */
  13. abstract class Fz_Db_Table_Row_Abstract {
  14. protected $_updatedColumns = array ();
  15. protected $_sqlModifiers = array ();
  16. protected $_data = array ();
  17. protected $_exists = false;
  18. protected $_tableClass ;
  19. /**
  20. * Constructor
  21. *
  22. * @return Fz_Table_Row
  23. */
  24. public function __construct ($exists = false) {
  25. $this->_exists = $exists;
  26. }
  27. /**
  28. * Table row getter from column name. ex: $row->column_name
  29. *
  30. * @param string $var Column name
  31. * @return mixed Column value
  32. */
  33. public function __get ($var) {
  34. if (array_key_exists ($var, $this->_data))
  35. return $this->_data [$var];
  36. else if (in_array ($var, $this->getTable()->getTableColumns ()))
  37. return null;
  38. else
  39. throw new Exception ('Unknown table attribute "'.$var.'"');
  40. }
  41. /**
  42. * Table row getter from column name. ex: $row->getColumnName ()
  43. */
  44. public function __call ($method, $args) {
  45. if (method_exists ($this, $method))
  46. return call_user_func_array (array ($this, $method), $args);
  47. $var = substr ($method, 3);
  48. $var[0] = strtolower ($var[0]);
  49. $func = create_function ('$c', 'return "_" . strtolower ($c[1]);');
  50. $var = preg_replace_callback ('/([A-Z])/', $func, $var);
  51. if (substr ($method, 0, 3) == 'get') {
  52. return $this->$var;
  53. } else if (substr ($method, 0, 3) == 'set') {
  54. return $this->$var = $args[0]; // TODO check args size & trigger error
  55. } else {
  56. throw new Exception ('Unknown method "'.$method.'"');
  57. }
  58. }
  59. /**
  60. * Table row setter from column name. ex: $row->column_name = 'foo';
  61. *
  62. * @param string $var Column name
  63. * @param mixed $value Column value
  64. * @return mixed Column value
  65. */
  66. public function __set ($var, $value) {
  67. if (array_key_exists ($var, $this->_data) && $this->_data [$var] == $value)
  68. return $value;
  69. $this->_data [$var] = $value;
  70. $this->_updatedColumns [] = $var;
  71. return $value;
  72. }
  73. /**
  74. *
  75. * @param string $var Column name
  76. * @return boolean
  77. */
  78. public function __isset ($var) {
  79. return in_array ($var, $this->getTable()->getTableColumns ());
  80. }
  81. /**
  82. * Transform a string from underscore_format to CamelFormat
  83. *
  84. * @param string $var
  85. * @return string
  86. */
  87. private static function camelify ($var) {
  88. return str_replace (' ', '', ucwords (str_replace ('_', ' ', $var)));
  89. }
  90. /**
  91. * Return a string representation of the table row ('id' by default)
  92. *
  93. * @return string
  94. */
  95. public function __toString () {
  96. return $this->id;
  97. }
  98. /**
  99. * Return an array reprensentation of the table row.
  100. * Custom getter will be called if they exist.
  101. *
  102. * @return array
  103. */
  104. public function toArray () {
  105. $array = array ();
  106. foreach ($this->getTableColumns as $column) {
  107. $method = 'get'.self::camelify ($var);
  108. $array [$column] = method_exists ($this, $method) ?
  109. call_user_method_array (array ($this, $method)) : $this->$var;
  110. }
  111. return $array;
  112. }
  113. /**
  114. * Return an array of all updated columns since last select/update
  115. *
  116. * @return array Columns name
  117. */
  118. public function getUpdatedColumns () {
  119. return array_unique ($this->_updatedColumns);
  120. }
  121. /**
  122. * Save a row into the database
  123. *
  124. * @return self
  125. */
  126. public function save () {
  127. if ($this->_exists)
  128. $this->update ();
  129. else
  130. $this->insert ();
  131. $this->resetModifiedColumns();
  132. $this->_exists = true;
  133. return $this;
  134. }
  135. /**
  136. * Save an existing row into the database
  137. *
  138. * @return self
  139. */
  140. protected function update () {
  141. $db = option ('db_conn');
  142. $table = $this->getTableName ();
  143. $columnsName = $this->getUpdatedColumns ();
  144. $sqlModifiersColumnsName = array_keys ($this->_sqlModifiers);
  145. $unmodifiedColumns = array_diff ($columnsName, $sqlModifiersColumnsName);
  146. if (count ($columnsName) == 0 && count ($sqlModifiersColumnsName) == 0)
  147. return $this;
  148. array_walk ($this->_sqlModifiers, array ('Fz_Db','nameEqSql'));
  149. $sql = "UPDATE `$table` SET " .
  150. implode (', ', array_merge (array_map (array ('Fz_Db','nameEqColonName'),$unmodifiedColumns), $this->_sqlModifiers)) .
  151. ' WHERE id = :id';
  152. fz_log ($sql, FZ_LOG_DEBUG);
  153. $stmt = $db->prepare ($sql);
  154. $stmt->bindValue (':id', $this->id);
  155. $this->bindUpdatedColumnsValues ($stmt);
  156. $stmt->execute ();
  157. return $this;
  158. }
  159. /**
  160. * Save a new row into the database
  161. *
  162. * @return self
  163. */
  164. protected function insert () {
  165. $db = option ('db_conn');
  166. $table = $this->getTableName ();
  167. $columnsName = $this->getUpdatedColumns ();
  168. $sqlModifiersColumnsName = array_keys ($this->_sqlModifiers);
  169. $unmodifiedColumns = array_diff ($columnsName, $sqlModifiersColumnsName);
  170. $sql =
  171. "INSERT INTO `$table` (" .
  172. implode (', ', array_merge ($unmodifiedColumns, $sqlModifiersColumnsName)) . // reorder columns
  173. ') VALUES (' .
  174. implode (', ', array_merge (array_map (array ('Fz_Db','addColon'), $unmodifiedColumns), $this->_sqlModifiers)) . ')';
  175. fz_log ($sql, FZ_LOG_DEBUG);
  176. $stmt = $db->prepare ($sql);
  177. $this->bindUpdatedColumnsValues ($stmt);
  178. $stmt->execute ();
  179. return $db->lastInsertId ();
  180. }
  181. /**
  182. * Delete an existing row from the database
  183. */
  184. public function delete () {
  185. $db = option ('db_conn');
  186. if ($this->_exists === false) return;
  187. $stmt = $db->prepare ('DELETE FROM `'.$this->getTableName ().'` WHERE id = ?');
  188. $stmt->execute (array ($this->id));
  189. }
  190. /**
  191. * Bind updated object values to the prepared statement
  192. *
  193. * @param PDO_Statement $stmt
  194. * @return PDO_Statement
  195. */
  196. private function bindUpdatedColumnsValues ($stmt) {
  197. foreach ($this->getUpdatedColumns () as $column)
  198. $stmt->bindValue (':'.$column, $this->_data[$column]);
  199. return $stmt;
  200. }
  201. /**
  202. * Return a string representation of the object for debug purpose
  203. *
  204. * @return string
  205. */
  206. public function debug () {
  207. echo "\n";
  208. foreach ($this->getTableColumns () as $c) {
  209. echo $c.': '.$this->$c."\n";
  210. }
  211. }
  212. /**
  213. * Return the table name of the current row
  214. *
  215. * @return string Table name
  216. */
  217. public function getTableName () {
  218. return $this->getTable ()->getTableName ();
  219. }
  220. /**
  221. * Return the table object of the current row
  222. *
  223. * @return Fz_Table_Abstract
  224. */
  225. public function getTable () {
  226. return Fz_Db::getTable ($this->_tableClass);
  227. }
  228. /**
  229. * Return all columns name from the current table row
  230. *
  231. * @return array
  232. */
  233. public function getTableColumns () {
  234. return $this->getTable ()->getTableColumns ();
  235. }
  236. /**
  237. * Indicate whether the object exists or not
  238. *
  239. * @param boolean
  240. */
  241. protected function setExist ($exists) {
  242. $this->_exists = $exists;
  243. }
  244. /**
  245. * Reset the updated columns references
  246. */
  247. public function resetModifiedColumns () {
  248. $this->_updatedColumns = array ();
  249. }
  250. /**
  251. * Use this method when you want to execute your custom sql to alter the
  252. * value of a column.
  253. *
  254. * To make a reference to the user value, for the password column for
  255. * example, use :password in your sql command.
  256. *
  257. * Ex: $user->setColumnModifier ('password', 'SHA1(:password)');
  258. *
  259. * @param string $columnName
  260. * @param string $sql
  261. */
  262. public function setColumnModifier ($columnName, $sql) {
  263. $this->_sqlModifiers [$columnName] = $sql;
  264. }
  265. }