PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/akelos_utils/contrib/pear/DB/storage.php

https://github.com/bermi/akelos
PHP | 445 lines | 246 code | 23 blank | 176 comment | 46 complexity | 933507dee931dcdb612b552bc3d1bf9d MD5 | raw file
  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2001 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available at through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stig Bakken <stig@php.net> |
  17. // | |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: storage.php,v 1.23.2.2 2001/11/13 01:26:43 ssb Exp $
  21. //
  22. // DB_storage: a class that lets you return SQL data as objects that
  23. // can be manipulated and that updates the database accordingly.
  24. //
  25. require_once "PEAR.php";
  26. require_once "DB.php";
  27. /**
  28. * DB_storage provides an object interface to a table row. It lets
  29. * you add, delete and change rows without using SQL.
  30. *
  31. * @author Stig Bakken <stig@php.net>
  32. *
  33. * @package DB
  34. */
  35. class DB_storage extends PEAR
  36. {
  37. /** the name of the table (or view, if the backend database supports
  38. updates in views) we hold data from */
  39. var $_table = null;
  40. /** which column(s) in the table contains primary keys, can be a
  41. string for single-column primary keys, or an array of strings
  42. for multiple-column primary keys */
  43. var $_keycolumn = null;
  44. /** DB connection handle used for all transactions */
  45. var $_dbh = null;
  46. /** an assoc with the names of database fields stored as properties
  47. in this object */
  48. var $_properties = array();
  49. /** an assoc with the names of the properties in this object that
  50. have been changed since they were fetched from the database */
  51. var $_changes = array();
  52. /** flag that decides if data in this object can be changed.
  53. objects that don't have their table's key column in their
  54. property lists will be flagged as read-only. */
  55. var $_readonly = false;
  56. /** function or method that implements a validator for fields that
  57. are set, this validator function returns true if the field is
  58. valid, false if not */
  59. var $_validator = null;
  60. /**
  61. * Constructor
  62. *
  63. * @param $table string the name of the database table
  64. *
  65. * @param $keycolumn mixed string with name of key column, or array of
  66. * strings if the table has a primary key of more than one column
  67. *
  68. * @param $dbh object database connection object
  69. *
  70. * @param $validator mixed function or method used to validate
  71. * each new value, called with three parameters: the name of the
  72. * field/column that is changing, a reference to the new value and
  73. * a reference to this object
  74. *
  75. */
  76. function DB_storage($table, $keycolumn, &$dbh, $validator = null)
  77. {
  78. $this->PEAR('DB_Error');
  79. $this->_table = $table;
  80. $this->_keycolumn = $keycolumn;
  81. $this->_dbh = $dbh;
  82. $this->_readonly = false;
  83. $this->_validator = $validator;
  84. }
  85. /**
  86. * Utility method to build a "WHERE" clause to locate ourselves in
  87. * the table.
  88. *
  89. * XXX future improvement: use rowids?
  90. *
  91. * @access private
  92. */
  93. function _makeWhere($keyval = null)
  94. {
  95. if (is_array($this->_keycolumn)) {
  96. if ($keyval === null) {
  97. for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
  98. $keyval[] = $this->{$this->_keycolumn[$i]};
  99. }
  100. }
  101. $whereclause = '';
  102. for ($i = 0; $i < sizeof($this->_keycolumn); $i++) {
  103. if ($i > 0) {
  104. $whereclause .= ' AND ';
  105. }
  106. $whereclause .= $this->_keycolumn[$i];
  107. if (is_null($keyval[$i])) {
  108. // there's not much point in having a NULL key,
  109. // but we support it anyway
  110. $whereclause .= ' IS NULL';
  111. } else {
  112. $whereclause .= ' = ' . $this->_dbh->quote($keyval[$i]);
  113. }
  114. }
  115. } else {
  116. if ($keyval === null) {
  117. $keyval = @$this->{$this->_keycolumn};
  118. }
  119. $whereclause = $this->_keycolumn;
  120. if (is_null($keyval)) {
  121. // there's not much point in having a NULL key,
  122. // but we support it anyway
  123. $whereclause .= ' IS NULL';
  124. } else {
  125. $whereclause .= ' = ' . $this->_dbh->quote($keyval);
  126. }
  127. }
  128. return $whereclause;
  129. }
  130. /**
  131. * Method used to initialize a DB_storage object from the
  132. * configured table.
  133. *
  134. * @param $keyval mixed the key[s] of the row to fetch (string or array)
  135. *
  136. * @return int DB_OK on success, a DB error if not
  137. */
  138. function setup($keyval)
  139. {
  140. $qval = $this->_dbh->quote($keyval);
  141. $whereclause = $this->_makeWhere($keyval);
  142. $query = 'SELECT * FROM ' . $this->_table . ' WHERE ' . $whereclause;
  143. $sth = $this->_dbh->query($query);
  144. if (DB::isError($sth)) {
  145. return $sth;
  146. }
  147. $row = $sth->fetchRow(DB_FETCHMODE_ASSOC);
  148. if (DB::isError($row)) {
  149. return $row;
  150. }
  151. if (empty($row)) {
  152. return $this->raiseError(null, DB_ERROR_NOT_FOUND, null, null,
  153. $query, null, true);
  154. }
  155. foreach ($row as $key => $value) {
  156. $this->_properties[$key] = true;
  157. $this->$key = $value;
  158. }
  159. return DB_OK;
  160. }
  161. /**
  162. * Create a new (empty) row in the configured table for this
  163. * object.
  164. */
  165. function insert($newpk)
  166. {
  167. if (is_array($this->_keycolumn)) {
  168. $primarykey = $this->_keycolumn;
  169. } else {
  170. $primarykey = array($this->_keycolumn);
  171. }
  172. settype($newpk, "array");
  173. for ($i = 0; $i < sizeof($primarykey); $i++) {
  174. $pkvals[] = $this->_dbh->quote($newpk[$i]);
  175. }
  176. $sth = $this->_dbh->query("INSERT INTO $this->_table (" .
  177. implode(",", $primarykey) . ") VALUES(" .
  178. implode(",", $pkvals) . ")");
  179. if (DB::isError($sth)) {
  180. return $sth;
  181. }
  182. if (sizeof($newpk) == 1) {
  183. $newpk = $newpk[0];
  184. }
  185. $this->setup($newpk);
  186. }
  187. /**
  188. * Output a simple description of this DB_storage object.
  189. * @return string object description
  190. */
  191. function toString()
  192. {
  193. $info = get_class(&$this);
  194. $info .= " (table=";
  195. $info .= $this->_table;
  196. $info .= ", keycolumn=";
  197. if (is_array($this->_keycolumn)) {
  198. $info .= "(" . implode(",", $this->_keycolumn) . ")";
  199. } else {
  200. $info .= $this->_keycolumn;
  201. }
  202. $info .= ", dbh=";
  203. if (is_object($this->_dbh)) {
  204. $info .= $this->_dbh->toString();
  205. } else {
  206. $info .= "null";
  207. }
  208. $info .= ")";
  209. if (sizeof($this->_properties)) {
  210. $info .= " [loaded, key=";
  211. $keyname = $this->_keycolumn;
  212. if (is_array($keyname)) {
  213. $info .= "(";
  214. for ($i = 0; $i < sizeof($keyname); $i++) {
  215. if ($i > 0) {
  216. $info .= ",";
  217. }
  218. $info .= $this->$keyname[$i];
  219. }
  220. $info .= ")";
  221. } else {
  222. $info .= $this->$keyname;
  223. }
  224. $info .= "]";
  225. }
  226. if (sizeof($this->_changes)) {
  227. $info .= " [modified]";
  228. }
  229. return $info;
  230. }
  231. /**
  232. * Dump the contents of this object to "standard output".
  233. */
  234. function dump()
  235. {
  236. reset($this->_properties);
  237. while (list($prop, $foo) = each($this->_properties)) {
  238. print "$prop = ";
  239. print htmlentities($this->$prop);
  240. print "<BR>\n";
  241. }
  242. }
  243. /**
  244. * Static method used to create new DB storage objects.
  245. * @param $data assoc. array where the keys are the names
  246. * of properties/columns
  247. * @return object a new instance of DB_storage or a subclass of it
  248. */
  249. function &create($table, &$data)
  250. {
  251. $classname = get_class(&$this);
  252. $obj = new $classname($table);
  253. reset($data);
  254. while (list($name, $value) = each($data)) {
  255. $obj->_properties[$name] = true;
  256. $obj->$name = &$value;
  257. }
  258. return $obj;
  259. }
  260. /**
  261. * Loads data into this object from the given query. If this
  262. * object already contains table data, changes will be saved and
  263. * the object re-initialized first.
  264. *
  265. * @param $query SQL query
  266. *
  267. * @param $params parameter list in case you want to use
  268. * prepare/execute mode
  269. *
  270. * @return int DB_OK on success, DB_WARNING_READ_ONLY if the
  271. * returned object is read-only (because the object's specified
  272. * key column was not found among the columns returned by $query),
  273. * or another DB error code in case of errors.
  274. */
  275. // XXX commented out for now
  276. /*
  277. function loadFromQuery($query, $params = null)
  278. {
  279. if (sizeof($this->_properties)) {
  280. if (sizeof($this->_changes)) {
  281. $this->store();
  282. $this->_changes = array();
  283. }
  284. $this->_properties = array();
  285. }
  286. $rowdata = $this->_dbh->getRow($query, DB_FETCHMODE_ASSOC, $params);
  287. if (DB::isError($rowdata)) {
  288. return $rowdata;
  289. }
  290. reset($rowdata);
  291. $found_keycolumn = false;
  292. while (list($key, $value) = each($rowdata)) {
  293. if ($key == $this->_keycolumn) {
  294. $found_keycolumn = true;
  295. }
  296. $this->_properties[$key] = true;
  297. $this->$key = &$value;
  298. unset($value); // have to unset, or all properties will
  299. // refer to the same value
  300. }
  301. if (!$found_keycolumn) {
  302. $this->_readonly = true;
  303. return DB_WARNING_READ_ONLY;
  304. }
  305. return DB_OK;
  306. }
  307. */
  308. /**
  309. * Modify an attriute value.
  310. */
  311. function set($property, $newvalue)
  312. {
  313. // only change if $property is known and object is not
  314. // read-only
  315. if ($this->_readonly) {
  316. return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
  317. null, null, null, true);
  318. }
  319. if (@isset($this->_properties[$property])) {
  320. if (empty($this->_validator)) {
  321. $valid = true;
  322. } else {
  323. $valid = @call_user_func($this->_validator,
  324. $this->_table,
  325. $property,
  326. &$newvalue,
  327. &$this->$property,
  328. &$this);
  329. }
  330. if ($valid) {
  331. $this->$property = $newvalue;
  332. @$this->_changes[$property]++;
  333. } else {
  334. return $this->raiseError(null, DB_ERROR_INVALID, null,
  335. null, "invalid field: $property",
  336. null, true);
  337. }
  338. return true;
  339. }
  340. return $this->raiseError(null, DB_ERROR_NOSUCHFIELD, null,
  341. null, "unknown field: $property",
  342. null, true);
  343. }
  344. /**
  345. * Fetch an attribute value.
  346. *
  347. * @param string attribute name
  348. *
  349. * @return attribute contents, or null if the attribute name is
  350. * unknown
  351. */
  352. function &get($property)
  353. {
  354. // only return if $property is known
  355. if (isset($this->_properties[$property])) {
  356. return $this->$property;
  357. }
  358. return null;
  359. }
  360. /**
  361. * Destructor, calls DB_storage::store() if there are changes
  362. * that are to be kept.
  363. */
  364. function _DB_storage()
  365. {
  366. if (empty($this->_discard) && sizeof($this->_changes)) {
  367. $this->store();
  368. }
  369. $this->_properties = array();
  370. $this->_changes = array();
  371. $this->_table = null;
  372. }
  373. /**
  374. * Stores changes to this object in the database.
  375. *
  376. * @return DB_OK or a DB error
  377. */
  378. function store()
  379. {
  380. while (list($name, $changed) = each($this->_changes)) {
  381. $params[] = &$this->$name;
  382. $vars[] = $name . ' = ?';
  383. }
  384. if ($vars) {
  385. $query = 'UPDATE ' . $this->_table . ' SET ' .
  386. implode(', ', $vars) . ' WHERE ' .
  387. $this->_makeWhere();
  388. $stmt = $this->_dbh->prepare($query);
  389. $res = $this->_dbh->execute($stmt, &$params);
  390. if (DB::isError($res)) {
  391. return $res;
  392. }
  393. $this->_changes = array();
  394. }
  395. return DB_OK;
  396. }
  397. /**
  398. * Remove the row represented by this object from the database.
  399. *
  400. * @return mixed DB_OK or a DB error
  401. */
  402. function remove()
  403. {
  404. if ($this->_readonly) {
  405. return $this->raiseError(null, DB_WARNING_READ_ONLY, null,
  406. null, null, null, true);
  407. }
  408. $query = 'DELETE FROM ' . $this->_table .' WHERE '.
  409. $this->_makeWhere();
  410. $res = $this->_dbh->query($query);
  411. if (DB::isError($res)) {
  412. return $res;
  413. }
  414. foreach ($this->_properties as $prop => $foo) {
  415. unset($this->$prop);
  416. }
  417. $this->_properties = array();
  418. $this->_changes = array();
  419. return DB_OK;
  420. }
  421. }
  422. ?>