PageRenderTime 75ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 1ms

/extlib/DB/DataObject.php

https://github.com/zh/statusnet
PHP | 4354 lines | 2767 code | 579 blank | 1008 comment | 556 complexity | f44d3ca7b9672113004464317f671bd7 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-3.0, 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 291349 2009-11-27 09:15:18Z 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. // NOTE: Overload SEGFAULTS ON PHP4 + Zend Optimizer (see define before..)
  157. // these two are BC/FC handlers for call in PHP4/5
  158. if ( substr(phpversion(),0,1) == 5) {
  159. class DB_DataObject_Overload
  160. {
  161. function __call($method,$args)
  162. {
  163. $return = null;
  164. $this->_call($method,$args,$return);
  165. return $return;
  166. }
  167. function __sleep()
  168. {
  169. return array_keys(get_object_vars($this)) ;
  170. }
  171. }
  172. } else {
  173. if (version_compare(phpversion(),'4.3.10','eq') && !defined('DB_DATAOBJECT_NO_OVERLOAD')) {
  174. trigger_error(
  175. "overload does not work with PHP4.3.10, either upgrade
  176. (snaps.php.net) or more recent version
  177. or define DB_DATAOBJECT_NO_OVERLOAD as per the manual.
  178. ",E_USER_ERROR);
  179. }
  180. if (!function_exists('clone')) {
  181. // emulate clone - as per php_compact, slow but really the correct behaviour..
  182. eval('function clone($t) { $r = $t; if (method_exists($r,"__clone")) { $r->__clone(); } return $r; }');
  183. }
  184. eval('
  185. class DB_DataObject_Overload {
  186. function __call($method,$args,&$return) {
  187. return $this->_call($method,$args,$return);
  188. }
  189. }
  190. ');
  191. }
  192. /*
  193. *
  194. * @package DB_DataObject
  195. * @author Alan Knowles <alan@akbkhome.com>
  196. * @since PHP 4.0
  197. */
  198. class DB_DataObject extends DB_DataObject_Overload
  199. {
  200. /**
  201. * The Version - use this to check feature changes
  202. *
  203. * @access private
  204. * @var string
  205. */
  206. var $_DB_DataObject_version = "1.9.0";
  207. /**
  208. * The Database table (used by table extends)
  209. *
  210. * @access private
  211. * @var string
  212. */
  213. var $__table = ''; // database table
  214. /**
  215. * The Number of rows returned from a query
  216. *
  217. * @access public
  218. * @var int
  219. */
  220. var $N = 0; // Number of rows returned from a query
  221. /* ============================================================= */
  222. /* Major Public Methods */
  223. /* (designed to be optionally then called with parent::method()) */
  224. /* ============================================================= */
  225. /**
  226. * Get a result using key, value.
  227. *
  228. * for example
  229. * $object->get("ID",1234);
  230. * Returns Number of rows located (usually 1) for success,
  231. * and puts all the table columns into this classes variables
  232. *
  233. * see the fetch example on how to extend this.
  234. *
  235. * if no value is entered, it is assumed that $key is a value
  236. * and get will then use the first key in keys()
  237. * to obtain the key.
  238. *
  239. * @param string $k column
  240. * @param string $v value
  241. * @access public
  242. * @return int No. of rows
  243. */
  244. function get($k = null, $v = null)
  245. {
  246. global $_DB_DATAOBJECT;
  247. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  248. DB_DataObject::_loadConfig();
  249. }
  250. $keys = array();
  251. if ($v === null) {
  252. $v = $k;
  253. $keys = $this->keys();
  254. if (!$keys) {
  255. $this->raiseError("No Keys available for {$this->__table}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  256. return false;
  257. }
  258. $k = $keys[0];
  259. }
  260. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  261. $this->debug("$k $v " .print_r($keys,true), "GET");
  262. }
  263. if ($v === null) {
  264. $this->raiseError("No Value specified for get", DB_DATAOBJECT_ERROR_INVALIDARGS);
  265. return false;
  266. }
  267. $this->$k = $v;
  268. return $this->find(1);
  269. }
  270. /**
  271. * An autoloading, caching static get method using key, value (based on get)
  272. * (depreciated - use ::get / and your own caching method)
  273. *
  274. * Usage:
  275. * $object = DB_DataObject::staticGet("DbTable_mytable",12);
  276. * or
  277. * $object = DB_DataObject::staticGet("DbTable_mytable","name","fred");
  278. *
  279. * or write it into your extended class:
  280. * function &staticGet($k,$v=NULL) { return DB_DataObject::staticGet("This_Class",$k,$v); }
  281. *
  282. * @param string $class class name
  283. * @param string $k column (or value if using keys)
  284. * @param string $v value (optional)
  285. * @access public
  286. * @return object
  287. */
  288. function &staticGet($class, $k, $v = null)
  289. {
  290. $lclass = strtolower($class);
  291. global $_DB_DATAOBJECT;
  292. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  293. DB_DataObject::_loadConfig();
  294. }
  295. $key = "$k:$v";
  296. if ($v === null) {
  297. $key = $k;
  298. }
  299. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  300. DB_DataObject::debug("$class $key","STATIC GET - TRY CACHE");
  301. }
  302. if (!empty($_DB_DATAOBJECT['CACHE'][$lclass][$key])) {
  303. return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
  304. }
  305. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  306. DB_DataObject::debug("$class $key","STATIC GET - NOT IN CACHE");
  307. }
  308. $obj = DB_DataObject::factory(substr($class,strlen($_DB_DATAOBJECT['CONFIG']['class_prefix'])));
  309. if (PEAR::isError($obj)) {
  310. DB_DataObject::raiseError("could not autoload $class", DB_DATAOBJECT_ERROR_NOCLASS);
  311. $r = false;
  312. return $r;
  313. }
  314. if (!isset($_DB_DATAOBJECT['CACHE'][$lclass])) {
  315. $_DB_DATAOBJECT['CACHE'][$lclass] = array();
  316. }
  317. if (!$obj->get($k,$v)) {
  318. DB_DataObject::raiseError("No Data return from get $k $v", DB_DATAOBJECT_ERROR_NODATA);
  319. $r = false;
  320. return $r;
  321. }
  322. $_DB_DATAOBJECT['CACHE'][$lclass][$key] = $obj;
  323. return $_DB_DATAOBJECT['CACHE'][$lclass][$key];
  324. }
  325. /**
  326. * find results, either normal or crosstable
  327. *
  328. * for example
  329. *
  330. * $object = new mytable();
  331. * $object->ID = 1;
  332. * $object->find();
  333. *
  334. *
  335. * will set $object->N to number of rows, and expects next command to fetch rows
  336. * will return $object->N
  337. *
  338. * @param boolean $n Fetch first result
  339. * @access public
  340. * @return mixed (number of rows returned, or true if numRows fetching is not supported)
  341. */
  342. function find($n = false)
  343. {
  344. global $_DB_DATAOBJECT;
  345. if ($this->_query === false) {
  346. $this->raiseError(
  347. "You cannot do two queries on the same object (copy it before finding)",
  348. DB_DATAOBJECT_ERROR_INVALIDARGS);
  349. return false;
  350. }
  351. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  352. DB_DataObject::_loadConfig();
  353. }
  354. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  355. $this->debug($n, "find",1);
  356. }
  357. if (!$this->__table) {
  358. // xdebug can backtrace this!
  359. trigger_error("NO \$__table SPECIFIED in class definition",E_USER_ERROR);
  360. }
  361. $this->N = 0;
  362. $query_before = $this->_query;
  363. $this->_build_condition($this->table()) ;
  364. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  365. $this->_connect();
  366. $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  367. /* We are checking for method modifyLimitQuery as it is PEAR DB specific */
  368. $sql = 'SELECT ' .
  369. $this->_query['data_select'] . " \n" .
  370. ' FROM ' . ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table) . " \n" .
  371. $this->_join . " \n" .
  372. $this->_query['condition'] . " \n" .
  373. $this->_query['group_by'] . " \n" .
  374. $this->_query['having'] . " \n" .
  375. $this->_query['order_by'] . " \n";
  376. if ((!isset($_DB_DATAOBJECT['CONFIG']['db_driver'])) ||
  377. ($_DB_DATAOBJECT['CONFIG']['db_driver'] == 'DB')) {
  378. /* PEAR DB specific */
  379. if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
  380. $sql = $DB->modifyLimitQuery($sql,$this->_query['limit_start'], $this->_query['limit_count']);
  381. }
  382. } else {
  383. /* theoretically MDB2! */
  384. if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
  385. $DB->setLimit($this->_query['limit_count'],$this->_query['limit_start']);
  386. }
  387. }
  388. $this->_query($sql);
  389. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  390. $this->debug("CHECK autofetchd $n", "find", 1);
  391. }
  392. // find(true)
  393. $ret = $this->N;
  394. if (!$ret && !empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid])) {
  395. // clear up memory if nothing found!?
  396. unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
  397. }
  398. if ($n && $this->N > 0 ) {
  399. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  400. $this->debug("ABOUT TO AUTOFETCH", "find", 1);
  401. }
  402. $fs = $this->fetch();
  403. // if fetch returns false (eg. failed), then the backend doesnt support numRows (eg. ret=true)
  404. // - hence find() also returns false..
  405. $ret = ($ret === true) ? $fs : $ret;
  406. }
  407. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  408. $this->debug("DONE", "find", 1);
  409. }
  410. $this->_query = $query_before;
  411. return $ret;
  412. }
  413. /**
  414. * fetches next row into this objects var's
  415. *
  416. * returns 1 on success 0 on failure
  417. *
  418. *
  419. *
  420. * Example
  421. * $object = new mytable();
  422. * $object->name = "fred";
  423. * $object->find();
  424. * $store = array();
  425. * while ($object->fetch()) {
  426. * echo $this->ID;
  427. * $store[] = $object; // builds an array of object lines.
  428. * }
  429. *
  430. * to add features to a fetch
  431. * function fetch () {
  432. * $ret = parent::fetch();
  433. * $this->date_formated = date('dmY',$this->date);
  434. * return $ret;
  435. * }
  436. *
  437. * @access public
  438. * @return boolean on success
  439. */
  440. function fetch()
  441. {
  442. global $_DB_DATAOBJECT;
  443. if (empty($_DB_DATAOBJECT['CONFIG'])) {
  444. DB_DataObject::_loadConfig();
  445. }
  446. if (empty($this->N)) {
  447. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  448. $this->debug("No data returned from FIND (eg. N is 0)","FETCH", 3);
  449. }
  450. return false;
  451. }
  452. if (empty($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]) ||
  453. !is_object($result = &$_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]))
  454. {
  455. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  456. $this->debug('fetched on object after fetch completed (no results found)');
  457. }
  458. return false;
  459. }
  460. $array = $result->fetchRow(DB_DATAOBJECT_FETCHMODE_ASSOC);
  461. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  462. $this->debug(serialize($array),"FETCH");
  463. }
  464. // fetched after last row..
  465. if ($array === null) {
  466. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  467. $t= explode(' ',microtime());
  468. $this->debug("Last Data Fetch'ed after " .
  469. ($t[0]+$t[1]- $_DB_DATAOBJECT['QUERYENDTIME'] ) .
  470. " seconds",
  471. "FETCH", 1);
  472. }
  473. // reduce the memory usage a bit... (but leave the id in, so count() works ok on it)
  474. unset($_DB_DATAOBJECT['RESULTS'][$this->_DB_resultid]);
  475. // we need to keep a copy of resultfields locally so toArray() still works
  476. // however we dont want to keep it in the global cache..
  477. if (!empty($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
  478. $this->_resultFields = $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid];
  479. unset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]);
  480. }
  481. // this is probably end of data!!
  482. //DB_DataObject::raiseError("fetch: no data returned", DB_DATAOBJECT_ERROR_NODATA);
  483. return false;
  484. }
  485. // make sure resultFields is always empty..
  486. $this->_resultFields = false;
  487. if (!isset($_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid])) {
  488. // note: we dont declare this to keep the print_r size down.
  489. $_DB_DATAOBJECT['RESULTFIELDS'][$this->_DB_resultid]= array_flip(array_keys($array));
  490. }
  491. foreach($array as $k=>$v) {
  492. $kk = str_replace(".", "_", $k);
  493. $kk = str_replace(" ", "_", $kk);
  494. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  495. $this->debug("$kk = ". $array[$k], "fetchrow LINE", 3);
  496. }
  497. $this->$kk = $array[$k];
  498. }
  499. // set link flag
  500. $this->_link_loaded=false;
  501. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  502. $this->debug("{$this->__table} DONE", "fetchrow",2);
  503. }
  504. if (($this->_query !== false) && empty($_DB_DATAOBJECT['CONFIG']['keep_query_after_fetch'])) {
  505. $this->_query = false;
  506. }
  507. return true;
  508. }
  509. /**
  510. * Adds a condition to the WHERE statement, defaults to AND
  511. *
  512. * $object->whereAdd(); //reset or cleaer ewhwer
  513. * $object->whereAdd("ID > 20");
  514. * $object->whereAdd("age > 20","OR");
  515. *
  516. * @param string $cond condition
  517. * @param string $logic optional logic "OR" (defaults to "AND")
  518. * @access public
  519. * @return string|PEAR::Error - previous condition or Error when invalid args found
  520. */
  521. function whereAdd($cond = false, $logic = 'AND')
  522. {
  523. // for PHP5.2.3 - there is a bug with setting array properties of an object.
  524. $_query = $this->_query;
  525. if (!isset($this->_query) || ($_query === false)) {
  526. return $this->raiseError(
  527. "You cannot do two queries on the same object (clone it before finding)",
  528. DB_DATAOBJECT_ERROR_INVALIDARGS);
  529. }
  530. if ($cond === false) {
  531. $r = $this->_query['condition'];
  532. $_query['condition'] = '';
  533. $this->_query = $_query;
  534. return preg_replace('/^\s+WHERE\s+/','',$r);
  535. }
  536. // check input...= 0 or ' ' == error!
  537. if (!trim($cond)) {
  538. return $this->raiseError("WhereAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  539. }
  540. $r = $_query['condition'];
  541. if ($_query['condition']) {
  542. $_query['condition'] .= " {$logic} ( {$cond} )";
  543. $this->_query = $_query;
  544. return $r;
  545. }
  546. $_query['condition'] = " WHERE ( {$cond} ) ";
  547. $this->_query = $_query;
  548. return $r;
  549. }
  550. /**
  551. * Adds a order by condition
  552. *
  553. * $object->orderBy(); //clears order by
  554. * $object->orderBy("ID");
  555. * $object->orderBy("ID,age");
  556. *
  557. * @param string $order Order
  558. * @access public
  559. * @return none|PEAR::Error - invalid args only
  560. */
  561. function orderBy($order = false)
  562. {
  563. if ($this->_query === false) {
  564. $this->raiseError(
  565. "You cannot do two queries on the same object (copy it before finding)",
  566. DB_DATAOBJECT_ERROR_INVALIDARGS);
  567. return false;
  568. }
  569. if ($order === false) {
  570. $this->_query['order_by'] = '';
  571. return;
  572. }
  573. // check input...= 0 or ' ' == error!
  574. if (!trim($order)) {
  575. return $this->raiseError("orderBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  576. }
  577. if (!$this->_query['order_by']) {
  578. $this->_query['order_by'] = " ORDER BY {$order} ";
  579. return;
  580. }
  581. $this->_query['order_by'] .= " , {$order}";
  582. }
  583. /**
  584. * Adds a group by condition
  585. *
  586. * $object->groupBy(); //reset the grouping
  587. * $object->groupBy("ID DESC");
  588. * $object->groupBy("ID,age");
  589. *
  590. * @param string $group Grouping
  591. * @access public
  592. * @return none|PEAR::Error - invalid args only
  593. */
  594. function groupBy($group = false)
  595. {
  596. if ($this->_query === false) {
  597. $this->raiseError(
  598. "You cannot do two queries on the same object (copy it before finding)",
  599. DB_DATAOBJECT_ERROR_INVALIDARGS);
  600. return false;
  601. }
  602. if ($group === false) {
  603. $this->_query['group_by'] = '';
  604. return;
  605. }
  606. // check input...= 0 or ' ' == error!
  607. if (!trim($group)) {
  608. return $this->raiseError("groupBy: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  609. }
  610. if (!$this->_query['group_by']) {
  611. $this->_query['group_by'] = " GROUP BY {$group} ";
  612. return;
  613. }
  614. $this->_query['group_by'] .= " , {$group}";
  615. }
  616. /**
  617. * Adds a having clause
  618. *
  619. * $object->having(); //reset the grouping
  620. * $object->having("sum(value) > 0 ");
  621. *
  622. * @param string $having condition
  623. * @access public
  624. * @return none|PEAR::Error - invalid args only
  625. */
  626. function having($having = false)
  627. {
  628. if ($this->_query === false) {
  629. $this->raiseError(
  630. "You cannot do two queries on the same object (copy it before finding)",
  631. DB_DATAOBJECT_ERROR_INVALIDARGS);
  632. return false;
  633. }
  634. if ($having === false) {
  635. $this->_query['having'] = '';
  636. return;
  637. }
  638. // check input...= 0 or ' ' == error!
  639. if (!trim($having)) {
  640. return $this->raiseError("Having: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  641. }
  642. if (!$this->_query['having']) {
  643. $this->_query['having'] = " HAVING {$having} ";
  644. return;
  645. }
  646. $this->_query['having'] .= " AND {$having}";
  647. }
  648. /**
  649. * Sets the Limit
  650. *
  651. * $boject->limit(); // clear limit
  652. * $object->limit(12);
  653. * $object->limit(12,10);
  654. *
  655. * Note this will emit an error on databases other than mysql/postgress
  656. * as there is no 'clean way' to implement it. - you should consider refering to
  657. * your database manual to decide how you want to implement it.
  658. *
  659. * @param string $a limit start (or number), or blank to reset
  660. * @param string $b number
  661. * @access public
  662. * @return none|PEAR::Error - invalid args only
  663. */
  664. function limit($a = null, $b = null)
  665. {
  666. if ($this->_query === false) {
  667. $this->raiseError(
  668. "You cannot do two queries on the same object (copy it before finding)",
  669. DB_DATAOBJECT_ERROR_INVALIDARGS);
  670. return false;
  671. }
  672. if ($a === null) {
  673. $this->_query['limit_start'] = '';
  674. $this->_query['limit_count'] = '';
  675. return;
  676. }
  677. // check input...= 0 or ' ' == error!
  678. if ((!is_int($a) && ((string)((int)$a) !== (string)$a))
  679. || (($b !== null) && (!is_int($b) && ((string)((int)$b) !== (string)$b)))) {
  680. return $this->raiseError("limit: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  681. }
  682. global $_DB_DATAOBJECT;
  683. $this->_connect();
  684. $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  685. $this->_query['limit_start'] = ($b == null) ? 0 : (int)$a;
  686. $this->_query['limit_count'] = ($b == null) ? (int)$a : (int)$b;
  687. }
  688. /**
  689. * Adds a select columns
  690. *
  691. * $object->selectAdd(); // resets select to nothing!
  692. * $object->selectAdd("*"); // default select
  693. * $object->selectAdd("unixtime(DATE) as udate");
  694. * $object->selectAdd("DATE");
  695. *
  696. * to prepend distict:
  697. * $object->selectAdd('distinct ' . $object->selectAdd());
  698. *
  699. * @param string $k
  700. * @access public
  701. * @return mixed null or old string if you reset it.
  702. */
  703. function selectAdd($k = null)
  704. {
  705. if ($this->_query === false) {
  706. $this->raiseError(
  707. "You cannot do two queries on the same object (copy it before finding)",
  708. DB_DATAOBJECT_ERROR_INVALIDARGS);
  709. return false;
  710. }
  711. if ($k === null) {
  712. $old = $this->_query['data_select'];
  713. $this->_query['data_select'] = '';
  714. return $old;
  715. }
  716. // check input...= 0 or ' ' == error!
  717. if (!trim($k)) {
  718. return $this->raiseError("selectAdd: No Valid Arguments", DB_DATAOBJECT_ERROR_INVALIDARGS);
  719. }
  720. if ($this->_query['data_select']) {
  721. $this->_query['data_select'] .= ', ';
  722. }
  723. $this->_query['data_select'] .= " $k ";
  724. }
  725. /**
  726. * Adds multiple Columns or objects to select with formating.
  727. *
  728. * $object->selectAs(null); // adds "table.colnameA as colnameA,table.colnameB as colnameB,......"
  729. * // note with null it will also clear the '*' default select
  730. * $object->selectAs(array('a','b'),'%s_x'); // adds "a as a_x, b as b_x"
  731. * $object->selectAs(array('a','b'),'ddd_%s','ccc'); // adds "ccc.a as ddd_a, ccc.b as ddd_b"
  732. * $object->selectAdd($object,'prefix_%s'); // calls $object->get_table and adds it all as
  733. * objectTableName.colnameA as prefix_colnameA
  734. *
  735. * @param array|object|null the array or object to take column names from.
  736. * @param string format in sprintf format (use %s for the colname)
  737. * @param string table name eg. if you have joinAdd'd or send $from as an array.
  738. * @access public
  739. * @return void
  740. */
  741. function selectAs($from = null,$format = '%s',$tableName=false)
  742. {
  743. global $_DB_DATAOBJECT;
  744. if ($this->_query === false) {
  745. $this->raiseError(
  746. "You cannot do two queries on the same object (copy it before finding)",
  747. DB_DATAOBJECT_ERROR_INVALIDARGS);
  748. return false;
  749. }
  750. if ($from === null) {
  751. // blank the '*'
  752. $this->selectAdd();
  753. $from = $this;
  754. }
  755. $table = $this->__table;
  756. if (is_object($from)) {
  757. $table = $from->__table;
  758. $from = array_keys($from->table());
  759. }
  760. if ($tableName !== false) {
  761. $table = $tableName;
  762. }
  763. $s = '%s';
  764. if (!empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers'])) {
  765. $this->_connect();
  766. $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  767. $s = $DB->quoteIdentifier($s);
  768. $format = $DB->quoteIdentifier($format);
  769. }
  770. foreach ($from as $k) {
  771. $this->selectAdd(sprintf("{$s}.{$s} as {$format}",$table,$k,$k));
  772. }
  773. $this->_query['data_select'] .= "\n";
  774. }
  775. /**
  776. * Insert the current objects variables into the database
  777. *
  778. * Returns the ID of the inserted element (if auto increment or sequences are used.)
  779. *
  780. * for example
  781. *
  782. * Designed to be extended
  783. *
  784. * $object = new mytable();
  785. * $object->name = "fred";
  786. * echo $object->insert();
  787. *
  788. * @access public
  789. * @return mixed false on failure, int when auto increment or sequence used, otherwise true on success
  790. */
  791. function insert()
  792. {
  793. global $_DB_DATAOBJECT;
  794. // we need to write to the connection (For nextid) - so us the real
  795. // one not, a copyied on (as ret-by-ref fails with overload!)
  796. if (!isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5])) {
  797. $this->_connect();
  798. }
  799. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  800. $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  801. $items = isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ?
  802. $_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table();
  803. if (!$items) {
  804. $this->raiseError("insert:No table definition for {$this->__table}",
  805. DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  806. return false;
  807. }
  808. $options = &$_DB_DATAOBJECT['CONFIG'];
  809. $datasaved = 1;
  810. $leftq = '';
  811. $rightq = '';
  812. $seqKeys = isset($_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table]) ?
  813. $_DB_DATAOBJECT['SEQUENCE'][$this->_database][$this->__table] :
  814. $this->sequenceKey();
  815. $key = isset($seqKeys[0]) ? $seqKeys[0] : false;
  816. $useNative = isset($seqKeys[1]) ? $seqKeys[1] : false;
  817. $seq = isset($seqKeys[2]) ? $seqKeys[2] : false;
  818. $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn["phptype"];
  819. // nativeSequences or Sequences..
  820. // big check for using sequences
  821. if (($key !== false) && !$useNative) {
  822. if (!$seq) {
  823. $keyvalue = $DB->nextId($this->__table);
  824. } else {
  825. $f = $DB->getOption('seqname_format');
  826. $DB->setOption('seqname_format','%s');
  827. $keyvalue = $DB->nextId($seq);
  828. $DB->setOption('seqname_format',$f);
  829. }
  830. if (PEAR::isError($keyvalue)) {
  831. $this->raiseError($keyvalue->toString(), DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  832. return false;
  833. }
  834. $this->$key = $keyvalue;
  835. }
  836. // if we haven't set disable_null_strings to "full"
  837. $ignore_null = !isset($options['disable_null_strings'])
  838. || !is_string($options['disable_null_strings'])
  839. || strtolower($options['disable_null_strings']) !== 'full' ;
  840. foreach($items as $k => $v) {
  841. // if we are using autoincrement - skip the column...
  842. if ($key && ($k == $key) && $useNative) {
  843. continue;
  844. }
  845. // Ignore variables which aren't set to a value
  846. if ( !isset($this->$k) && $ignore_null) {
  847. continue;
  848. }
  849. // dont insert data into mysql timestamps
  850. // use query() if you really want to do this!!!!
  851. if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
  852. continue;
  853. }
  854. if ($leftq) {
  855. $leftq .= ', ';
  856. $rightq .= ', ';
  857. }
  858. $leftq .= ($quoteIdentifiers ? ($DB->quoteIdentifier($k) . ' ') : "$k ");
  859. if (is_a($this->$k,'DB_DataObject_Cast')) {
  860. $value = $this->$k->toString($v,$DB);
  861. if (PEAR::isError($value)) {
  862. $this->raiseError($value->toString() ,DB_DATAOBJECT_ERROR_INVALIDARGS);
  863. return false;
  864. }
  865. $rightq .= $value;
  866. continue;
  867. }
  868. if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this,$k)) {
  869. $rightq .= " NULL ";
  870. continue;
  871. }
  872. // DATE is empty... on a col. that can be null..
  873. // note: this may be usefull for time as well..
  874. if (!$this->$k &&
  875. (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
  876. !($v & DB_DATAOBJECT_NOTNULL)) {
  877. $rightq .= " NULL ";
  878. continue;
  879. }
  880. if ($v & DB_DATAOBJECT_STR) {
  881. $rightq .= $this->_quote((string) (
  882. ($v & DB_DATAOBJECT_BOOL) ?
  883. // this is thanks to the braindead idea of postgres to
  884. // use t/f for boolean.
  885. (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
  886. $this->$k
  887. )) . " ";
  888. continue;
  889. }
  890. if (is_numeric($this->$k)) {
  891. $rightq .=" {$this->$k} ";
  892. continue;
  893. }
  894. /* flag up string values - only at debug level... !!!??? */
  895. if (is_object($this->$k) || is_array($this->$k)) {
  896. $this->debug('ODD DATA: ' .$k . ' ' . print_r($this->$k,true),'ERROR');
  897. }
  898. // at present we only cast to integers
  899. // - V2 may store additional data about float/int
  900. $rightq .= ' ' . intval($this->$k) . ' ';
  901. }
  902. // not sure why we let empty insert here.. - I guess to generate a blank row..
  903. if ($leftq || $useNative) {
  904. $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table);
  905. if (($dbtype == 'pgsql') && empty($leftq)) {
  906. $r = $this->_query("INSERT INTO {$table} DEFAULT VALUES");
  907. } else {
  908. $r = $this->_query("INSERT INTO {$table} ($leftq) VALUES ($rightq) ");
  909. }
  910. if (PEAR::isError($r)) {
  911. $this->raiseError($r);
  912. return false;
  913. }
  914. if ($r < 1) {
  915. return 0;
  916. }
  917. // now do we have an integer key!
  918. if ($key && $useNative) {
  919. switch ($dbtype) {
  920. case 'mysql':
  921. case 'mysqli':
  922. $method = "{$dbtype}_insert_id";
  923. $this->$key = $method(
  924. $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection
  925. );
  926. break;
  927. case 'mssql':
  928. // note this is not really thread safe - you should wrapp it with
  929. // transactions = eg.
  930. // $db->query('BEGIN');
  931. // $db->insert();
  932. // $db->query('COMMIT');
  933. $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
  934. $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
  935. $mssql_key = $DB->$method("SELECT @@IDENTITY");
  936. if (PEAR::isError($mssql_key)) {
  937. $this->raiseError($mssql_key);
  938. return false;
  939. }
  940. $this->$key = $mssql_key;
  941. break;
  942. case 'pgsql':
  943. if (!$seq) {
  944. $seq = $DB->getSequenceName(strtolower($this->__table));
  945. }
  946. $db_driver = empty($options['db_driver']) ? 'DB' : $options['db_driver'];
  947. $method = ($db_driver == 'DB') ? 'getOne' : 'queryOne';
  948. $pgsql_key = $DB->$method("SELECT currval('".$seq . "')");
  949. if (PEAR::isError($pgsql_key)) {
  950. $this->raiseError($pgsql_key);
  951. return false;
  952. }
  953. $this->$key = $pgsql_key;
  954. break;
  955. case 'ifx':
  956. $this->$key = array_shift (
  957. ifx_fetch_row (
  958. ifx_query(
  959. "select DBINFO('sqlca.sqlerrd1') FROM systables where tabid=1",
  960. $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->connection,
  961. IFX_SCROLL
  962. ),
  963. "FIRST"
  964. )
  965. );
  966. break;
  967. }
  968. }
  969. if (isset($_DB_DATAOBJECT['CACHE'][strtolower(get_class($this))])) {
  970. $this->_clear_cache();
  971. }
  972. if ($key) {
  973. return $this->$key;
  974. }
  975. return true;
  976. }
  977. $this->raiseError("insert: No Data specifed for query", DB_DATAOBJECT_ERROR_NODATA);
  978. return false;
  979. }
  980. /**
  981. * Updates current objects variables into the database
  982. * uses the keys() to decide how to update
  983. * Returns the true on success
  984. *
  985. * for example
  986. *
  987. * $object = DB_DataObject::factory('mytable');
  988. * $object->get("ID",234);
  989. * $object->email="testing@test.com";
  990. * if(!$object->update())
  991. * echo "UPDATE FAILED";
  992. *
  993. * to only update changed items :
  994. * $dataobject->get(132);
  995. * $original = $dataobject; // clone/copy it..
  996. * $dataobject->setFrom($_POST);
  997. * if ($dataobject->validate()) {
  998. * $dataobject->update($original);
  999. * } // otherwise an error...
  1000. *
  1001. * performing global updates:
  1002. * $object = DB_DataObject::factory('mytable');
  1003. * $object->status = "dead";
  1004. * $object->whereAdd('age > 150');
  1005. * $object->update(DB_DATAOBJECT_WHEREADD_ONLY);
  1006. *
  1007. * @param object dataobject (optional) | DB_DATAOBJECT_WHEREADD_ONLY - used to only update changed items.
  1008. * @access public
  1009. * @return int rows affected or false on failure
  1010. */
  1011. function update($dataObject = false)
  1012. {
  1013. global $_DB_DATAOBJECT;
  1014. // connect will load the config!
  1015. $this->_connect();
  1016. $original_query = $this->_query;
  1017. $items = isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table]) ?
  1018. $_DB_DATAOBJECT['INI'][$this->_database][$this->__table] : $this->table();
  1019. // only apply update against sequence key if it is set?????
  1020. $seq = $this->sequenceKey();
  1021. if ($seq[0] !== false) {
  1022. $keys = array($seq[0]);
  1023. if (empty($this->{$keys[0]}) && $dataObject !== true) {
  1024. $this->raiseError("update: trying to perform an update without
  1025. the key set, and argument to update is not
  1026. DB_DATAOBJECT_WHEREADD_ONLY
  1027. ", DB_DATAOBJECT_ERROR_INVALIDARGS);
  1028. return false;
  1029. }
  1030. } else {
  1031. $keys = $this->keys();
  1032. }
  1033. if (!$items) {
  1034. $this->raiseError("update:No table definition for {$this->__table}", DB_DATAOBJECT_ERROR_INVALIDCONFIG);
  1035. return false;
  1036. }
  1037. $datasaved = 1;
  1038. $settings = '';
  1039. $this->_connect();
  1040. $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  1041. $dbtype = $DB->dsn["phptype"];
  1042. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  1043. $options = $_DB_DATAOBJECT['CONFIG'];
  1044. $ignore_null = !isset($options['disable_null_strings'])
  1045. || !is_string($options['disable_null_strings'])
  1046. || strtolower($options['disable_null_strings']) !== 'full' ;
  1047. foreach($items as $k => $v) {
  1048. if (!isset($this->$k) && $ignore_null) {
  1049. continue;
  1050. }
  1051. // ignore stuff thats
  1052. // dont write things that havent changed..
  1053. if (($dataObject !== false) && isset($dataObject->$k) && ($dataObject->$k === $this->$k)) {
  1054. continue;
  1055. }
  1056. // - dont write keys to left.!!!
  1057. if (in_array($k,$keys)) {
  1058. continue;
  1059. }
  1060. // dont insert data into mysql timestamps
  1061. // use query() if you really want to do this!!!!
  1062. if ($v & DB_DATAOBJECT_MYSQLTIMESTAMP) {
  1063. continue;
  1064. }
  1065. if ($settings) {
  1066. $settings .= ', ';
  1067. }
  1068. $kSql = ($quoteIdentifiers ? $DB->quoteIdentifier($k) : $k);
  1069. if (is_a($this->$k,'DB_DataObject_Cast')) {
  1070. $value = $this->$k->toString($v,$DB);
  1071. if (PEAR::isError($value)) {
  1072. $this->raiseError($value->getMessage() ,DB_DATAOBJECT_ERROR_INVALIDARG);
  1073. return false;
  1074. }
  1075. $settings .= "$kSql = $value ";
  1076. continue;
  1077. }
  1078. // special values ... at least null is handled...
  1079. if (!($v & DB_DATAOBJECT_NOTNULL) && DB_DataObject::_is_null($this,$k)) {
  1080. $settings .= "$kSql = NULL ";
  1081. continue;
  1082. }
  1083. // DATE is empty... on a col. that can be null..
  1084. // note: this may be usefull for time as well..
  1085. if (!$this->$k &&
  1086. (($v & DB_DATAOBJECT_DATE) || ($v & DB_DATAOBJECT_TIME)) &&
  1087. !($v & DB_DATAOBJECT_NOTNULL)) {
  1088. $settings .= "$kSql = NULL ";
  1089. continue;
  1090. }
  1091. if ($v & DB_DATAOBJECT_STR) {
  1092. $settings .= "$kSql = ". $this->_quote((string) (
  1093. ($v & DB_DATAOBJECT_BOOL) ?
  1094. // this is thanks to the braindead idea of postgres to
  1095. // use t/f for boolean.
  1096. (($this->$k === 'f') ? 0 : (int)(bool) $this->$k) :
  1097. $this->$k
  1098. )) . ' ';
  1099. continue;
  1100. }
  1101. if (is_numeric($this->$k)) {
  1102. $settings .= "$kSql = {$this->$k} ";
  1103. continue;
  1104. }
  1105. // at present we only cast to integers
  1106. // - V2 may store additional data about float/int
  1107. $settings .= "$kSql = " . intval($this->$k) . ' ';
  1108. }
  1109. if (!empty($_DB_DATAOBJECT['CONFIG']['debug'])) {
  1110. $this->debug("got keys as ".serialize($keys),3);
  1111. }
  1112. if ($dataObject !== true) {
  1113. $this->_build_condition($items,$keys);
  1114. } else {
  1115. // prevent wiping out of data!
  1116. if (empty($this->_query['condition'])) {
  1117. $this->raiseError("update: global table update not available
  1118. do \$do->whereAdd('1=1'); if you really want to do that.
  1119. ", DB_DATAOBJECT_ERROR_INVALIDARGS);
  1120. return false;
  1121. }
  1122. }
  1123. // echo " $settings, $this->condition ";
  1124. if ($settings && isset($this->_query) && $this->_query['condition']) {
  1125. $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table);
  1126. $r = $this->_query("UPDATE {$table} SET {$settings} {$this->_query['condition']} ");
  1127. // restore original query conditions.
  1128. $this->_query = $original_query;
  1129. if (PEAR::isError($r)) {
  1130. $this->raiseError($r);
  1131. return false;
  1132. }
  1133. if ($r < 1) {
  1134. return 0;
  1135. }
  1136. $this->_clear_cache();
  1137. return $r;
  1138. }
  1139. // restore original query conditions.
  1140. $this->_query = $original_query;
  1141. // if you manually specified a dataobject, and there where no changes - then it's ok..
  1142. if ($dataObject !== false) {
  1143. return true;
  1144. }
  1145. $this->raiseError(
  1146. "update: No Data specifed for query $settings , {$this->_query['condition']}",
  1147. DB_DATAOBJECT_ERROR_NODATA);
  1148. return false;
  1149. }
  1150. /**
  1151. * Deletes items from table which match current objects variables
  1152. *
  1153. * Returns the true on success
  1154. *
  1155. * for example
  1156. *
  1157. * Designed to be extended
  1158. *
  1159. * $object = new mytable();
  1160. * $object->ID=123;
  1161. * echo $object->delete(); // builds a conditon
  1162. *
  1163. * $object = new mytable();
  1164. * $object->whereAdd('age > 12');
  1165. * $object->limit(1);
  1166. * $object->orderBy('age DESC');
  1167. * $object->delete(true); // dont use object vars, use the conditions, limit and order.
  1168. *
  1169. * @param bool $useWhere (optional) If DB_DATAOBJECT_WHEREADD_ONLY is passed in then
  1170. * we will build the condition only using the whereAdd's. Default is to
  1171. * build the condition only using the object parameters.
  1172. *
  1173. * @access public
  1174. * @return mixed Int (No. of rows affected) on success, false on failure, 0 on no data affected
  1175. */
  1176. function delete($useWhere = false)
  1177. {
  1178. global $_DB_DATAOBJECT;
  1179. // connect will load the config!
  1180. $this->_connect();
  1181. $DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
  1182. $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']);
  1183. $extra_cond = ' ' . (isset($this->_query['order_by']) ? $this->_query['order_by'] : '');
  1184. if (!$useWhere) {
  1185. $keys = $this->keys();
  1186. $this->_query = array(); // as it's probably unset!
  1187. $this->_query['condition'] = ''; // default behaviour not to use where condition
  1188. $this->_build_condition($this->table(),$keys);
  1189. // if primary keys are not set then use data from rest of object.
  1190. if (!$this->_query['condition']) {
  1191. $this->_build_condition($this->table(),array(),$keys);
  1192. }
  1193. $extra_cond = '';
  1194. }
  1195. // don't delete without a condition
  1196. if (($this->_query !== false) && $this->_query['condition']) {
  1197. $table = ($quoteIdentifiers ? $DB->quoteIdentifier($this->__table) : $this->__table);
  1198. $sql = "DELETE ";
  1199. // using a joined delete. - with useWhere..
  1200. $sql .= (!empty($this->_join) && $useWhere) ?
  1201. "{$table} FROM {$table} {$this->_join} " :
  1202. "FROM {$table} ";
  1203. $sql .= $this->_query['condition']. $extra_cond;
  1204. // add limit..
  1205. if (isset($this->_query['limit_start']) && strlen($this->_query['limit_start'] . $this->_query['limit_count'])) {
  1206. if (!isset($_DB_DATAOBJECT['CONFIG']['db_driver']) ||
  1207. ($_DB_DATAOBJECT['…

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