PageRenderTime 64ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/extlib/DB/DataObject.php

https://bitbucket.org/stk2k/charcoalphp2.1
PHP | 4082 lines | 2354 code | 619 blank | 1109 comment | 560 complexity | 491dee0afc438e7b258de10a4d72acc8 MD5 | raw file

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

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