PageRenderTime 56ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 1ms

/extlib/DB/DataObject.php

https://gitlab.com/windigo-gs/windigos-gnu-social
PHP | 4851 lines | 3030 code | 668 blank | 1153 comment | 582 complexity | 7101a9a262e1f720338ab63f667baf88 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Object Based Database Query Builder and data store
  4. *
  5. * For PHP versions 4,5 and 6
  6. *
  7. * LICENSE: This source file is subject to version 3.01 of the PHP license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.php.net/license/3_01.txt. If you did not receive a copy of
  10. * the PHP License and are unable to obtain it through the web, please
  11. * send a note to license@php.net so we can mail you a copy immediately.
  12. *
  13. * @category Database
  14. * @package DB_DataObject
  15. * @author Alan Knowles <alan@akbkhome.com>
  16. * @copyright 1997-2006 The PHP Group
  17. * @license http://www.php.net/license/3_01.txt PHP License 3.01
  18. * @version CVS: $Id: DataObject.php 329992 2013-04-03 11:38:43Z alan_k $
  19. * @link http://pear.php.net/package/DB_DataObject
  20. */
  21. /* ===========================================================================
  22. *
  23. * !!!!!!!!!!!!! W A R N I N G !!!!!!!!!!!
  24. *
  25. * THIS MAY SEGFAULT PHP IF YOU ARE USING THE ZEND OPTIMIZER (to fix it,
  26. * just add "define('DB_DATAOBJECT_NO_OVERLOAD',true);" before you include
  27. * this file. reducing the optimization level may also solve the segfault.
  28. * ===========================================================================
  29. */
  30. /**
  31. * The main "DB_DataObject" class is really a base class for your own tables classes
  32. *
  33. * // Set up the class by creating an ini file (refer to the manual for more details
  34. * [DB_DataObject]
  35. * database = mysql:/username:password@host/database
  36. * schema_location = /home/myapplication/database
  37. * class_location = /home/myapplication/DBTables/
  38. * clase_prefix = DBTables_
  39. *
  40. *
  41. * //Start and initialize...................... - dont forget the &
  42. * $config = parse_ini_file('example.ini',true);
  43. * $options = &PEAR::getStaticProperty('DB_DataObject','options');
  44. * $options = $config['DB_DataObject'];
  45. *
  46. * // example of a class (that does not use the 'auto generated tables data')
  47. * class mytable extends DB_DataObject {
  48. * // mandatory - set the table
  49. * var $_database_dsn = "mysql://username:password@localhost/database";
  50. * var $__table = "mytable";
  51. * function table() {
  52. * return array(
  53. * 'id' => 1, // integer or number
  54. * 'name' => 2, // string
  55. * );
  56. * }
  57. * function keys() {
  58. * return array('id');
  59. * }
  60. * }
  61. *
  62. * // use in the application
  63. *
  64. *
  65. * Simple get one row
  66. *
  67. * $instance = new mytable;
  68. * $instance->get("id",12);
  69. * echo $instance->somedata;
  70. *
  71. *
  72. * Get multiple rows
  73. *
  74. * $instance = new mytable;
  75. * $instance->whereAdd("ID > 12");
  76. * $instance->whereAdd("ID < 14");
  77. * $instance->find();
  78. * while ($instance->fetch()) {
  79. * echo $instance->somedata;
  80. * }
  81. /**
  82. * Needed classes
  83. * - we use getStaticProperty from PEAR pretty extensively (cant remove it ATM)
  84. */
  85. require_once 'PEAR.php';
  86. /**
  87. * We are duping fetchmode constants to be compatible with
  88. * both DB and MDB2
  89. */
  90. define('DB_DATAOBJECT_FETCHMODE_ORDERED',1);
  91. define('DB_DATAOBJECT_FETCHMODE_ASSOC',2);
  92. /**
  93. * these are constants for the get_table array
  94. * user to determine what type of escaping is required around the object vars.
  95. */
  96. define('DB_DATAOBJECT_INT', 1); // does not require ''
  97. define('DB_DATAOBJECT_STR', 2); // requires ''
  98. define('DB_DATAOBJECT_DATE', 4); // is date #TODO
  99. define('DB_DATAOBJECT_TIME', 8); // is time #TODO
  100. define('DB_DATAOBJECT_BOOL', 16); // is boolean #TODO
  101. define('DB_DATAOBJECT_TXT', 32); // is long text #TODO
  102. define('DB_DATAOBJECT_BLOB', 64); // is blob type
  103. define('DB_DATAOBJECT_NOTNULL', 128); // not null col.
  104. define('DB_DATAOBJECT_MYSQLTIMESTAMP' , 256); // mysql timestamps (ignored by update/insert)
  105. /*
  106. * Define this before you include DataObjects.php to disable overload - if it segfaults due to Zend optimizer..
  107. */
  108. //define('DB_DATAOBJECT_NO_OVERLOAD',true)
  109. /**
  110. * Theses are the standard error codes, most methods will fail silently - and return false
  111. * to access the error message either use $table->_lastError
  112. * or $last_error = PEAR::getStaticProperty('DB_DataObject','lastError');
  113. * the code is $last_error->code, and the message is $last_error->message (a standard PEAR error)
  114. */
  115. define('DB_DATAOBJECT_ERROR_INVALIDARGS', -1); // wrong args to function
  116. define('DB_DATAOBJECT_ERROR_NODATA', -2); // no data available
  117. define('DB_DATAOBJECT_ERROR_INVALIDCONFIG', -3); // something wrong with the config
  118. define('DB_DATAOBJECT_ERROR_NOCLASS', -4); // no class exists
  119. define('DB_DATAOBJECT_ERROR_INVALID_CALL' ,-7); // overlad getter/setter failure
  120. /**
  121. * Used in methods like delete() and count() to specify that the method should
  122. * build the condition only out of the whereAdd's and not the object parameters.
  123. */
  124. define('DB_DATAOBJECT_WHEREADD_ONLY', true);
  125. /**
  126. *
  127. * storage for connection and result objects,
  128. * it is done this way so that print_r()'ing the is smaller, and
  129. * it reduces the memory size of the object.
  130. * -- future versions may use $this->_connection = & PEAR object..
  131. * although will need speed tests to see how this affects it.
  132. * - includes sub arrays
  133. * - connections = md5 sum mapp to pear db object
  134. * - results = [id] => map to pear db object
  135. * - resultseq = sequence id for results & results field
  136. * - resultfields = [id] => list of fields return from query (for use with toArray())
  137. * - ini = mapping of database to ini file results
  138. * - links = mapping of database to links file
  139. * - lasterror = pear error objects for last error event.
  140. * - config = aliased view of PEAR::getStaticPropery('DB_DataObject','options') * done for performance.
  141. * - array of loaded classes by autoload method - to stop it doing file access request over and over again!
  142. */
  143. $GLOBALS['_DB_DATAOBJECT']['RESULTS'] = array();
  144. $GLOBALS['_DB_DATAOBJECT']['RESULTSEQ'] = 1;
  145. $GLOBALS['_DB_DATAOBJECT']['RESULTFIELDS'] = array();
  146. $GLOBALS['_DB_DATAOBJECT']['CONNECTIONS'] = array();
  147. $GLOBALS['_DB_DATAOBJECT']['INI'] = array();
  148. $GLOBALS['_DB_DATAOBJECT']['LINKS'] = array();
  149. $GLOBALS['_DB_DATAOBJECT']['SEQUENCE'] = array();
  150. $GLOBALS['_DB_DATAOBJECT']['LASTERROR'] = null;
  151. $GLOBALS['_DB_DATAOBJECT']['CONFIG'] = array();
  152. $GLOBALS['_DB_DATAOBJECT']['CACHE'] = array();
  153. $GLOBALS['_DB_DATAOBJECT']['OVERLOADED'] = false;
  154. $GLOBALS['_DB_DATAOBJECT']['QUERYENDTIME'] = 0;
  155. // this will be horrifically slow!!!!
  156. // these two are BC/FC handlers for call in PHP4/5
  157. if (!defined('DB_DATAOBJECT_NO_OVERLOAD')) {
  158. class DB_DataObject_Overload
  159. {
  160. function __call($method,$args)
  161. {
  162. $return = null;
  163. $this->_call($method,$args,$return);
  164. return $return;
  165. }
  166. function __sleep()
  167. {
  168. return array_keys(get_object_vars($this)) ;
  169. }
  170. }
  171. } else {
  172. class DB_DataObject_Overload {}
  173. }
  174. /*
  175. *
  176. * @package DB_DataObject
  177. * @author Alan Knowles <alan@akbkhome.com>
  178. * @since PHP 4.0
  179. */
  180. class DB_DataObject extends DB_DataObject_Overload
  181. {
  182. /**
  183. * The Version - use this to check feature changes
  184. *
  185. * @access private
  186. * @var string
  187. */
  188. var $_DB_DataObject_version = "1.11.0";
  189. /**
  190. * The Database table (used by table extends)
  191. *
  192. * @access private
  193. * @var string
  194. */
  195. var $__table = ''; // database table
  196. /**
  197. * The Number of rows returned from a query
  198. *
  199. * @access public
  200. * @var int
  201. */
  202. var $N = 0; // Number of rows returned from a query
  203. /* ============================================================= */
  204. /* Major Public Methods */
  205. /* (designed to be optionally then called with parent::method()) */
  206. /* ============================================================= */
  207. /**
  208. * Get a result using key, value.
  209. *
  210. * for example
  211. * $object->get("ID",1234);
  212. * Returns Number of rows located (usually 1) for success,
  213. * and puts all the table columns into this classes variables
  214. *
  215. * see the fetch example on how to extend this.
  216. *
  217. * if no value is entered, it is assumed that $key is a value
  218. * and get will then use the first key in keys()
  219. * to obtain the key.
  220. *
  221. * @param string $k column
  222. * @param string $v value
  223. * @access public
  224. * @return int No. of rows
  225. */
  226. function get($k = null, $v = null)
  227. {
  228. global $_DB_DATAOBJECT;
  229. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  230. DB_DataObject::_loadConfig();
  231. }
  232. $keys = array();
  233. if ($v === null) {
  234. $v = $k;
  235. $keys = $this->keys();
  236. if (!$keys) {
  237. $this->raiseError("No Keys available for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  238. return false;
  239. }
  240. $k = $keys[0];
  241. }
  242. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  243. $this->debug("$k $v " .print_r($keys,true), "GET");
  244. }
  245. if ($v === null) {
  246. $this->raiseError("No Value specified for get", DB_DATAOBJECT_ERROR_INVALIDARGS);
  247. return false;
  248. }
  249. $this->$k = $v;
  250. return $this->find(1);
  251. }
  252. /**
  253. * Get the value of the primary id
  254. *
  255. * While I normally use 'id' as the PRIMARY KEY value, some database use
  256. * {table}_id as the column name.
  257. *
  258. * To save a bit of typing,
  259. *
  260. * $id = $do->pid();
  261. *
  262. * @return the id
  263. */
  264. function pid()
  265. {
  266. $keys = $this->keys();
  267. if (!$keys) {
  268. $this->raiseError("No Keys available for {$this->tableName()}",
  269. DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  270. return false;
  271. }
  272. $k = $keys[0];
  273. if (empty($this->$k)) { // we do not
  274. $this->raiseError("pid() called on Object where primary key value not available",
  275. DB_DATAOBJECT_ERROR_NODATA);
  276. return false;
  277. }
  278. return $this->$k;
  279. }
  280. /**
  281. * build the basic select query.
  282. *
  283. * @access private
  284. */
  285. function _build_select()
  286. {
  287. global $_DB_DATAOBJECT;
  288. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  289. if ($quoteIdentifiers) {
  290. $this->_connect();
  291. $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  292. }
  293. $tn = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName()) ;
  294. if (!empty($this->_query['derive_table']) && !empty($this->_query['derive_select']) ) {
  295. // this is a derived select..
  296. // not much support in the api yet..
  297. $sql = 'SELECT ' .
  298. $this->_query['derive_select']
  299. .' FROM ( SELECT'.
  300. $this->_query['data_select'] . " \n" .
  301. " FROM $tn \n" .
  302. $this->_join . " \n" .
  303. $this->_query['condition'] . " \n" .
  304. $this->_query['group_by'] . " \n" .
  305. $this->_query['having'] . " \n" .
  306. ') ' . $this->_query['derive_table'];
  307. return $sql;
  308. }
  309. $sql = 'SELECT ' .
  310. $this->_query['data_select'] . " \n" .
  311. " FROM $tn \n" .
  312. $this->_join . " \n" .
  313. $this->_query['condition'] . " \n" .
  314. $this->_query['group_by'] . " \n" .
  315. $this->_query['having'] . " \n";
  316. return $sql;
  317. }
  318. /**
  319. * find results, either normal or crosstable
  320. *
  321. * for example
  322. *
  323. * $object = new mytable();
  324. * $object->ID = 1;
  325. * $object->find();
  326. *
  327. *
  328. * will set $object->N to number of rows, and expects next command to fetch rows
  329. * will return $object->N
  330. *
  331. * if an error occurs $object->N will be set to false and return value will also be false;
  332. * if numRows is not supported it will
  333. *
  334. *
  335. * @param boolean $n Fetch first result
  336. * @access public
  337. * @return mixed (number of rows returned, or true if numRows fetching is not supported)
  338. */
  339. function find($n = false)
  340. {
  341. global $_DB_DATAOBJECT;
  342. if ($this->_query === false) {
  343. $this->raiseError(
  344. "You cannot do two queries on the same object (copy it before finding)",
  345. DB_DATAOBJECT_ERROR_INVALIDARGS);
  346. return false;
  347. }
  348. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  349. DB_DataObject::_loadConfig();
  350. }
  351. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  352. $this->debug($n, "find",1);
  353. }
  354. if (!$this->__table) {
  355. // xdebug can backtrace this!
  356. trigger_error("NO \$__table SPECIFIED in class definition",E_USER_ERROR);
  357. }
  358. $this->N = 0;
  359. $query_before = $this->_query;
  360. $this->_build_condition($this->table()) ;
  361. $this->_connect();
  362. $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  363. $sql = $this->_build_select();
  364. foreach ($this->_query['unions'] as $union_ar) {
  365. $sql .= $union_ar[1] . $union_ar[0]->_build_select() . " \n";
  366. }
  367. $sql .= $this->_query['order_by'] . " \n";
  368. /* We are checking for method modifyLimitQuery as it is PEAR DB specific */
  369. if ((!isset($_DB_DATAOBJECT['CONFIG']['db_driver'])) ||
  370. ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
  371. /* PEAR DB specific */
  372. if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
  373. $sql = $DB->modifyLimitQuery($sql,$this->_query['limit_start'], $this->_query['limit_count']);
  374. }
  375. } else {
  376. /* theoretically MDB2! */
  377. if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
  378. $DB->setLimit($this->_query['limit_count'],$this->_query['limit_start']);
  379. }
  380. }
  381. $err = $this->_query($sql);
  382. if (is_a($err,'PEAR_Error')) {
  383. return false;
  384. }
  385. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  386. $this->debug("CHECK autofetchd $n", "find", 1);
  387. }
  388. // find(true)
  389. $ret = $this->N;
  390. if (!$ret && !empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
  391. // clear up memory if nothing found!?
  392. unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
  393. }
  394. if ($n && $this->N > 0 ) {
  395. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  396. $this->debug("ABOUT TO AUTOFETCH", "find", 1);
  397. }
  398. $fs = $this->fetch();
  399. // if fetch returns false (eg. failed), then the backend doesnt support numRows (eg. ret=true)
  400. // - hence find() also returns false..
  401. $ret = ($ret === true) ? $fs : $ret;
  402. }
  403. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  404. $this->debug("DONE", "find", 1);
  405. }
  406. $this->_query = $query_before;
  407. return $ret;
  408. }
  409. /**
  410. * fetches next row into this objects var's
  411. *
  412. * returns 1 on success 0 on failure
  413. *
  414. *
  415. *
  416. * Example
  417. * $object = new mytable();
  418. * $object->name = "fred";
  419. * $object->find();
  420. * $store = array();
  421. * while ($object->fetch()) {
  422. * echo $this->ID;
  423. * $store[] = $object; // builds an array of object lines.
  424. * }
  425. *
  426. * to add features to a fetch
  427. * function fetch () {
  428. * $ret = parent::fetch();
  429. * $this->date_formated = date('dmY',$this->date);
  430. * return $ret;
  431. * }
  432. *
  433. * @access public
  434. * @return boolean on success
  435. */
  436. function fetch()
  437. {
  438. global $_DB_DATAOBJECT;
  439. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  440. DB_DataObject::_loadConfig();
  441. }
  442. if (empty($this->N)) {
  443. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  444. $this->debug("No data returned from FIND (eg. N is 0)","FETCH", 3);
  445. }
  446. return false;
  447. }
  448. if (empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]) ||
  449. !is_object($result = $_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]))
  450. {
  451. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  452. $this->debug('fetched on object after fetch completed (no results found)');
  453. }
  454. return false;
  455. }
  456. $array = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ASSOC);
  457. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  458. $this->debug(serialize($array),"FETCH");
  459. }
  460. // fetched after last row..
  461. if ($array === null) {
  462. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  463. $t= explode(' ',microtime());
  464. $this->debug("Last Data Fetch'ed after " .
  465. ($t[0]+$t[1]- $_DB_DATAOBJECT['QUERYENDTIME'] ) .
  466. " seconds",
  467. "FETCH", 1);
  468. }
  469. // reduce the memory usage a bit... (but leave the id in, so count() works ok on it)
  470. unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
  471. // we need to keep a copy of resultfields locally so toArray() still works
  472. // however we dont want to keep it in the global cache..
  473. if (!empty($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
  474. $this->_resultFields = $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid];
  475. unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]);
  476. }
  477. // this is probably end of data!!
  478. //DB_DataObject::raiseError("fetch: no data returned", DB_DATAOBJECT_ERROR_NODATA);
  479. return false;
  480. }
  481. // make sure resultFields is always empty..
  482. $this->_resultFields = false;
  483. if (!isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
  484. // note: we dont declare this to keep the print_r size down.
  485. $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]= array_flip(array_keys($array));
  486. }
  487. $replace = array('.', ' ');
  488. foreach($array as $k=>$v) {
  489. // use strpos as str_replace is slow.
  490. $kk = (strpos($k, '.') === false && strpos($k, ' ') === false) ?
  491. $k : str_replace($replace, '_', $k);
  492. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  493. $this->debug("$kk = ". $array[$k], "fetchrow LINE", 3);
  494. }
  495. $this->$kk = $array[$k];
  496. }
  497. // set link flag
  498. $this->_link_loaded=false;
  499. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  500. $this->debug("{$this->tableName()} DONE", "fetchrow",2);
  501. }
  502. if (($this->_query !== false) && empty($_DB_DATAOBJECT['CONFIG']['keep_query_after_fetch'])) {
  503. $this->_query = false;
  504. }
  505. return true;
  506. }
  507. /**
  508. * fetches all results as an array,
  509. *
  510. * return format is dependant on args.
  511. * if selectAdd() has not been called on the object, then it will add the correct columns to the query.
  512. *
  513. * A) Array of values (eg. a list of 'id')
  514. *
  515. * $x = DB_DataObject::factory('mytable');
  516. * $x->whereAdd('something = 1')
  517. * $ar = $x->fetchAll('id');
  518. * -- returns array(1,2,3,4,5)
  519. *
  520. * B) Array of values (not from table)
  521. *
  522. * $x = DB_DataObject::factory('mytable');
  523. * $x->whereAdd('something = 1');
  524. * $x->selectAdd();
  525. * $x->selectAdd('distinct(group_id) as group_id');
  526. * $ar = $x->fetchAll('group_id');
  527. * -- returns array(1,2,3,4,5)
  528. * *
  529. * C) A key=>value associative array
  530. *
  531. * $x = DB_DataObject::factory('mytable');
  532. * $x->whereAdd('something = 1')
  533. * $ar = $x->fetchAll('id','name');
  534. * -- returns array(1=>'fred',2=>'blogs',3=> .......
  535. *
  536. * D) array of objects
  537. * $x = DB_DataObject::factory('mytable');
  538. * $x->whereAdd('something = 1');
  539. * $ar = $x->fetchAll();
  540. *
  541. * E) array of arrays (for example)
  542. * $x = DB_DataObject::factory('mytable');
  543. * $x->whereAdd('something = 1');
  544. * $ar = $x->fetchAll(false,false,'toArray');
  545. *
  546. *
  547. * @param string|false $k key
  548. * @param string|false $v value
  549. * @param string|false $method method to call on each result to get array value (eg. 'toArray')
  550. * @access public
  551. * @return array format dependant on arguments, may be empty
  552. */
  553. function fetchAll($k= false, $v = false, $method = false)
  554. {
  555. // should it even do this!!!?!?
  556. if ($k !== false &&
  557. ( // only do this is we have not been explicit..
  558. empty($this->_query['data_select']) ||
  559. ($this->_query['data_select'] == '*')
  560. )
  561. ) {
  562. $this->selectAdd();
  563. $this->selectAdd($k);
  564. if ($v !== false) {
  565. $this->selectAdd($v);
  566. }
  567. }
  568. $this->find();
  569. $ret = array();
  570. while ($this->fetch()) {
  571. if ($v !== false) {
  572. $ret[$this->$k] = $this->$v;
  573. continue;
  574. }
  575. $ret[] = $k === false ?
  576. ($method == false ? clone($this) : $this->$method())
  577. : $this->$k;
  578. }
  579. return $ret;
  580. }
  581. /**
  582. * Adds a condition to the WHERE statement, defaults to AND
  583. *
  584. * $object->whereAdd(); //reset or cleaer ewhwer
  585. * $object->whereAdd("ID > 20");
  586. * $object->whereAdd("age > 20","OR");
  587. *
  588. * @param string $cond condition
  589. * @param string $logic optional logic "OR" (defaults to "AND")
  590. * @access public
  591. * @return string|PEAR::Error - previous condition or Error when invalid args found
  592. */
  593. function whereAdd($cond = false, $logic = 'AND')
  594. {
  595. // for PHP5.2.3 - there is a bug with setting array properties of an object.
  596. $_query = $this->_query;
  597. if (!isset($this->_query) || ($_query === false)) {
  598. return $this->raiseError(
  599. "You cannot do two queries on the same object (clone it before finding)",
  600. DB_DATAOBJECT_ERROR_INVALIDARGS);
  601. }
  602. if ($cond === false) {
  603. $r = $this->_query['condition'];
  604. $_query['condition'] = '';
  605. $this->_query = $_query;
  606. return preg_replace('/^\s+WHERE\s+/','',$r);
  607. }
  608. // check input...= 0 or ' ' == error!
  609. if (!trim($cond)) {
  610. return $this->raiseError("WhereAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  611. }
  612. $r = $_query['condition'];
  613. if ($_query['condition']) {
  614. $_query['condition'] .= " {$logic} ( {$cond} )";
  615. $this->_query = $_query;
  616. return $r;
  617. }
  618. $_query['condition'] = " WHERE ( {$cond} ) ";
  619. $this->_query = $_query;
  620. return $r;
  621. }
  622. /**
  623. * Adds a 'IN' condition to the WHERE statement
  624. *
  625. * $object->whereAddIn('id', $array, 'int'); //minimal usage
  626. * $object->whereAddIn('price', $array, 'float', 'OR'); // cast to float, and call whereAdd with 'OR'
  627. * $object->whereAddIn('name', $array, 'string'); // quote strings
  628. *
  629. * @param string $key key column to match
  630. * @param array $list list of values to match
  631. * @param string $type string|int|integer|float|bool cast to type.
  632. * @param string $logic optional logic to call whereAdd with eg. "OR" (defaults to "AND")
  633. * @access public
  634. * @return string|PEAR::Error - previous condition or Error when invalid args found
  635. */
  636. function whereAddIn($key, $list, $type, $logic = 'AND')
  637. {
  638. $not = '';
  639. if ($key[0] == '!') {
  640. $not = 'NOT ';
  641. $key = substr($key, 1);
  642. }
  643. // fix type for short entry.
  644. $type = $type == 'int' ? 'integer' : $type;
  645. if ($type == 'string') {
  646. $this->_connect();
  647. }
  648. $ar = array();
  649. foreach($list as $k) {
  650. settype($k, $type);
  651. $ar[] = $type == 'string' ? $this->_quote($k) : $k;
  652. }
  653. if (!$ar) {
  654. return $not ? $this->_query['condition'] : $this->whereAdd("1=0");
  655. }
  656. return $this->whereAdd("$key $not IN (". implode(',', $ar). ')', $logic );
  657. }
  658. /**
  659. * Adds a order by condition
  660. *
  661. * $object->orderBy(); //clears order by
  662. * $object->orderBy("ID");
  663. * $object->orderBy("ID,age");
  664. *
  665. * @param string $order Order
  666. * @access public
  667. * @return none|PEAR::Error - invalid args only
  668. */
  669. function orderBy($order = false)
  670. {
  671. if ($this->_query === false) {
  672. $this->raiseError(
  673. "You cannot do two queries on the same object (copy it before finding)",
  674. DB_DATAOBJECT_ERROR_INVALIDARGS);
  675. return false;
  676. }
  677. if ($order === false) {
  678. $this->_query['order_by'] = '';
  679. return;
  680. }
  681. // check input...= 0 or ' ' == error!
  682. if (!trim($order)) {
  683. return $this->raiseError("orderBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  684. }
  685. if (!$this->_query['order_by']) {
  686. $this->_query['order_by'] = " ORDER BY {$order} ";
  687. return;
  688. }
  689. $this->_query['order_by'] .= " , {$order}";
  690. }
  691. /**
  692. * Adds a group by condition
  693. *
  694. * $object->groupBy(); //reset the grouping
  695. * $object->groupBy("ID DESC");
  696. * $object->groupBy("ID,age");
  697. *
  698. * @param string $group Grouping
  699. * @access public
  700. * @return none|PEAR::Error - invalid args only
  701. */
  702. function groupBy($group = false)
  703. {
  704. if ($this->_query === false) {
  705. $this->raiseError(
  706. "You cannot do two queries on the same object (copy it before finding)",
  707. DB_DATAOBJECT_ERROR_INVALIDARGS);
  708. return false;
  709. }
  710. if ($group === false) {
  711. $this->_query['group_by'] = '';
  712. return;
  713. }
  714. // check input...= 0 or ' ' == error!
  715. if (!trim($group)) {
  716. return $this->raiseError("groupBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  717. }
  718. if (!$this->_query['group_by']) {
  719. $this->_query['group_by'] = " GROUP BY {$group} ";
  720. return;
  721. }
  722. $this->_query['group_by'] .= " , {$group}";
  723. }
  724. /**
  725. * Adds a having clause
  726. *
  727. * $object->having(); //reset the grouping
  728. * $object->having("sum(value) > 0 ");
  729. *
  730. * @param string $having condition
  731. * @access public
  732. * @return none|PEAR::Error - invalid args only
  733. */
  734. function having($having = false)
  735. {
  736. if ($this->_query === false) {
  737. $this->raiseError(
  738. "You cannot do two queries on the same object (copy it before finding)",
  739. DB_DATAOBJECT_ERROR_INVALIDARGS);
  740. return false;
  741. }
  742. if ($having === false) {
  743. $this->_query['having'] = '';
  744. return;
  745. }
  746. // check input...= 0 or ' ' == error!
  747. if (!trim($having)) {
  748. return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  749. }
  750. if (!$this->_query['having']) {
  751. $this->_query['having'] = " HAVING {$having} ";
  752. return;
  753. }
  754. $this->_query['having'] .= " AND {$having}";
  755. }
  756. /**
  757. * Sets the Limit
  758. *
  759. * $boject->limit(); // clear limit
  760. * $object->limit(12);
  761. * $object->limit(12,10);
  762. *
  763. * Note this will emit an error on databases other than mysql/postgress
  764. * as there is no 'clean way' to implement it. - you should consider refering to
  765. * your database manual to decide how you want to implement it.
  766. *
  767. * @param string $a limit start (or number), or blank to reset
  768. * @param string $b number
  769. * @access public
  770. * @return none|PEAR::Error - invalid args only
  771. */
  772. function limit($a = null, $b = null)
  773. {
  774. if ($this->_query === false) {
  775. $this->raiseError(
  776. "You cannot do two queries on the same object (copy it before finding)",
  777. DB_DATAOBJECT_ERROR_INVALIDARGS);
  778. return false;
  779. }
  780. if ($a === null) {
  781. $this->_query['limit_start'] = '';
  782. $this->_query['limit_count'] = '';
  783. return;
  784. }
  785. // check input...= 0 or ' ' == error!
  786. if ((!is_int($a) && ((string)((int)$a) !== (string)$a))
  787. || (($b !== null) && (!is_int($b) && ((string)((int)$b) !== (string)$b)))) {
  788. return $this->raiseError("limit: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  789. }
  790. global $_DB_DATAOBJECT;
  791. $this->_connect();
  792. $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  793. $this->_query['limit_start'] = ($b == null) ? 0 : (int)$a;
  794. $this->_query['limit_count'] = ($b == null) ? (int)$a : (int)$b;
  795. }
  796. /**
  797. * Adds a select columns
  798. *
  799. * $object->selectAdd(); // resets select to nothing!
  800. * $object->selectAdd("*"); // default select
  801. * $object->selectAdd("unixtime(DATE) as udate");
  802. * $object->selectAdd("DATE");
  803. *
  804. * to prepend distict:
  805. * $object->selectAdd('distinct ' . $object->selectAdd());
  806. *
  807. * @param string $k
  808. * @access public
  809. * @return mixed null or old string if you reset it.
  810. */
  811. function selectAdd($k = null)
  812. {
  813. if ($this->_query === false) {
  814. $this->raiseError(
  815. "You cannot do two queries on the same object (copy it before finding)",
  816. DB_DATAOBJECT_ERROR_INVALIDARGS);
  817. return false;
  818. }
  819. if ($k === null) {
  820. $old = $this->_query['data_select'];
  821. $this->_query['data_select'] = '';
  822. return $old;
  823. }
  824. // check input...= 0 or ' ' == error!
  825. if (!trim($k)) {
  826. return $this->raiseError("selectAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  827. }
  828. if ($this->_query['data_select']) {
  829. $this->_query['data_select'] .= ', ';
  830. }
  831. $this->_query['data_select'] .= " $k ";
  832. }
  833. /**
  834. * Adds multiple Columns or objects to select with formating.
  835. *
  836. * $object->selectAs(null); // adds "table.colnameA as colnameA,table.colnameB as colnameB,......"
  837. * // note with null it will also clear the '*' default select
  838. * $object->selectAs(array('a','b'),'%s_x'); // adds "a as a_x, b as b_x"
  839. * $object->selectAs(array('a','b'),'ddd_%s','ccc'); // adds "ccc.a as ddd_a, ccc.b as ddd_b"
  840. * $object->selectAdd($object,'prefix_%s'); // calls $object->get_table and adds it all as
  841. * objectTableName.colnameA as prefix_colnameA
  842. *
  843. * @param array|object|null the array or object to take column names from.
  844. * @param string format in sprintf format (use %s for the colname)
  845. * @param string table name eg. if you have joinAdd'd or send $from as an array.
  846. * @access public
  847. * @return void
  848. */
  849. function selectAs($from = null,$format = '%s',$tableName=false)
  850. {
  851. global $_DB_DATAOBJECT;
  852. if ($this->_query === false) {
  853. $this->raiseError(
  854. "You cannot do two queries on the same object (copy it before finding)",
  855. DB_DATAOBJECT_ERROR_INVALIDARGS);
  856. return false;
  857. }
  858. if ($from === null) {
  859. // blank the '*'
  860. $this->selectAdd();
  861. $from = $this;
  862. }
  863. $table = $this->tableName();
  864. if (is_object($from)) {
  865. $table = $from->tableName();
  866. $from = array_keys($from->table());
  867. }
  868. if ($tableName !== false) {
  869. $table = $tableName;
  870. }
  871. $s = '%s';
  872. if (!empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers'])) {
  873. $this->_connect();
  874. $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  875. $s = $DB->quoteIdentifier($s);
  876. $format = $DB->quoteIdentifier($format);
  877. }
  878. foreach ($from as $k) {
  879. $this->selectAdd(sprintf("{$s}.{$s} as {$format}",$table,$k,$k));
  880. }
  881. $this->_query['data_select'] .= "\n";
  882. }
  883. /**
  884. * Insert the current objects variables into the database
  885. *
  886. * Returns the ID of the inserted element (if auto increment or sequences are used.)
  887. *
  888. * for example
  889. *
  890. * Designed to be extended
  891. *
  892. * $object = new mytable();
  893. * $object->name = "fred";
  894. * echo $object->insert();
  895. *
  896. * @access public
  897. * @return mixed false on failure, int when auto increment or sequence used, otherwise true on success
  898. */
  899. function insert()
  900. {
  901. global $_DB_DATAOBJECT;
  902. // we need to write to the connection (For nextid) - so us the real
  903. // one not, a copyied on (as ret-by-ref fails with overload!)
  904. if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
  905. $this->_connect();
  906. }
  907. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  908. $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  909. $items = $this->table();
  910. if (!$items) {
  911. $this->raiseError("insert:No table definition for {$this->tableName()}",
  912. DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  913. return false;
  914. }
  915. $options = $_DB_DATAOBJECT['CONFIG'];
  916. $datasaved = 1;
  917. $leftq = '';
  918. $rightq = '';
  919. $seqKeys = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()]) ?
  920. $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->tableName()] :
  921. $this->sequenceKey();
  922. $key = isset($seqKeys[0]) ? $seqKeys[0] : false;
  923. $useNative = isset($seqKeys[1]) ? $seqKeys[1] : false;
  924. $seq = isset($seqKeys[2]) ? $seqKeys[2] : false;
  925. $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["phptype"];
  926. // nativeSequences or Sequences..
  927. // big check for using sequences
  928. if (($key !== false) && !$useNative) {
  929. if (!$seq) {
  930. $keyvalue = $DB->nextId($this->tableName());
  931. } else {
  932. $f = $DB->getOption('seqname_format');
  933. $DB->setOption('seqname_format','%s');
  934. $keyvalue = $DB->nextId($seq);
  935. $DB->setOption('seqname_format',$f);
  936. }
  937. if (PEAR::isError($keyvalue)) {
  938. $this->raiseError($keyvalue->toString(), DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  939. return false;
  940. }
  941. $this->$key = $keyvalue;
  942. }
  943. // if we haven't set disable_null_strings to "full"
  944. $ignore_null = !isset($options['disable_null_strings'])
  945. || !is_string($options['disable_null_strings'])
  946. || strtolower($options['disable_null_strings']) !== 'full' ;
  947. foreach($items as $k => $v) {
  948. // if we are using autoincrement - skip the column...
  949. if ($key && ($k == $key) && $useNative) {
  950. continue;
  951. }
  952. // Ignore variables which aren't set to a value
  953. if ( !isset($this->$k) && $ignore_null) {
  954. continue;
  955. }
  956. // dont insert data into mysql timestamps
  957. // use query() if you really want to do this!!!!
  958. if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
  959. continue;
  960. }
  961. if ($leftq) {
  962. $leftq .= ', ';
  963. $rightq .= ', ';
  964. }
  965. $leftq .= ($quoteIdentifiers ? ($DB->quoteIdentifier($k) . ' ') : "$k ");
  966. if (is_object($this->$k) && is_a($this->$k,'DB_DataObject_Cast')) {
  967. $value = $this->$k->toString($v,$DB);
  968. if (PEAR::isError($value)) {
  969. $this->raiseError($value->toString() ,DB_DATAOBJECT_ERROR_INVALIDARGS);
  970. return false;
  971. }
  972. $rightq .= $value;
  973. continue;
  974. }
  975. if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this,$k)) {
  976. $rightq .= " NULL ";
  977. continue;
  978. }
  979. // DATE is empty... on a col. that can be null..
  980. // note: this may be usefull for time as well..
  981. if (!$this->$k &&
  982. (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
  983. !($v & DB_DATAOBJECT_NOTNULL)) {
  984. $rightq .= " NULL ";
  985. continue;
  986. }
  987. if ($v & DB_DATAOBJECT_STR) {
  988. $rightq .= $this->_quote((string) (
  989. ($v & DB_DATAOBJECT_BOOL) ?
  990. // this is thanks to the braindead idea of postgres to
  991. // use t/f for boolean.
  992. (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
  993. $this->$k
  994. )) . " ";
  995. continue;
  996. }
  997. if (is_numeric($this->$k)) {
  998. $rightq .=" {$this->$k} ";
  999. continue;
  1000. }
  1001. /* flag up string values - only at debug level... !!!??? */
  1002. if (is_object($this->$k) || is_array($this->$k)) {
  1003. $this->debug('ODD DATA: ' .$k . ' ' . print_r($this->$k,true),'ERROR');
  1004. }
  1005. // at present we only cast to integers
  1006. // - V2 may store additional data about float/int
  1007. $rightq .= ' ' . intval($this->$k) . ' ';
  1008. }
  1009. // not sure why we let empty insert here.. - I guess to generate a blank row..
  1010. if ($leftq || $useNative) {
  1011. $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
  1012. if (($dbtype == 'pgsql') && empty($leftq)) {
  1013. $r = $this->_query("INSERT INTO {$table} DEFAULT VALUES");
  1014. } else {
  1015. $r = $this->_query("INSERT INTO {$table} ($leftq) VALUES ($rightq) ");
  1016. }
  1017. if (PEAR::isError($r)) {
  1018. $this->raiseError($r);
  1019. return false;
  1020. }
  1021. if ($r < 1) {
  1022. return 0;
  1023. }
  1024. // now do we have an integer key!
  1025. if ($key && $useNative) {
  1026. switch ($dbtype) {
  1027. case 'mysql':
  1028. case 'mysqli':
  1029. $method = "{$dbtype}_insert_id";
  1030. $this->$key = $method(
  1031. $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection
  1032. );
  1033. break;
  1034. case 'mssql':
  1035. // note this is not really thread safe - you should wrapp it with
  1036. // transactions = eg.
  1037. // $db->query('BEGIN');
  1038. // $db->insert();
  1039. // $db->query('COMMIT');
  1040. $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
  1041. $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
  1042. $mssql_key = $DB->$method("SELECT @@IDENTITY");
  1043. if (PEAR::isError($mssql_key)) {
  1044. $this->raiseError($mssql_key);
  1045. return false;
  1046. }
  1047. $this->$key = $mssql_key;
  1048. break;
  1049. case 'pgsql':
  1050. if (!$seq) {
  1051. $seq = $DB->getSequenceName(strtolower($this->tableName()));
  1052. }
  1053. $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
  1054. $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
  1055. $pgsql_key = $DB->$method("SELECT currval('".$seq . "')");
  1056. if (PEAR::isError($pgsql_key)) {
  1057. $this->raiseError($pgsql_key);
  1058. return false;
  1059. }
  1060. $this->$key = $pgsql_key;
  1061. break;
  1062. case 'ifx':
  1063. $this->$key = array_shift (
  1064. ifx_fetch_row (
  1065. ifx_query(
  1066. "select DBINFO('sqlca.sqlerrd1') FROM systables where tabid=1",
  1067. $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection,
  1068. IFX_SCROLL
  1069. ),
  1070. "FIRST"
  1071. )
  1072. );
  1073. break;
  1074. }
  1075. }
  1076. if (isset($_DB_DATAOBJECT['CACHE'][strtolower(get_class($this))])) {
  1077. $this->_clear_cache();
  1078. }
  1079. if ($key) {
  1080. return $this->$key;
  1081. }
  1082. return true;
  1083. }
  1084. $this->raiseError("insert: No Data specifed for query", DB_DATAOBJECT_ERROR_NODATA);
  1085. return false;
  1086. }
  1087. /**
  1088. * Updates current objects variables into the database
  1089. * uses the keys() to decide how to update
  1090. * Returns the true on success
  1091. *
  1092. * for example
  1093. *
  1094. * $object = DB_DataObject::factory('mytable');
  1095. * $object->get("ID",234);
  1096. * $object->email="testing@test.com";
  1097. * if(!$object->update())
  1098. * echo "UPDATE FAILED";
  1099. *
  1100. * to only update changed items :
  1101. * $dataobject->get(132);
  1102. * $original = $dataobject; // clone/copy it..
  1103. * $dataobject->setFrom($_POST);
  1104. * if ($dataobject->validate()) {
  1105. * $dataobject->update($original);
  1106. * } // otherwise an error...
  1107. *
  1108. * performing global updates:
  1109. * $object = DB_DataObject::factory('mytable');
  1110. * $object->status = "dead";
  1111. * $object->whereAdd('age > 150');
  1112. * $object->update(DB_DATAOBJECT_WHEREADD_ONLY);
  1113. *
  1114. * @param object dataobject (optional) | DB_DATAOBJECT_WHEREADD_ONLY - used to only update changed items.
  1115. * @access public
  1116. * @return int rows affected or false on failure
  1117. */
  1118. function update($dataObject = false)
  1119. {
  1120. global $_DB_DATAOBJECT;
  1121. // connect will load the config!
  1122. $this->_connect();
  1123. $original_query = $this->_query;
  1124. $items = $this->table();
  1125. // only apply update against sequence key if it is set?????
  1126. $seq = $this->sequenceKey();
  1127. if ($seq[0] !== false) {
  1128. $keys = array($seq[0]);
  1129. if (!isset($this->{$keys[0]}) && $dataObject !== true) {
  1130. $this->raiseError("update: trying to perform an update without
  1131. the key set, and argument to update is not
  1132. DB_DATAOBJECT_WHEREADD_ONLY
  1133. ", DB_DATAOBJECT_ERROR_INVALIDARGS);
  1134. return false;
  1135. }
  1136. } else {
  1137. $keys = $this->keys();
  1138. }
  1139. if (!$items) {
  1140. $this->raiseError("update:No table definition for {$this->tableName()}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  1141. return false;
  1142. }
  1143. $datasaved = 1;
  1144. $settings = '';
  1145. $this->_connect();
  1146. $DB = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  1147. $dbtype = $DB->dsn["phptype"];
  1148. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  1149. $options = $_DB_DATAOBJECT['CONFIG'];
  1150. $ignore_null = !isset($options['disable_null_strings'])
  1151. || !is_string($options['disable_null_strings'])
  1152. || strtolower($options['disable_null_strings']) !== 'full' ;
  1153. foreach($items as $k => $v) {
  1154. if (!isset($this->$k) && $ignore_null) {
  1155. continue;
  1156. }
  1157. // ignore stuff thats
  1158. // dont write things that havent changed..
  1159. if (($dataObject !== false) && isset($dataObject->$k) && ($dataObject->$k === $this->$k)) {
  1160. continue;
  1161. }
  1162. // - dont write keys to left.!!!
  1163. if (in_array($k,$keys)) {
  1164. continue;
  1165. }
  1166. // dont insert data into mysql timestamps
  1167. // use query() if you really want to do this!!!!
  1168. if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
  1169. continue;
  1170. }
  1171. if ($settings) {
  1172. $settings .= ', ';
  1173. }
  1174. $kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k);
  1175. if (is_object($this->$k) && is_a($this->$k,'DB_DataObject_Cast')) {
  1176. $value = $this->$k->toString($v,$DB);
  1177. if (PEAR::isError($value)) {
  1178. $this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG);
  1179. return false;
  1180. }
  1181. $settings .= "$kSql = $value ";
  1182. continue;
  1183. }
  1184. // special values ... at least null is handled...
  1185. if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this,$k)) {
  1186. $settings .= "$kSql = NULL ";
  1187. continue;
  1188. }
  1189. // DATE is empty... on a col. that can be null..
  1190. // note: this may be usefull for time as well..
  1191. if (!$this->$k &&
  1192. (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
  1193. !($v & DB_DATAOBJECT_NOTNULL)) {
  1194. $settings .= "$kSql = NULL ";
  1195. continue;
  1196. }
  1197. if ($v & DB_DATAOBJECT_STR) {
  1198. $settings .= "$kSql = ". $this->_quote((string) (
  1199. ($v & DB_DATAOBJECT_BOOL) ?
  1200. // this is thanks to the braindead idea of postgres to
  1201. // use t/f for boolean.
  1202. (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
  1203. $this->$k
  1204. )) . ' ';
  1205. continue;
  1206. }
  1207. if (is_numeric($this->$k)) {
  1208. $settings .= "$kSql = {$this->$k} ";
  1209. continue;
  1210. }
  1211. // at present we only cast to integers
  1212. // - V2 may store additional data about float/int
  1213. $settings .= "$kSql = " . intval($this->$k) . ' ';
  1214. }
  1215. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  1216. $this->debug("got keys as ".serialize($keys),3);
  1217. }
  1218. if ($dataObject !== true) {
  1219. $this->_build_condition($items,$keys);
  1220. } else {
  1221. // prevent wiping out of data!
  1222. if (empty($this->_query['condition'])) {
  1223. $this->raiseError("update: global table update not available
  1224. do \$do->whereAdd('1=1'); if you really want to do that.
  1225. ", DB_DATAOBJECT_ERROR_INVALIDARGS);
  1226. return false;
  1227. }
  1228. }
  1229. // echo " $settings, $this->condition ";
  1230. if ($settings && isset($this->_query) && $this->_query['condition']) {
  1231. $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->tableName()) : $this->tableName());
  1232. $r = $this->_query("UPDATE {$table} SET {$settings} {$this->_query['condition']} ");
  1233. // restore original query conditions.
  1234. $this->_query = $original_query;
  1235. if (PEAR::isError($r)) {
  1236. $this-

Large files files are truncated, but you can click here to view the full file