PageRenderTime 51ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/libraries/3rdparty/adodb/adodb-active-record.inc.php

https://bitbucket.org/selfeky/xclusivescardwebsite
PHP | 1005 lines | 755 code | 161 blank | 89 comment | 184 complexity | c746620891f8f240df217ed6873f5e3e MD5 | raw file
  1. <?php
  2. /*
  3. @version V5.18 3 Sep 2012 (c) 2000-2012 John Lim (jlim#natsoft.com). All rights reserved.
  4. Latest version is available at http://adodb.sourceforge.net
  5. Released under both BSD license and Lesser GPL library license.
  6. Whenever there is any discrepancy between the two licenses,
  7. the BSD license will take precedence.
  8. Active Record implementation. Superset of Zend Framework's.
  9. Version 0.92
  10. See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord
  11. for info on Ruby on Rails Active Record implementation
  12. */
  13. global $_ADODB_ACTIVE_DBS;
  14. global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
  15. global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
  16. global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
  17. // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
  18. $_ADODB_ACTIVE_DBS = array();
  19. $ACTIVE_RECORD_SAFETY = true;
  20. $ADODB_ACTIVE_DEFVALS = false;
  21. $ADODB_ACTIVE_CACHESECS = 0;
  22. class ADODB_Active_DB {
  23. var $db; // ADOConnection
  24. var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
  25. }
  26. class ADODB_Active_Table {
  27. var $name; // table name
  28. var $flds; // assoc array of adofieldobjs, indexed by fieldname
  29. var $keys; // assoc array of primary keys, indexed by fieldname
  30. var $_created; // only used when stored as a cached file
  31. var $_belongsTo = array();
  32. var $_hasMany = array();
  33. }
  34. // $db = database connection
  35. // $index = name of index - can be associative, for an example see
  36. // http://phplens.com/lens/lensforum/msgs.php?id=17790
  37. // returns index into $_ADODB_ACTIVE_DBS
  38. function ADODB_SetDatabaseAdapter(&$db, $index=false)
  39. {
  40. global $_ADODB_ACTIVE_DBS;
  41. foreach($_ADODB_ACTIVE_DBS as $k => $d) {
  42. if (PHP_VERSION >= 5) {
  43. if ($d->db === $db) return $k;
  44. } else {
  45. if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database)
  46. return $k;
  47. }
  48. }
  49. $obj = new ADODB_Active_DB();
  50. $obj->db = $db;
  51. $obj->tables = array();
  52. if ($index == false) $index = sizeof($_ADODB_ACTIVE_DBS);
  53. $_ADODB_ACTIVE_DBS[$index] = $obj;
  54. return sizeof($_ADODB_ACTIVE_DBS)-1;
  55. }
  56. class ADODB_Active_Record {
  57. static $_changeNames = true; // dynamically pluralize table names
  58. static $_quoteNames = false;
  59. static $_foreignSuffix = '_id'; //
  60. var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
  61. var $_table; // tablename, if set in class definition then use it as table name
  62. var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
  63. var $_where; // where clause set in Load()
  64. var $_saved = false; // indicates whether data is already inserted.
  65. var $_lasterr = false; // last error message
  66. var $_original = false; // the original values loaded or inserted, refreshed on update
  67. var $foreignName; // CFR: class name when in a relationship
  68. var $lockMode = ' for update '; // you might want to change to
  69. static function UseDefaultValues($bool=null)
  70. {
  71. global $ADODB_ACTIVE_DEFVALS;
  72. if (isset($bool)) $ADODB_ACTIVE_DEFVALS = $bool;
  73. return $ADODB_ACTIVE_DEFVALS;
  74. }
  75. // should be static
  76. static function SetDatabaseAdapter(&$db, $index=false)
  77. {
  78. return ADODB_SetDatabaseAdapter($db, $index);
  79. }
  80. public function __set($name, $value)
  81. {
  82. $name = str_replace(' ', '_', $name);
  83. $this->$name = $value;
  84. }
  85. // php5 constructor
  86. function __construct($table = false, $pkeyarr=false, $db=false)
  87. {
  88. global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
  89. if ($db == false && is_object($pkeyarr)) {
  90. $db = $pkeyarr;
  91. $pkeyarr = false;
  92. }
  93. if (!$table) {
  94. if (!empty($this->_table)) $table = $this->_table;
  95. else $table = $this->_pluralize(get_class($this));
  96. }
  97. $this->foreignName = strtolower(get_class($this)); // CFR: default foreign name
  98. if ($db) {
  99. $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
  100. } else if (!isset($this->_dbat)) {
  101. if (sizeof($_ADODB_ACTIVE_DBS) == 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
  102. end($_ADODB_ACTIVE_DBS);
  103. $this->_dbat = key($_ADODB_ACTIVE_DBS);
  104. }
  105. $this->_table = $table;
  106. $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
  107. $this->UpdateActiveTable($pkeyarr);
  108. }
  109. function __wakeup()
  110. {
  111. $class = get_class($this);
  112. new $class;
  113. }
  114. function _pluralize($table)
  115. {
  116. if (!ADODB_Active_Record::$_changeNames) return $table;
  117. $ut = strtoupper($table);
  118. $len = strlen($table);
  119. $lastc = $ut[$len-1];
  120. $lastc2 = substr($ut,$len-2);
  121. switch ($lastc) {
  122. case 'S':
  123. return $table.'es';
  124. case 'Y':
  125. return substr($table,0,$len-1).'ies';
  126. case 'X':
  127. return $table.'es';
  128. case 'H':
  129. if ($lastc2 == 'CH' || $lastc2 == 'SH')
  130. return $table.'es';
  131. default:
  132. return $table.'s';
  133. }
  134. }
  135. // CFR Lamest singular inflector ever - @todo Make it real!
  136. // Note: There is an assumption here...and it is that the argument's length >= 4
  137. function _singularize($tables)
  138. {
  139. if (!ADODB_Active_Record::$_changeNames) return $table;
  140. $ut = strtoupper($tables);
  141. $len = strlen($tables);
  142. if($ut[$len-1] != 'S')
  143. return $tables; // I know...forget oxen
  144. if($ut[$len-2] != 'E')
  145. return substr($tables, 0, $len-1);
  146. switch($ut[$len-3])
  147. {
  148. case 'S':
  149. case 'X':
  150. return substr($tables, 0, $len-2);
  151. case 'I':
  152. return substr($tables, 0, $len-3) . 'y';
  153. case 'H';
  154. if($ut[$len-4] == 'C' || $ut[$len-4] == 'S')
  155. return substr($tables, 0, $len-2);
  156. default:
  157. return substr($tables, 0, $len-1); // ?
  158. }
  159. }
  160. function hasMany($foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
  161. {
  162. $ar = new $foreignClass($foreignRef);
  163. $ar->foreignName = $foreignRef;
  164. $ar->UpdateActiveTable();
  165. $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
  166. $table =& $this->TableInfo();
  167. $table->_hasMany[$foreignRef] = $ar;
  168. # $this->$foreignRef = $this->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
  169. }
  170. // use when you don't want ADOdb to auto-pluralize tablename
  171. static function TableHasMany($table, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
  172. {
  173. $ar = new ADODB_Active_Record($table);
  174. $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
  175. }
  176. // use when you don't want ADOdb to auto-pluralize tablename
  177. static function TableKeyHasMany($table, $tablePKey, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
  178. {
  179. if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
  180. $ar = new ADODB_Active_Record($table,$tablePKey);
  181. $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
  182. }
  183. // use when you want ADOdb to auto-pluralize tablename for you. Note that the class must already be defined.
  184. // e.g. class Person will generate relationship for table Persons
  185. static function ClassHasMany($parentclass, $foreignRef, $foreignKey = false, $foreignClass = 'ADODB_Active_Record')
  186. {
  187. $ar = new $parentclass();
  188. $ar->hasMany($foreignRef, $foreignKey, $foreignClass);
  189. }
  190. function belongsTo($foreignRef,$foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
  191. {
  192. global $inflector;
  193. $ar = new $parentClass($this->_pluralize($foreignRef));
  194. $ar->foreignName = $foreignRef;
  195. $ar->parentKey = $parentKey;
  196. $ar->UpdateActiveTable();
  197. $ar->foreignKey = ($foreignKey) ? $foreignKey : $foreignRef.ADODB_Active_Record::$_foreignSuffix;
  198. $table =& $this->TableInfo();
  199. $table->_belongsTo[$foreignRef] = $ar;
  200. # $this->$foreignRef = $this->_belongsTo[$foreignRef];
  201. }
  202. static function ClassBelongsTo($class, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
  203. {
  204. $ar = new $class();
  205. $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
  206. }
  207. static function TableBelongsTo($table, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
  208. {
  209. $ar = new ADOdb_Active_Record($table);
  210. $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
  211. }
  212. static function TableKeyBelongsTo($table, $tablePKey, $foreignRef, $foreignKey=false, $parentKey='', $parentClass = 'ADODB_Active_Record')
  213. {
  214. if (!is_array($tablePKey)) $tablePKey = array($tablePKey);
  215. $ar = new ADOdb_Active_Record($table, $tablePKey);
  216. $ar->belongsTo($foreignRef, $foreignKey, $parentKey, $parentClass);
  217. }
  218. /**
  219. * __get Access properties - used for lazy loading
  220. *
  221. * @param mixed $name
  222. * @access protected
  223. * @return mixed
  224. */
  225. function __get($name)
  226. {
  227. return $this->LoadRelations($name, '', -1, -1);
  228. }
  229. /**
  230. * @param string $name
  231. * @param string $whereOrderBy : eg. ' AND field1 = value ORDER BY field2'
  232. * @param offset
  233. * @param limit
  234. * @return mixed
  235. */
  236. function LoadRelations($name, $whereOrderBy='', $offset=-1,$limit=-1)
  237. {
  238. $extras = array();
  239. $table = $this->TableInfo();
  240. if ($limit >= 0) $extras['limit'] = $limit;
  241. if ($offset >= 0) $extras['offset'] = $offset;
  242. if (strlen($whereOrderBy))
  243. if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy))
  244. if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy))
  245. $whereOrderBy = 'AND '.$whereOrderBy;
  246. if(!empty($table->_belongsTo[$name]))
  247. {
  248. $obj = $table->_belongsTo[$name];
  249. $columnName = $obj->foreignKey;
  250. if(empty($this->$columnName))
  251. $this->$name = null;
  252. else
  253. {
  254. if ($obj->parentKey) $key = $obj->parentKey;
  255. else $key = reset($table->keys);
  256. $arrayOfOne = $obj->Find($key.'='.$this->$columnName.' '.$whereOrderBy,false,false,$extras);
  257. if ($arrayOfOne) {
  258. $this->$name = $arrayOfOne[0];
  259. return $arrayOfOne[0];
  260. }
  261. }
  262. }
  263. if(!empty($table->_hasMany[$name]))
  264. {
  265. $obj = $table->_hasMany[$name];
  266. $key = reset($table->keys);
  267. $id = @$this->$key;
  268. if (!is_numeric($id)) {
  269. $db = $this->DB();
  270. $id = $db->qstr($id);
  271. }
  272. $objs = $obj->Find($obj->foreignKey.'='.$id. ' '.$whereOrderBy,false,false,$extras);
  273. if (!$objs) $objs = array();
  274. $this->$name = $objs;
  275. return $objs;
  276. }
  277. return array();
  278. }
  279. //////////////////////////////////
  280. // update metadata
  281. function UpdateActiveTable($pkeys=false,$forceUpdate=false)
  282. {
  283. global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
  284. global $ADODB_ACTIVE_DEFVALS,$ADODB_FETCH_MODE;
  285. $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  286. $table = $this->_table;
  287. $tables = $activedb->tables;
  288. $tableat = $this->_tableat;
  289. if (!$forceUpdate && !empty($tables[$tableat])) {
  290. $acttab = $tables[$tableat];
  291. foreach($acttab->flds as $name => $fld) {
  292. if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value))
  293. $this->$name = $fld->default_value;
  294. else
  295. $this->$name = null;
  296. }
  297. return;
  298. }
  299. $db = $activedb->db;
  300. $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
  301. if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
  302. $fp = fopen($fname,'r');
  303. @flock($fp, LOCK_SH);
  304. $acttab = unserialize(fread($fp,100000));
  305. fclose($fp);
  306. if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
  307. // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
  308. // ideally, you should cache at least 32 secs
  309. foreach($acttab->flds as $name => $fld) {
  310. if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value))
  311. $this->$name = $fld->default_value;
  312. else
  313. $this->$name = null;
  314. }
  315. $activedb->tables[$table] = $acttab;
  316. //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
  317. return;
  318. } else if ($db->debug) {
  319. ADOConnection::outp("Refreshing cached active record file: $fname");
  320. }
  321. }
  322. $activetab = new ADODB_Active_Table();
  323. $activetab->name = $table;
  324. $save = $ADODB_FETCH_MODE;
  325. $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
  326. if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
  327. $cols = $db->MetaColumns($table);
  328. if (isset($savem)) $db->SetFetchMode($savem);
  329. $ADODB_FETCH_MODE = $save;
  330. if (!$cols) {
  331. $this->Error("Invalid table name: $table",'UpdateActiveTable');
  332. return false;
  333. }
  334. $fld = reset($cols);
  335. if (!$pkeys) {
  336. if (isset($fld->primary_key)) {
  337. $pkeys = array();
  338. foreach($cols as $name => $fld) {
  339. if (!empty($fld->primary_key)) $pkeys[] = $name;
  340. }
  341. } else
  342. $pkeys = $this->GetPrimaryKeys($db, $table);
  343. }
  344. if (empty($pkeys)) {
  345. $this->Error("No primary key found for table $table",'UpdateActiveTable');
  346. return false;
  347. }
  348. $attr = array();
  349. $keys = array();
  350. switch($ADODB_ASSOC_CASE) {
  351. case 0:
  352. foreach($cols as $name => $fldobj) {
  353. $name = strtolower($name);
  354. if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  355. $this->$name = $fldobj->default_value;
  356. else
  357. $this->$name = null;
  358. $attr[$name] = $fldobj;
  359. }
  360. foreach($pkeys as $k => $name) {
  361. $keys[strtolower($name)] = strtolower($name);
  362. }
  363. break;
  364. case 1:
  365. foreach($cols as $name => $fldobj) {
  366. $name = strtoupper($name);
  367. if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  368. $this->$name = $fldobj->default_value;
  369. else
  370. $this->$name = null;
  371. $attr[$name] = $fldobj;
  372. }
  373. foreach($pkeys as $k => $name) {
  374. $keys[strtoupper($name)] = strtoupper($name);
  375. }
  376. break;
  377. default:
  378. foreach($cols as $name => $fldobj) {
  379. $name = ($fldobj->name);
  380. if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  381. $this->$name = $fldobj->default_value;
  382. else
  383. $this->$name = null;
  384. $attr[$name] = $fldobj;
  385. }
  386. foreach($pkeys as $k => $name) {
  387. $keys[$name] = $cols[$name]->name;
  388. }
  389. break;
  390. }
  391. $activetab->keys = $keys;
  392. $activetab->flds = $attr;
  393. if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
  394. $activetab->_created = time();
  395. $s = serialize($activetab);
  396. if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
  397. adodb_write_file($fname,$s);
  398. }
  399. if (isset($activedb->tables[$table])) {
  400. $oldtab = $activedb->tables[$table];
  401. if ($oldtab) $activetab->_belongsTo = $oldtab->_belongsTo;
  402. if ($oldtab) $activetab->_hasMany = $oldtab->_hasMany;
  403. }
  404. $activedb->tables[$table] = $activetab;
  405. }
  406. function GetPrimaryKeys(&$db, $table)
  407. {
  408. return $db->MetaPrimaryKeys($table);
  409. }
  410. // error handler for both PHP4+5.
  411. function Error($err,$fn)
  412. {
  413. global $_ADODB_ACTIVE_DBS;
  414. $fn = get_class($this).'::'.$fn;
  415. $this->_lasterr = $fn.': '.$err;
  416. if ($this->_dbat < 0) $db = false;
  417. else {
  418. $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  419. $db = $activedb->db;
  420. }
  421. if (function_exists('adodb_throw')) {
  422. if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
  423. else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
  424. } else
  425. if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
  426. }
  427. // return last error message
  428. function ErrorMsg()
  429. {
  430. if (!function_exists('adodb_throw')) {
  431. if ($this->_dbat < 0) $db = false;
  432. else $db = $this->DB();
  433. // last error could be database error too
  434. if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
  435. }
  436. return $this->_lasterr;
  437. }
  438. function ErrorNo()
  439. {
  440. if ($this->_dbat < 0) return -9999; // no database connection...
  441. $db = $this->DB();
  442. return (int) $db->ErrorNo();
  443. }
  444. // retrieve ADOConnection from _ADODB_Active_DBs
  445. function DB()
  446. {
  447. global $_ADODB_ACTIVE_DBS;
  448. if ($this->_dbat < 0) {
  449. $false = false;
  450. $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
  451. return $false;
  452. }
  453. $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  454. $db = $activedb->db;
  455. return $db;
  456. }
  457. // retrieve ADODB_Active_Table
  458. function &TableInfo()
  459. {
  460. global $_ADODB_ACTIVE_DBS;
  461. $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
  462. $table = $activedb->tables[$this->_tableat];
  463. return $table;
  464. }
  465. // I have an ON INSERT trigger on a table that sets other columns in the table.
  466. // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
  467. function Reload()
  468. {
  469. $db =& $this->DB(); if (!$db) return false;
  470. $table =& $this->TableInfo();
  471. $where = $this->GenWhere($db, $table);
  472. return($this->Load($where));
  473. }
  474. // set a numeric array (using natural table field ordering) as object properties
  475. function Set(&$row)
  476. {
  477. global $ACTIVE_RECORD_SAFETY;
  478. $db = $this->DB();
  479. if (!$row) {
  480. $this->_saved = false;
  481. return false;
  482. }
  483. $this->_saved = true;
  484. $table = $this->TableInfo();
  485. if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds) != sizeof($row)) {
  486. # <AP>
  487. $bad_size = TRUE;
  488. if (sizeof($row) == 2 * sizeof($table->flds)) {
  489. // Only keep string keys
  490. $keys = array_filter(array_keys($row), 'is_string');
  491. if (sizeof($keys) == sizeof($table->flds))
  492. $bad_size = FALSE;
  493. }
  494. if ($bad_size) {
  495. $this->Error("Table structure of $this->_table has changed","Load");
  496. return false;
  497. }
  498. # </AP>
  499. }
  500. else
  501. $keys = array_keys($row);
  502. # <AP>
  503. reset($keys);
  504. $this->_original = array();
  505. foreach($table->flds as $name=>$fld) {
  506. $value = $row[current($keys)];
  507. $this->$name = $value;
  508. $this->_original[] = $value;
  509. next($keys);
  510. }
  511. # </AP>
  512. return true;
  513. }
  514. // get last inserted id for INSERT
  515. function LastInsertID(&$db,$fieldname)
  516. {
  517. if ($db->hasInsertID)
  518. $val = $db->Insert_ID($this->_table,$fieldname);
  519. else
  520. $val = false;
  521. if (is_null($val) || $val === false) {
  522. // this might not work reliably in multi-user environment
  523. return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
  524. }
  525. return $val;
  526. }
  527. // quote data in where clause
  528. function doquote(&$db, $val,$t)
  529. {
  530. switch($t) {
  531. case 'L':
  532. if (strpos($db->databaseType,'postgres') !== false) return $db->qstr($val);
  533. case 'D':
  534. case 'T':
  535. if (empty($val)) return 'null';
  536. case 'B':
  537. case 'N':
  538. case 'C':
  539. case 'X':
  540. if (is_null($val)) return 'null';
  541. if (strlen($val)>0 &&
  542. (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")) {
  543. return $db->qstr($val);
  544. break;
  545. }
  546. else {
  547. return "''";
  548. break;
  549. }
  550. default:
  551. return $val;
  552. break;
  553. }
  554. }
  555. // generate where clause for an UPDATE/SELECT
  556. function GenWhere(&$db, &$table)
  557. {
  558. $keys = $table->keys;
  559. $parr = array();
  560. foreach($keys as $k) {
  561. $f = $table->flds[$k];
  562. if ($f) {
  563. $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
  564. }
  565. }
  566. return implode(' and ', $parr);
  567. }
  568. function _QName($n,$db=false)
  569. {
  570. if (!ADODB_Active_Record::$_quoteNames) return $n;
  571. if (!$db) $db = $this->DB(); if (!$db) return false;
  572. return $db->nameQuote.$n.$db->nameQuote;
  573. }
  574. //------------------------------------------------------------ Public functions below
  575. function Load($where=null,$bindarr=false, $lock = false)
  576. {
  577. global $ADODB_FETCH_MODE;
  578. $db = $this->DB(); if (!$db) return false;
  579. $this->_where = $where;
  580. $save = $ADODB_FETCH_MODE;
  581. $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  582. if ($db->fetchMode !== false) $savem = $db->SetFetchMode(false);
  583. $qry = "select * from ".$this->_table;
  584. if($where) {
  585. $qry .= ' WHERE '.$where;
  586. }
  587. if ($lock) $qry .= $this->lockMode;
  588. $row = $db->GetRow($qry,$bindarr);
  589. if (isset($savem)) $db->SetFetchMode($savem);
  590. $ADODB_FETCH_MODE = $save;
  591. return $this->Set($row);
  592. }
  593. function LoadLocked($where=null, $bindarr=false)
  594. {
  595. $this->Load($where,$bindarr,true);
  596. }
  597. # useful for multiple record inserts
  598. # see http://phplens.com/lens/lensforum/msgs.php?id=17795
  599. function Reset()
  600. {
  601. $this->_where=null;
  602. $this->_saved = false;
  603. $this->_lasterr = false;
  604. $this->_original = false;
  605. $vars=get_object_vars($this);
  606. foreach($vars as $k=>$v){
  607. if(substr($k,0,1)!=='_'){
  608. $this->{$k}=null;
  609. }
  610. }
  611. $this->foreignName=strtolower(get_class($this));
  612. return true;
  613. }
  614. // false on error
  615. function Save()
  616. {
  617. if ($this->_saved) $ok = $this->Update();
  618. else $ok = $this->Insert();
  619. return $ok;
  620. }
  621. // false on error
  622. function Insert()
  623. {
  624. $db = $this->DB(); if (!$db) return false;
  625. $cnt = 0;
  626. $table = $this->TableInfo();
  627. $valarr = array();
  628. $names = array();
  629. $valstr = array();
  630. foreach($table->flds as $name=>$fld) {
  631. $val = $this->$name;
  632. if(!is_array($val) || !is_null($val) || !array_key_exists($name, $table->keys)) {
  633. $valarr[] = $val;
  634. $names[] = $this->_QName($name,$db);
  635. $valstr[] = $db->Param($cnt);
  636. $cnt += 1;
  637. }
  638. }
  639. if (empty($names)){
  640. foreach($table->flds as $name=>$fld) {
  641. $valarr[] = null;
  642. $names[] = $name;
  643. $valstr[] = $db->Param($cnt);
  644. $cnt += 1;
  645. }
  646. }
  647. $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
  648. $ok = $db->Execute($sql,$valarr);
  649. if ($ok) {
  650. $this->_saved = true;
  651. $autoinc = false;
  652. foreach($table->keys as $k) {
  653. if (is_null($this->$k)) {
  654. $autoinc = true;
  655. break;
  656. }
  657. }
  658. if ($autoinc && sizeof($table->keys) == 1) {
  659. $k = reset($table->keys);
  660. $this->$k = $this->LastInsertID($db,$k);
  661. }
  662. }
  663. $this->_original = $valarr;
  664. return !empty($ok);
  665. }
  666. function Delete()
  667. {
  668. $db = $this->DB(); if (!$db) return false;
  669. $table = $this->TableInfo();
  670. $where = $this->GenWhere($db,$table);
  671. $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
  672. $ok = $db->Execute($sql);
  673. return $ok ? true : false;
  674. }
  675. // returns an array of active record objects
  676. function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
  677. {
  678. $db = $this->DB(); if (!$db || empty($this->_table)) return false;
  679. $arr = $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr,$extra);
  680. return $arr;
  681. }
  682. // returns 0 on error, 1 on update, 2 on insert
  683. function Replace()
  684. {
  685. global $ADODB_ASSOC_CASE;
  686. $db = $this->DB(); if (!$db) return false;
  687. $table = $this->TableInfo();
  688. $pkey = $table->keys;
  689. foreach($table->flds as $name=>$fld) {
  690. $val = $this->$name;
  691. /*
  692. if (is_null($val)) {
  693. if (isset($fld->not_null) && $fld->not_null) {
  694. if (isset($fld->default_value) && strlen($fld->default_value)) continue;
  695. else {
  696. $this->Error("Cannot update null into $name","Replace");
  697. return false;
  698. }
  699. }
  700. }*/
  701. if (is_null($val) && !empty($fld->auto_increment)) {
  702. continue;
  703. }
  704. if (is_array($val)) continue;
  705. $t = $db->MetaType($fld->type);
  706. $arr[$name] = $this->doquote($db,$val,$t);
  707. $valarr[] = $val;
  708. }
  709. if (!is_array($pkey)) $pkey = array($pkey);
  710. if ($ADODB_ASSOC_CASE == 0)
  711. foreach($pkey as $k => $v)
  712. $pkey[$k] = strtolower($v);
  713. elseif ($ADODB_ASSOC_CASE == 1)
  714. foreach($pkey as $k => $v)
  715. $pkey[$k] = strtoupper($v);
  716. $ok = $db->Replace($this->_table,$arr,$pkey);
  717. if ($ok) {
  718. $this->_saved = true; // 1= update 2=insert
  719. if ($ok == 2) {
  720. $autoinc = false;
  721. foreach($table->keys as $k) {
  722. if (is_null($this->$k)) {
  723. $autoinc = true;
  724. break;
  725. }
  726. }
  727. if ($autoinc && sizeof($table->keys) == 1) {
  728. $k = reset($table->keys);
  729. $this->$k = $this->LastInsertID($db,$k);
  730. }
  731. }
  732. $this->_original = $valarr;
  733. }
  734. return $ok;
  735. }
  736. // returns 0 on error, 1 on update, -1 if no change in data (no update)
  737. function Update()
  738. {
  739. $db = $this->DB(); if (!$db) return false;
  740. $table = $this->TableInfo();
  741. $where = $this->GenWhere($db, $table);
  742. if (!$where) {
  743. $this->error("Where missing for table $table", "Update");
  744. return false;
  745. }
  746. $valarr = array();
  747. $neworig = array();
  748. $pairs = array();
  749. $i = -1;
  750. $cnt = 0;
  751. foreach($table->flds as $name=>$fld) {
  752. $i += 1;
  753. $val = $this->$name;
  754. $neworig[] = $val;
  755. if (isset($table->keys[$name]) || is_array($val))
  756. continue;
  757. if (is_null($val)) {
  758. if (isset($fld->not_null) && $fld->not_null) {
  759. if (isset($fld->default_value) && strlen($fld->default_value)) continue;
  760. else {
  761. $this->Error("Cannot set field $name to NULL","Update");
  762. return false;
  763. }
  764. }
  765. }
  766. if (isset($this->_original[$i]) && strcmp($val,$this->_original[$i]) == 0) continue;
  767. if (is_null($this->_original[$i]) && is_null($val)) continue;
  768. $valarr[] = $val;
  769. $pairs[] = $this->_QName($name,$db).'='.$db->Param($cnt);
  770. $cnt += 1;
  771. }
  772. if (!$cnt) return -1;
  773. $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
  774. $ok = $db->Execute($sql,$valarr);
  775. if ($ok) {
  776. $this->_original = $neworig;
  777. return 1;
  778. }
  779. return 0;
  780. }
  781. function GetAttributeNames()
  782. {
  783. $table = $this->TableInfo();
  784. if (!$table) return false;
  785. return array_keys($table->flds);
  786. }
  787. };
  788. function adodb_GetActiveRecordsClass(&$db, $class, $table,$whereOrderBy,$bindarr, $primkeyArr,
  789. $extra)
  790. {
  791. global $_ADODB_ACTIVE_DBS;
  792. $save = $db->SetFetchMode(ADODB_FETCH_NUM);
  793. $qry = "select * from ".$table;
  794. if (!empty($whereOrderBy))
  795. $qry .= ' WHERE '.$whereOrderBy;
  796. if(isset($extra['limit']))
  797. {
  798. $rows = false;
  799. if(isset($extra['offset'])) {
  800. $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset'],$bindarr);
  801. } else {
  802. $rs = $db->SelectLimit($qry, $extra['limit'],-1,$bindarr);
  803. }
  804. if ($rs) {
  805. while (!$rs->EOF) {
  806. $rows[] = $rs->fields;
  807. $rs->MoveNext();
  808. }
  809. }
  810. } else
  811. $rows = $db->GetAll($qry,$bindarr);
  812. $db->SetFetchMode($save);
  813. $false = false;
  814. if ($rows === false) {
  815. return $false;
  816. }
  817. if (!class_exists($class)) {
  818. $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
  819. return $false;
  820. }
  821. $arr = array();
  822. // arrRef will be the structure that knows about our objects.
  823. // It is an associative array.
  824. // We will, however, return arr, preserving regular 0.. order so that
  825. // obj[0] can be used by app developpers.
  826. $arrRef = array();
  827. $bTos = array(); // Will store belongTo's indices if any
  828. foreach($rows as $row) {
  829. $obj = new $class($table,$primkeyArr,$db);
  830. if ($obj->ErrorNo()){
  831. $db->_errorMsg = $obj->ErrorMsg();
  832. return $false;
  833. }
  834. $obj->Set($row);
  835. $arr[] = $obj;
  836. } // foreach($rows as $row)
  837. return $arr;
  838. }
  839. ?>