TYPO3 CMS  TYPO3_7-6
adodb-active-recordx.inc.php
Go to the documentation of this file.
1 <?php
2 /*
3 
4 @version v5.20.3 01-Jan-2016
5 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
6 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
7  Latest version is available at http://adodb.sourceforge.net
8 
9  Released under both BSD license and Lesser GPL library license.
10  Whenever there is any discrepancy between the two licenses,
11  the BSD license will take precedence.
12 
13  Active Record implementation. Superset of Zend Framework's.
14 
15  This is "Active Record eXtended" to support JOIN, WORK and LAZY mode by Chris Ravenscroft chris#voilaweb.com
16 
17  Version 0.9
18 
19  See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord
20  for info on Ruby on Rails Active Record implementation
21 */
22 
23 
24  // CFR: Active Records Definitions
25 define('ADODB_JOIN_AR', 0x01);
26 define('ADODB_WORK_AR', 0x02);
27 define('ADODB_LAZY_AR', 0x03);
28 
29 
31 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
32 global $ACTIVE_RECORD_SAFETY; // set to false to disable safety checks
33 global $ADODB_ACTIVE_DEFVALS; // use default values of table definition when creating new active record.
34 
35 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
36 $_ADODB_ACTIVE_DBS = array();
37 $ACTIVE_RECORD_SAFETY = true; // CFR: disabled while playing with relations
38 $ADODB_ACTIVE_DEFVALS = false;
39 
40 class ADODB_Active_DB {
41  var $db; // ADOConnection
42  var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
43 }
44 
45 class ADODB_Active_Table {
46  var $name; // table name
47  var $flds; // assoc array of adofieldobjs, indexed by fieldname
48  var $keys; // assoc array of primary keys, indexed by fieldname
49  var $_created; // only used when stored as a cached file
50  var $_belongsTo = array();
51  var $_hasMany = array();
52  var $_colsCount; // total columns count, including relations
53 
54  function updateColsCount()
55  {
56  $this->_colsCount = sizeof($this->flds);
57  foreach($this->_belongsTo as $foreignTable)
58  $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
59  foreach($this->_hasMany as $foreignTable)
60  $this->_colsCount += sizeof($foreignTable->TableInfo()->flds);
61  }
62 }
63 
64 // returns index into $_ADODB_ACTIVE_DBS
66 {
67  global $_ADODB_ACTIVE_DBS;
68 
69  foreach($_ADODB_ACTIVE_DBS as $k => $d) {
70  if (PHP_VERSION >= 5) {
71  if ($d->db === $db) {
72  return $k;
73  }
74  } else {
75  if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database) {
76  return $k;
77  }
78  }
79  }
80 
81  $obj = new ADODB_Active_DB();
82  $obj->db = $db;
83  $obj->tables = array();
84 
85  $_ADODB_ACTIVE_DBS[] = $obj;
86 
87  return sizeof($_ADODB_ACTIVE_DBS)-1;
88 }
89 
90 
91 class ADODB_Active_Record {
92  static $_changeNames = true; // dynamically pluralize table names
93  static $_foreignSuffix = '_id'; //
94  var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
95  var $_table; // tablename, if set in class definition then use it as table name
96  var $_sTable; // singularized table name
97  var $_pTable; // pluralized table name
98  var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
99  var $_where; // where clause set in Load()
100  var $_saved = false; // indicates whether data is already inserted.
101  var $_lasterr = false; // last error message
102  var $_original = false; // the original values loaded or inserted, refreshed on update
103 
104  var $foreignName; // CFR: class name when in a relationship
105 
106  static function UseDefaultValues($bool=null)
107  {
108  global $ADODB_ACTIVE_DEFVALS;
109  if (isset($bool)) {
110  $ADODB_ACTIVE_DEFVALS = $bool;
111  }
112  return $ADODB_ACTIVE_DEFVALS;
113  }
114 
115  // should be static
116  static function SetDatabaseAdapter(&$db)
117  {
119  }
120 
121 
122  public function __set($name, $value)
123  {
124  $name = str_replace(' ', '_', $name);
125  $this->$name = $value;
126  }
127 
128  // php5 constructor
129  // Note: if $table is defined, then we will use it as our table name
130  // Otherwise we will use our classname...
131  // In our database, table names are pluralized (because there can be
132  // more than one row!)
133  // Similarly, if $table is defined here, it has to be plural form.
134  //
135  // $options is an array that allows us to tweak the constructor's behaviour
136  // if $options['refresh'] is true, we re-scan our metadata information
137  // if $options['new'] is true, we forget all relations
138  function __construct($table = false, $pkeyarr=false, $db=false, $options=array())
139  {
140  global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
141 
142  if ($db == false && is_object($pkeyarr)) {
143  $db = $pkeyarr;
144  $pkeyarr = false;
145  }
146 
147  if($table) {
148  // table argument exists. It is expected to be
149  // already plural form.
150  $this->_pTable = $table;
151  $this->_sTable = $this->_singularize($this->_pTable);
152  }
153  else {
154  // We will use current classname as table name.
155  // We need to pluralize it for the real table name.
156  $this->_sTable = strtolower(get_class($this));
157  $this->_pTable = $this->_pluralize($this->_sTable);
158  }
159  $this->_table = &$this->_pTable;
160 
161  $this->foreignName = $this->_sTable; // CFR: default foreign name (singular)
162 
163  if ($db) {
165  } else
166  $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
167 
168 
169  if ($this->_dbat < 0) {
170  $this->Error(
171  "No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",
172  'ADODB_Active_Record::__constructor'
173  );
174  }
175 
176  $this->_tableat = $this->_table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
177 
178  // CFR: Just added this option because UpdateActiveTable() can refresh its information
179  // but there was no way to ask it to do that.
180  $forceUpdate = (isset($options['refresh']) && true === $options['refresh']);
181  $this->UpdateActiveTable($pkeyarr, $forceUpdate);
182  if(isset($options['new']) && true === $options['new']) {
183  $table =& $this->TableInfo();
184  unset($table->_hasMany);
185  unset($table->_belongsTo);
186  $table->_hasMany = array();
187  $table->_belongsTo = array();
188  }
189  }
190 
191  function __wakeup()
192  {
193  $class = get_class($this);
194  new $class;
195  }
196 
197  // CFR: Constants found in Rails
198  static $IrregularP = array(
199  'PERSON' => 'people',
200  'MAN' => 'men',
201  'WOMAN' => 'women',
202  'CHILD' => 'children',
203  'COW' => 'kine',
204  );
205 
206  static $IrregularS = array(
207  'PEOPLE' => 'PERSON',
208  'MEN' => 'man',
209  'WOMEN' => 'woman',
210  'CHILDREN' => 'child',
211  'KINE' => 'cow',
212  );
213 
214  static $WeIsI = array(
215  'EQUIPMENT' => true,
216  'INFORMATION' => true,
217  'RICE' => true,
218  'MONEY' => true,
219  'SPECIES' => true,
220  'SERIES' => true,
221  'FISH' => true,
222  'SHEEP' => true,
223  );
224 
225  function _pluralize($table)
226  {
228  return $table;
229  }
230  $ut = strtoupper($table);
231  if(isset(self::$WeIsI[$ut])) {
232  return $table;
233  }
234  if(isset(self::$IrregularP[$ut])) {
235  return self::$IrregularP[$ut];
236  }
237  $len = strlen($table);
238  $lastc = $ut[$len-1];
239  $lastc2 = substr($ut,$len-2);
240  switch ($lastc) {
241  case 'S':
242  return $table.'es';
243  case 'Y':
244  return substr($table,0,$len-1).'ies';
245  case 'X':
246  return $table.'es';
247  case 'H':
248  if ($lastc2 == 'CH' || $lastc2 == 'SH') {
249  return $table.'es';
250  }
251  default:
252  return $table.'s';
253  }
254  }
255 
256  // CFR Lamest singular inflector ever - @todo Make it real!
257  // Note: There is an assumption here...and it is that the argument's length >= 4
258  function _singularize($table)
259  {
260 
262  return $table;
263  }
264  $ut = strtoupper($table);
265  if(isset(self::$WeIsI[$ut])) {
266  return $table;
267  }
268  if(isset(self::$IrregularS[$ut])) {
269  return self::$IrregularS[$ut];
270  }
271  $len = strlen($table);
272  if($ut[$len-1] != 'S') {
273  return $table; // I know...forget oxen
274  }
275  if($ut[$len-2] != 'E') {
276  return substr($table, 0, $len-1);
277  }
278  switch($ut[$len-3]) {
279  case 'S':
280  case 'X':
281  return substr($table, 0, $len-2);
282  case 'I':
283  return substr($table, 0, $len-3) . 'y';
284  case 'H';
285  if($ut[$len-4] == 'C' || $ut[$len-4] == 'S') {
286  return substr($table, 0, $len-2);
287  }
288  default:
289  return substr($table, 0, $len-1); // ?
290  }
291  }
292 
293  /*
294  * ar->foreignName will contain the name of the tables associated with this table because
295  * these other tables' rows may also be referenced by this table using theirname_id or the provided
296  * foreign keys (this index name is stored in ar->foreignKey)
297  *
298  * this-table.id = other-table-#1.this-table_id
299  * = other-table-#2.this-table_id
300  */
301  function hasMany($foreignRef,$foreignKey=false)
302  {
303  $ar = new ADODB_Active_Record($foreignRef);
304  $ar->foreignName = $foreignRef;
305  $ar->UpdateActiveTable();
306  $ar->foreignKey = ($foreignKey) ? $foreignKey : strtolower(get_class($this)) . self::$_foreignSuffix;
307 
308  $table =& $this->TableInfo();
309  if(!isset($table->_hasMany[$foreignRef])) {
310  $table->_hasMany[$foreignRef] = $ar;
311  $table->updateColsCount();
312  }
313 # @todo Can I make this guy be lazy?
314  $this->$foreignRef = $table->_hasMany[$foreignRef]; // WATCHME Removed assignment by ref. to please __get()
315  }
316 
324  function belongsTo($foreignRef,$foreignKey=false)
325  {
326  global $inflector;
327 
328  $ar = new ADODB_Active_Record($this->_pluralize($foreignRef));
329  $ar->foreignName = $foreignRef;
330  $ar->UpdateActiveTable();
331  $ar->foreignKey = ($foreignKey) ? $foreignKey : $ar->foreignName . self::$_foreignSuffix;
332 
333  $table =& $this->TableInfo();
334  if(!isset($table->_belongsTo[$foreignRef])) {
335  $table->_belongsTo[$foreignRef] = $ar;
336  $table->updateColsCount();
337  }
338  $this->$foreignRef = $table->_belongsTo[$foreignRef];
339  }
340 
348  function __get($name)
349  {
350  return $this->LoadRelations($name, '', -1. -1);
351  }
352 
353  function LoadRelations($name, $whereOrderBy, $offset=-1, $limit=-1)
354  {
355  $extras = array();
356  if($offset >= 0) {
357  $extras['offset'] = $offset;
358  }
359  if($limit >= 0) {
360  $extras['limit'] = $limit;
361  }
362  $table =& $this->TableInfo();
363 
364  if (strlen($whereOrderBy)) {
365  if (!preg_match('/^[ \n\r]*AND/i',$whereOrderBy)) {
366  if (!preg_match('/^[ \n\r]*ORDER[ \n\r]/i',$whereOrderBy)) {
367  $whereOrderBy = 'AND '.$whereOrderBy;
368  }
369  }
370  }
371 
372  if(!empty($table->_belongsTo[$name])) {
373  $obj = $table->_belongsTo[$name];
374  $columnName = $obj->foreignKey;
375  if(empty($this->$columnName)) {
376  $this->$name = null;
377  }
378  else {
379  if(($k = reset($obj->TableInfo()->keys))) {
380  $belongsToId = $k;
381  }
382  else {
383  $belongsToId = 'id';
384  }
385 
386  $arrayOfOne =
387  $obj->Find(
388  $belongsToId.'='.$this->$columnName.' '.$whereOrderBy, false, false, $extras);
389  $this->$name = $arrayOfOne[0];
390  }
391  return $this->$name;
392  }
393  if(!empty($table->_hasMany[$name])) {
394  $obj = $table->_hasMany[$name];
395  if(($k = reset($table->keys))) {
396  $hasManyId = $k;
397  }
398  else {
399  $hasManyId = 'id';
400  }
401 
402  $this->$name =
403  $obj->Find(
404  $obj->foreignKey.'='.$this->$hasManyId.' '.$whereOrderBy, false, false, $extras);
405  return $this->$name;
406  }
407  }
409 
410  // update metadata
411  function UpdateActiveTable($pkeys=false,$forceUpdate=false)
412  {
413  global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
414  global $ADODB_ACTIVE_DEFVALS, $ADODB_FETCH_MODE;
415 
416  $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
417 
418  $table = $this->_table;
419  $tables = $activedb->tables;
420  $tableat = $this->_tableat;
421  if (!$forceUpdate && !empty($tables[$tableat])) {
422 
423  $tobj = $tables[$tableat];
424  foreach($tobj->flds as $name => $fld) {
425  if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) {
426  $this->$name = $fld->default_value;
427  }
428  else {
429  $this->$name = null;
430  }
431  }
432  return;
433  }
434 
435  $db = $activedb->db;
436  $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
437  if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
438  $fp = fopen($fname,'r');
439  @flock($fp, LOCK_SH);
440  $acttab = unserialize(fread($fp,100000));
441  fclose($fp);
442  if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) {
443  // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
444  // ideally, you should cache at least 32 secs
445  $activedb->tables[$table] = $acttab;
446 
447  //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
448  return;
449  } else if ($db->debug) {
450  ADOConnection::outp("Refreshing cached active record file: $fname");
451  }
452  }
453  $activetab = new ADODB_Active_Table();
454  $activetab->name = $table;
455 
456  $save = $ADODB_FETCH_MODE;
457  $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
458  if ($db->fetchMode !== false) {
459  $savem = $db->SetFetchMode(false);
460  }
461 
462  $cols = $db->MetaColumns($table);
463 
464  if (isset($savem)) {
465  $db->SetFetchMode($savem);
466  }
467  $ADODB_FETCH_MODE = $save;
468 
469  if (!$cols) {
470  $this->Error("Invalid table name: $table",'UpdateActiveTable');
471  return false;
472  }
473  $fld = reset($cols);
474  if (!$pkeys) {
475  if (isset($fld->primary_key)) {
476  $pkeys = array();
477  foreach($cols as $name => $fld) {
478  if (!empty($fld->primary_key)) {
479  $pkeys[] = $name;
480  }
481  }
482  } else {
483  $pkeys = $this->GetPrimaryKeys($db, $table);
484  }
485  }
486  if (empty($pkeys)) {
487  $this->Error("No primary key found for table $table",'UpdateActiveTable');
488  return false;
489  }
490 
491  $attr = array();
492  $keys = array();
493 
494  switch($ADODB_ASSOC_CASE) {
495  case 0:
496  foreach($cols as $name => $fldobj) {
497  $name = strtolower($name);
498  if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
499  $this->$name = $fldobj->default_value;
500  }
501  else {
502  $this->$name = null;
503  }
504  $attr[$name] = $fldobj;
505  }
506  foreach($pkeys as $k => $name) {
507  $keys[strtolower($name)] = strtolower($name);
508  }
509  break;
510 
511  case 1:
512  foreach($cols as $name => $fldobj) {
513  $name = strtoupper($name);
514 
515  if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
516  $this->$name = $fldobj->default_value;
517  }
518  else {
519  $this->$name = null;
520  }
521  $attr[$name] = $fldobj;
522  }
523 
524  foreach($pkeys as $k => $name) {
525  $keys[strtoupper($name)] = strtoupper($name);
526  }
527  break;
528  default:
529  foreach($cols as $name => $fldobj) {
530  $name = ($fldobj->name);
531 
532  if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value)) {
533  $this->$name = $fldobj->default_value;
534  }
535  else {
536  $this->$name = null;
537  }
538  $attr[$name] = $fldobj;
539  }
540  foreach($pkeys as $k => $name) {
541  $keys[$name] = $cols[$name]->name;
542  }
543  break;
544  }
545 
546  $activetab->keys = $keys;
547  $activetab->flds = $attr;
548  $activetab->updateColsCount();
549 
550  if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
551  $activetab->_created = time();
552  $s = serialize($activetab);
553  if (!function_exists('adodb_write_file')) {
554  include(ADODB_DIR.'/adodb-csvlib.inc.php');
555  }
556  adodb_write_file($fname,$s);
557  }
558  if (isset($activedb->tables[$table])) {
559  $oldtab = $activedb->tables[$table];
560 
561  if ($oldtab) {
562  $activetab->_belongsTo = $oldtab->_belongsTo;
563  $activetab->_hasMany = $oldtab->_hasMany;
564  }
565  }
566  $activedb->tables[$table] = $activetab;
567  }
568 
569  function GetPrimaryKeys(&$db, $table)
570  {
571  return $db->MetaPrimaryKeys($table);
572  }
573 
574  // error handler for both PHP4+5.
575  function Error($err,$fn)
576  {
577  global $_ADODB_ACTIVE_DBS;
578 
579  $fn = get_class($this).'::'.$fn;
580  $this->_lasterr = $fn.': '.$err;
581 
582  if ($this->_dbat < 0) {
583  $db = false;
584  }
585  else {
586  $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
587  $db = $activedb->db;
588  }
589 
590  if (function_exists('adodb_throw')) {
591  if (!$db) {
592  adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
593  }
594  else {
595  adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
596  }
597  } else {
598  if (!$db || $db->debug) {
599  ADOConnection::outp($this->_lasterr);
600  }
601  }
602 
603  }
604 
605  // return last error message
606  function ErrorMsg()
607  {
608  if (!function_exists('adodb_throw')) {
609  if ($this->_dbat < 0) {
610  $db = false;
611  }
612  else {
613  $db = $this->DB();
614  }
615 
616  // last error could be database error too
617  if ($db && $db->ErrorMsg()) {
618  return $db->ErrorMsg();
619  }
620  }
621  return $this->_lasterr;
622  }
623 
624  function ErrorNo()
625  {
626  if ($this->_dbat < 0) {
627  return -9999; // no database connection...
628  }
629  $db = $this->DB();
630 
631  return (int) $db->ErrorNo();
632  }
633 
634 
635  // retrieve ADOConnection from _ADODB_Active_DBs
636  function DB()
637  {
638  global $_ADODB_ACTIVE_DBS;
639 
640  if ($this->_dbat < 0) {
641  $false = false;
642  $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
643  return $false;
644  }
645  $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
646  $db = $activedb->db;
647  return $db;
648  }
649 
650  // retrieve ADODB_Active_Table
651  function &TableInfo()
652  {
653  global $_ADODB_ACTIVE_DBS;
654 
655  $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
656  $table = $activedb->tables[$this->_tableat];
657  return $table;
658  }
659 
660 
661  // I have an ON INSERT trigger on a table that sets other columns in the table.
662  // So, I find that for myTable, I want to reload an active record after saving it. -- Malcolm Cook
663  function Reload()
664  {
665  $db =& $this->DB();
666  if (!$db) {
667  return false;
668  }
669  $table =& $this->TableInfo();
670  $where = $this->GenWhere($db, $table);
671  return($this->Load($where));
672  }
673 
674 
675  // set a numeric array (using natural table field ordering) as object properties
676  function Set(&$row)
677  {
678  global $ACTIVE_RECORD_SAFETY;
679 
680  $db = $this->DB();
681 
682  if (!$row) {
683  $this->_saved = false;
684  return false;
685  }
686 
687  $this->_saved = true;
688 
689  $table = $this->TableInfo();
690  $sizeofFlds = sizeof($table->flds);
691  $sizeofRow = sizeof($row);
692  if ($ACTIVE_RECORD_SAFETY && $table->_colsCount != $sizeofRow && $sizeofFlds != $sizeofRow) {
693  # <AP>
694  $bad_size = TRUE;
695  if($sizeofRow == 2 * $table->_colsCount || $sizeofRow == 2 * $sizeofFlds) {
696  // Only keep string keys
697  $keys = array_filter(array_keys($row), 'is_string');
698  if (sizeof($keys) == sizeof($table->flds)) {
699  $bad_size = FALSE;
700  }
701  }
702  if ($bad_size) {
703  $this->Error("Table structure of $this->_table has changed","Load");
704  return false;
705  }
706  # </AP>
707  }
708  else {
709  $keys = array_keys($row);
710  }
711 
712  # <AP>
713  reset($keys);
714  $this->_original = array();
715  foreach($table->flds as $name=>$fld) {
716  $value = $row[current($keys)];
717  $this->$name = $value;
718  $this->_original[] = $value;
719  if(!next($keys)) {
720  break;
721  }
722  }
723  $table =& $this->TableInfo();
724  foreach($table->_belongsTo as $foreignTable) {
725  $ft = $foreignTable->TableInfo();
726  $propertyName = $ft->name;
727  foreach($ft->flds as $name=>$fld) {
728  $value = $row[current($keys)];
729  $foreignTable->$name = $value;
730  $foreignTable->_original[] = $value;
731  if(!next($keys)) {
732  break;
733  }
734  }
735  }
736  foreach($table->_hasMany as $foreignTable) {
737  $ft = $foreignTable->TableInfo();
738  foreach($ft->flds as $name=>$fld) {
739  $value = $row[current($keys)];
740  $foreignTable->$name = $value;
741  $foreignTable->_original[] = $value;
742  if(!next($keys)) {
743  break;
744  }
745  }
746  }
747  # </AP>
748 
749  return true;
750  }
751 
752  // get last inserted id for INSERT
753  function LastInsertID(&$db,$fieldname)
754  {
755  if ($db->hasInsertID) {
756  $val = $db->Insert_ID($this->_table,$fieldname);
757  }
758  else {
759  $val = false;
760  }
761 
762  if (is_null($val) || $val === false) {
763  // this might not work reliably in multi-user environment
764  return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
765  }
766  return $val;
767  }
768 
769  // quote data in where clause
770  function doquote(&$db, $val,$t)
771  {
772  switch($t) {
773  case 'D':
774  case 'T':
775  if (empty($val)) {
776  return 'null';
777  }
778  case 'C':
779  case 'X':
780  if (is_null($val)) {
781  return 'null';
782  }
783  if (strlen($val)>0 &&
784  (strncmp($val,"'",1) != 0 || substr($val,strlen($val)-1,1) != "'")
785  ) {
786  return $db->qstr($val);
787  break;
788  }
789  default:
790  return $val;
791  break;
792  }
793  }
794 
795  // generate where clause for an UPDATE/SELECT
796  function GenWhere(&$db, &$table)
797  {
798  $keys = $table->keys;
799  $parr = array();
800 
801  foreach($keys as $k) {
802  $f = $table->flds[$k];
803  if ($f) {
804  $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
805  }
806  }
807  return implode(' and ', $parr);
808  }
809 
810 
811  //------------------------------------------------------------ Public functions below
812 
813  function Load($where=null,$bindarr=false)
814  {
815  $db = $this->DB();
816  if (!$db) {
817  return false;
818  }
819  $this->_where = $where;
820 
821  $save = $db->SetFetchMode(ADODB_FETCH_NUM);
822  $qry = "select * from ".$this->_table;
823  $table =& $this->TableInfo();
824 
825  if(($k = reset($table->keys))) {
826  $hasManyId = $k;
827  }
828  else {
829  $hasManyId = 'id';
830  }
831 
832  foreach($table->_belongsTo as $foreignTable) {
833  if(($k = reset($foreignTable->TableInfo()->keys))) {
834  $belongsToId = $k;
835  }
836  else {
837  $belongsToId = 'id';
838  }
839  $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
840  $this->_table.'.'.$foreignTable->foreignKey.'='.
841  $foreignTable->_table.'.'.$belongsToId;
842  }
843  foreach($table->_hasMany as $foreignTable)
844  {
845  $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
846  $this->_table.'.'.$hasManyId.'='.
847  $foreignTable->_table.'.'.$foreignTable->foreignKey;
848  }
849  if($where) {
850  $qry .= ' WHERE '.$where;
851  }
852 
853  // Simple case: no relations. Load row and return.
854  if((count($table->_hasMany) + count($table->_belongsTo)) < 1) {
855  $row = $db->GetRow($qry,$bindarr);
856  if(!$row) {
857  return false;
858  }
859  $db->SetFetchMode($save);
860  return $this->Set($row);
861  }
862 
863  // More complex case when relations have to be collated
864  $rows = $db->GetAll($qry,$bindarr);
865  if(!$rows) {
866  return false;
867  }
868  $db->SetFetchMode($save);
869  if(count($rows) < 1) {
870  return false;
871  }
872  $class = get_class($this);
873  $isFirstRow = true;
874 
875  if(($k = reset($this->TableInfo()->keys))) {
876  $myId = $k;
877  }
878  else {
879  $myId = 'id';
880  }
881  $index = 0; $found = false;
884  foreach($this->TableInfo()->flds as $fld) {
885  if($fld->name == $myId) {
886  $found = true;
887  break;
888  }
889  $index++;
890  }
891  if(!$found) {
892  $this->outp_throw("Unable to locate key $myId for $class in Load()",'Load');
893  }
894 
895  foreach($rows as $row) {
896  $rowId = intval($row[$index]);
897  if($rowId > 0) {
898  if($isFirstRow) {
899  $isFirstRow = false;
900  if(!$this->Set($row)) {
901  return false;
902  }
903  }
904  $obj = new $class($table,false,$db);
905  $obj->Set($row);
906  // TODO Copy/paste code below: bad!
907  if(count($table->_hasMany) > 0) {
908  foreach($table->_hasMany as $foreignTable) {
909  $foreignName = $foreignTable->foreignName;
910  if(!empty($obj->$foreignName)) {
911  if(!is_array($this->$foreignName)) {
912  $foreignObj = $this->$foreignName;
913  $this->$foreignName = array(clone($foreignObj));
914  }
915  else {
916  $foreignObj = $obj->$foreignName;
917  array_push($this->$foreignName, clone($foreignObj));
918  }
919  }
920  }
921  }
922  if(count($table->_belongsTo) > 0) {
923  foreach($table->_belongsTo as $foreignTable) {
924  $foreignName = $foreignTable->foreignName;
925  if(!empty($obj->$foreignName)) {
926  if(!is_array($this->$foreignName)) {
927  $foreignObj = $this->$foreignName;
928  $this->$foreignName = array(clone($foreignObj));
929  }
930  else {
931  $foreignObj = $obj->$foreignName;
932  array_push($this->$foreignName, clone($foreignObj));
933  }
934  }
935  }
936  }
937  }
938  }
939  return true;
940  }
941 
942  // false on error
943  function Save()
944  {
945  if ($this->_saved) {
946  $ok = $this->Update();
947  }
948  else {
949  $ok = $this->Insert();
950  }
951 
952  return $ok;
953  }
954 
955  // CFR: Sometimes we may wish to consider that an object is not to be replaced but inserted.
956  // Sample use case: an 'undo' command object (after a delete())
957  function Dirty()
958  {
959  $this->_saved = false;
960  }
961 
962  // false on error
963  function Insert()
964  {
965  $db = $this->DB();
966  if (!$db) {
967  return false;
968  }
969  $cnt = 0;
970  $table = $this->TableInfo();
971 
972  $valarr = array();
973  $names = array();
974  $valstr = array();
975 
976  foreach($table->flds as $name=>$fld) {
977  $val = $this->$name;
978  if(!is_null($val) || !array_key_exists($name, $table->keys)) {
979  $valarr[] = $val;
980  $names[] = $name;
981  $valstr[] = $db->Param($cnt);
982  $cnt += 1;
983  }
984  }
985 
986  if (empty($names)){
987  foreach($table->flds as $name=>$fld) {
988  $valarr[] = null;
989  $names[] = $name;
990  $valstr[] = $db->Param($cnt);
991  $cnt += 1;
992  }
993  }
994  $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
995  $ok = $db->Execute($sql,$valarr);
996 
997  if ($ok) {
998  $this->_saved = true;
999  $autoinc = false;
1000  foreach($table->keys as $k) {
1001  if (is_null($this->$k)) {
1002  $autoinc = true;
1003  break;
1004  }
1005  }
1006  if ($autoinc && sizeof($table->keys) == 1) {
1007  $k = reset($table->keys);
1008  $this->$k = $this->LastInsertID($db,$k);
1009  }
1010  }
1011 
1012  $this->_original = $valarr;
1013  return !empty($ok);
1014  }
1015 
1016  function Delete()
1017  {
1018  $db = $this->DB();
1019  if (!$db) {
1020  return false;
1021  }
1022  $table = $this->TableInfo();
1023 
1024  $where = $this->GenWhere($db,$table);
1025  $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
1026  $ok = $db->Execute($sql);
1027 
1028  return $ok ? true : false;
1029  }
1030 
1031  // returns an array of active record objects
1032  function Find($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
1033  {
1034  $db = $this->DB();
1035  if (!$db || empty($this->_table)) {
1036  return false;
1037  }
1038  $table =& $this->TableInfo();
1039  $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
1040  array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
1041  return $arr;
1042  }
1043 
1044  // CFR: In introduced this method to ensure that inner workings are not disturbed by
1045  // subclasses...for instance when GetActiveRecordsClass invokes Find()
1046  // Why am I not invoking parent::Find?
1047  // Shockingly because I want to preserve PHP4 compatibility.
1048  function packageFind($whereOrderBy,$bindarr=false,$pkeysArr=false,$extra=array())
1049  {
1050  $db = $this->DB();
1051  if (!$db || empty($this->_table)) {
1052  return false;
1053  }
1054  $table =& $this->TableInfo();
1055  $arr = $db->GetActiveRecordsClass(get_class($this),$this, $whereOrderBy,$bindarr,$pkeysArr,$extra,
1056  array('foreignName'=>$this->foreignName, 'belongsTo'=>$table->_belongsTo, 'hasMany'=>$table->_hasMany));
1057  return $arr;
1058  }
1059 
1060  // returns 0 on error, 1 on update, 2 on insert
1061  function Replace()
1062  {
1063  global $ADODB_ASSOC_CASE;
1064 
1065  $db = $this->DB();
1066  if (!$db) {
1067  return false;
1068  }
1069  $table = $this->TableInfo();
1070 
1071  $pkey = $table->keys;
1072 
1073  foreach($table->flds as $name=>$fld) {
1074  $val = $this->$name;
1075  /*
1076  if (is_null($val)) {
1077  if (isset($fld->not_null) && $fld->not_null) {
1078  if (isset($fld->default_value) && strlen($fld->default_value)) {
1079  continue;
1080  }
1081  else {
1082  $this->Error("Cannot update null into $name","Replace");
1083  return false;
1084  }
1085  }
1086  }*/
1087  if (is_null($val) && !empty($fld->auto_increment)) {
1088  continue;
1089  }
1090  $t = $db->MetaType($fld->type);
1091  $arr[$name] = $this->doquote($db,$val,$t);
1092  $valarr[] = $val;
1093  }
1094 
1095  if (!is_array($pkey)) {
1096  $pkey = array($pkey);
1097  }
1098 
1099 
1100  switch ($ADODB_ASSOC_CASE == 0) {
1101  case ADODB_ASSOC_CASE_LOWER:
1102  foreach($pkey as $k => $v) {
1103  $pkey[$k] = strtolower($v);
1104  }
1105  break;
1106  case ADODB_ASSOC_CASE_UPPER:
1107  foreach($pkey as $k => $v) {
1108  $pkey[$k] = strtoupper($v);
1109  }
1110  break;
1111  }
1112 
1113  $ok = $db->Replace($this->_table,$arr,$pkey);
1114  if ($ok) {
1115  $this->_saved = true; // 1= update 2=insert
1116  if ($ok == 2) {
1117  $autoinc = false;
1118  foreach($table->keys as $k) {
1119  if (is_null($this->$k)) {
1120  $autoinc = true;
1121  break;
1122  }
1123  }
1124  if ($autoinc && sizeof($table->keys) == 1) {
1125  $k = reset($table->keys);
1126  $this->$k = $this->LastInsertID($db,$k);
1127  }
1128  }
1129 
1130  $this->_original = $valarr;
1131  }
1132  return $ok;
1133  }
1134 
1135  // returns 0 on error, 1 on update, -1 if no change in data (no update)
1136  function Update()
1137  {
1138  $db = $this->DB();
1139  if (!$db) {
1140  return false;
1141  }
1142  $table = $this->TableInfo();
1143 
1144  $where = $this->GenWhere($db, $table);
1145 
1146  if (!$where) {
1147  $this->error("Where missing for table $table", "Update");
1148  return false;
1149  }
1150  $valarr = array();
1151  $neworig = array();
1152  $pairs = array();
1153  $i = -1;
1154  $cnt = 0;
1155  foreach($table->flds as $name=>$fld) {
1156  $i += 1;
1157  $val = $this->$name;
1158  $neworig[] = $val;
1159 
1160  if (isset($table->keys[$name])) {
1161  continue;
1162  }
1163 
1164  if (is_null($val)) {
1165  if (isset($fld->not_null) && $fld->not_null) {
1166  if (isset($fld->default_value) && strlen($fld->default_value)) {
1167  continue;
1168  }
1169  else {
1170  $this->Error("Cannot set field $name to NULL","Update");
1171  return false;
1172  }
1173  }
1174  }
1175 
1176  if (isset($this->_original[$i]) && $val === $this->_original[$i]) {
1177  continue;
1178  }
1179  $valarr[] = $val;
1180  $pairs[] = $name.'='.$db->Param($cnt);
1181  $cnt += 1;
1182  }
1183 
1184 
1185  if (!$cnt) {
1186  return -1;
1187  }
1188  $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
1189  $ok = $db->Execute($sql,$valarr);
1190  if ($ok) {
1191  $this->_original = $neworig;
1192  return 1;
1193  }
1194  return 0;
1195  }
1196 
1198  {
1199  $table = $this->TableInfo();
1200  if (!$table) {
1201  return false;
1202  }
1203  return array_keys($table->flds);
1204  }
1205 
1206 };
1207 
1208 function adodb_GetActiveRecordsClass(&$db, $class, $tableObj,$whereOrderBy,$bindarr, $primkeyArr,
1209  $extra, $relations)
1210 {
1211  global $_ADODB_ACTIVE_DBS;
1212 
1213  if (empty($extra['loading'])) {
1214  $extra['loading'] = ADODB_LAZY_AR;
1215  }
1216  $save = $db->SetFetchMode(ADODB_FETCH_NUM);
1217  $table = &$tableObj->_table;
1218  $tableInfo =& $tableObj->TableInfo();
1219  if(($k = reset($tableInfo->keys))) {
1220  $myId = $k;
1221  }
1222  else {
1223  $myId = 'id';
1224  }
1225  $index = 0; $found = false;
1228  foreach($tableInfo->flds as $fld)
1229  {
1230  if($fld->name == $myId) {
1231  $found = true;
1232  break;
1233  }
1234  $index++;
1235  }
1236  if(!$found) {
1237  $db->outp_throw("Unable to locate key $myId for $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
1238  }
1239 
1240  $qry = "select * from ".$table;
1241  if(ADODB_JOIN_AR == $extra['loading']) {
1242  if(!empty($relations['belongsTo'])) {
1243  foreach($relations['belongsTo'] as $foreignTable) {
1244  if(($k = reset($foreignTable->TableInfo()->keys))) {
1245  $belongsToId = $k;
1246  }
1247  else {
1248  $belongsToId = 'id';
1249  }
1250 
1251  $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
1252  $table.'.'.$foreignTable->foreignKey.'='.
1253  $foreignTable->_table.'.'.$belongsToId;
1254  }
1255  }
1256  if(!empty($relations['hasMany'])) {
1257  if(empty($relations['foreignName'])) {
1258  $db->outp_throw("Missing foreignName is relation specification in GetActiveRecordsClass()",'GetActiveRecordsClass');
1259  }
1260  if(($k = reset($tableInfo->keys))) {
1261  $hasManyId = $k;
1262  }
1263  else {
1264  $hasManyId = 'id';
1265  }
1266 
1267  foreach($relations['hasMany'] as $foreignTable) {
1268  $qry .= ' LEFT JOIN '.$foreignTable->_table.' ON '.
1269  $table.'.'.$hasManyId.'='.
1270  $foreignTable->_table.'.'.$foreignTable->foreignKey;
1271  }
1272  }
1273  }
1274  if (!empty($whereOrderBy)) {
1275  $qry .= ' WHERE '.$whereOrderBy;
1276  }
1277  if(isset($extra['limit'])) {
1278  $rows = false;
1279  if(isset($extra['offset'])) {
1280  $rs = $db->SelectLimit($qry, $extra['limit'], $extra['offset']);
1281  } else {
1282  $rs = $db->SelectLimit($qry, $extra['limit']);
1283  }
1284  if ($rs) {
1285  while (!$rs->EOF) {
1286  $rows[] = $rs->fields;
1287  $rs->MoveNext();
1288  }
1289  }
1290  } else
1291  $rows = $db->GetAll($qry,$bindarr);
1292 
1293  $db->SetFetchMode($save);
1294 
1295  $false = false;
1296 
1297  if ($rows === false) {
1298  return $false;
1299  }
1300 
1301 
1302  if (!isset($_ADODB_ACTIVE_DBS)) {
1303  include(ADODB_DIR.'/adodb-active-record.inc.php');
1304  }
1305  if (!class_exists($class)) {
1306  $db->outp_throw("Unknown class $class in GetActiveRecordsClass()",'GetActiveRecordsClass');
1307  return $false;
1308  }
1309  $uniqArr = array(); // CFR Keep track of records for relations
1310  $arr = array();
1311  // arrRef will be the structure that knows about our objects.
1312  // It is an associative array.
1313  // We will, however, return arr, preserving regular 0.. order so that
1314  // obj[0] can be used by app developpers.
1315  $arrRef = array();
1316  $bTos = array(); // Will store belongTo's indices if any
1317  foreach($rows as $row) {
1318 
1319  $obj = new $class($table,$primkeyArr,$db);
1320  if ($obj->ErrorNo()){
1321  $db->_errorMsg = $obj->ErrorMsg();
1322  return $false;
1323  }
1324  $obj->Set($row);
1325  // CFR: FIXME: Insane assumption here:
1326  // If the first column returned is an integer, then it's a 'id' field
1327  // And to make things a bit worse, I use intval() rather than is_int() because, in fact,
1328  // $row[0] is not an integer.
1329  //
1330  // So, what does this whole block do?
1331  // When relationships are found, we perform JOINs. This is fast. But not accurate:
1332  // instead of returning n objects with their n' associated cousins,
1333  // we get n*n' objects. This code fixes this.
1334  // Note: to-many relationships mess around with the 'limit' parameter
1335  $rowId = intval($row[$index]);
1336 
1337  if(ADODB_WORK_AR == $extra['loading']) {
1338  $arrRef[$rowId] = $obj;
1339  $arr[] = &$arrRef[$rowId];
1340  if(!isset($indices)) {
1341  $indices = $rowId;
1342  }
1343  else {
1344  $indices .= ','.$rowId;
1345  }
1346  if(!empty($relations['belongsTo'])) {
1347  foreach($relations['belongsTo'] as $foreignTable) {
1348  $foreignTableRef = $foreignTable->foreignKey;
1349  // First array: list of foreign ids we are looking for
1350  if(empty($bTos[$foreignTableRef])) {
1351  $bTos[$foreignTableRef] = array();
1352  }
1353  // Second array: list of ids found
1354  if(empty($obj->$foreignTableRef)) {
1355  continue;
1356  }
1357  if(empty($bTos[$foreignTableRef][$obj->$foreignTableRef])) {
1358  $bTos[$foreignTableRef][$obj->$foreignTableRef] = array();
1359  }
1360  $bTos[$foreignTableRef][$obj->$foreignTableRef][] = $obj;
1361  }
1362  }
1363  continue;
1364  }
1365 
1366  if($rowId>0) {
1367  if(ADODB_JOIN_AR == $extra['loading']) {
1368  $isNewObj = !isset($uniqArr['_'.$row[0]]);
1369  if($isNewObj) {
1370  $uniqArr['_'.$row[0]] = $obj;
1371  }
1372 
1373  // TODO Copy/paste code below: bad!
1374  if(!empty($relations['hasMany'])) {
1375  foreach($relations['hasMany'] as $foreignTable) {
1376  $foreignName = $foreignTable->foreignName;
1377  if(!empty($obj->$foreignName)) {
1378  $masterObj = &$uniqArr['_'.$row[0]];
1379  // Assumption: this property exists in every object since they are instances of the same class
1380  if(!is_array($masterObj->$foreignName)) {
1381  // Pluck!
1382  $foreignObj = $masterObj->$foreignName;
1383  $masterObj->$foreignName = array(clone($foreignObj));
1384  }
1385  else {
1386  // Pluck pluck!
1387  $foreignObj = $obj->$foreignName;
1388  array_push($masterObj->$foreignName, clone($foreignObj));
1389  }
1390  }
1391  }
1392  }
1393  if(!empty($relations['belongsTo'])) {
1394  foreach($relations['belongsTo'] as $foreignTable) {
1395  $foreignName = $foreignTable->foreignName;
1396  if(!empty($obj->$foreignName)) {
1397  $masterObj = &$uniqArr['_'.$row[0]];
1398  // Assumption: this property exists in every object since they are instances of the same class
1399  if(!is_array($masterObj->$foreignName)) {
1400  // Pluck!
1401  $foreignObj = $masterObj->$foreignName;
1402  $masterObj->$foreignName = array(clone($foreignObj));
1403  }
1404  else {
1405  // Pluck pluck!
1406  $foreignObj = $obj->$foreignName;
1407  array_push($masterObj->$foreignName, clone($foreignObj));
1408  }
1409  }
1410  }
1411  }
1412  if(!$isNewObj) {
1413  unset($obj); // We do not need this object itself anymore and do not want it re-added to the main array
1414  }
1415  }
1416  else if(ADODB_LAZY_AR == $extra['loading']) {
1417  // Lazy loading: we need to give AdoDb a hint that we have not really loaded
1418  // anything, all the while keeping enough information on what we wish to load.
1419  // Let's do this by keeping the relevant info in our relationship arrays
1420  // but get rid of the actual properties.
1421  // We will then use PHP's __get to load these properties on-demand.
1422  if(!empty($relations['hasMany'])) {
1423  foreach($relations['hasMany'] as $foreignTable) {
1424  $foreignName = $foreignTable->foreignName;
1425  if(!empty($obj->$foreignName)) {
1426  unset($obj->$foreignName);
1427  }
1428  }
1429  }
1430  if(!empty($relations['belongsTo'])) {
1431  foreach($relations['belongsTo'] as $foreignTable) {
1432  $foreignName = $foreignTable->foreignName;
1433  if(!empty($obj->$foreignName)) {
1434  unset($obj->$foreignName);
1435  }
1436  }
1437  }
1438  }
1439  }
1440 
1441  if(isset($obj)) {
1442  $arr[] = $obj;
1443  }
1444  }
1445 
1446  if(ADODB_WORK_AR == $extra['loading']) {
1447  // The best of both worlds?
1448  // Here, the number of queries is constant: 1 + n*relationship.
1449  // The second query will allow us to perform a good join
1450  // while preserving LIMIT etc.
1451  if(!empty($relations['hasMany'])) {
1452  foreach($relations['hasMany'] as $foreignTable) {
1453  $foreignName = $foreignTable->foreignName;
1454  $className = ucfirst($foreignTable->_singularize($foreignName));
1455  $obj = new $className();
1456  $dbClassRef = $foreignTable->foreignKey;
1457  $objs = $obj->packageFind($dbClassRef.' IN ('.$indices.')');
1458  foreach($objs as $obj) {
1459  if(!is_array($arrRef[$obj->$dbClassRef]->$foreignName)) {
1460  $arrRef[$obj->$dbClassRef]->$foreignName = array();
1461  }
1462  array_push($arrRef[$obj->$dbClassRef]->$foreignName, $obj);
1463  }
1464  }
1465 
1466  }
1467  if(!empty($relations['belongsTo'])) {
1468  foreach($relations['belongsTo'] as $foreignTable) {
1469  $foreignTableRef = $foreignTable->foreignKey;
1470  if(empty($bTos[$foreignTableRef])) {
1471  continue;
1472  }
1473  if(($k = reset($foreignTable->TableInfo()->keys))) {
1474  $belongsToId = $k;
1475  }
1476  else {
1477  $belongsToId = 'id';
1478  }
1479  $origObjsArr = $bTos[$foreignTableRef];
1480  $bTosString = implode(',', array_keys($bTos[$foreignTableRef]));
1481  $foreignName = $foreignTable->foreignName;
1482  $className = ucfirst($foreignTable->_singularize($foreignName));
1483  $obj = new $className();
1484  $objs = $obj->packageFind($belongsToId.' IN ('.$bTosString.')');
1485  foreach($objs as $obj)
1486  {
1487  foreach($origObjsArr[$obj->$belongsToId] as $idx=>$origObj)
1488  {
1489  $origObj->$foreignName = $obj;
1490  }
1491  }
1492  }
1493  }
1494  }
1495 
1496  return $arr;
1497 }
packageFind($whereOrderBy, $bindarr=false, $pkeysArr=false, $extra=array())
global $ADODB_ACTIVE_CACHESECS
LoadRelations($name, $whereOrderBy, $offset=-1, $limit=-1)
const ADODB_LAZY_AR
if(isset($_REQUEST['nrows'])) else $rs
Definition: server.php:94
global $_ADODB_ACTIVE_DBS
__construct($table=false, $pkeyarr=false, $db=false, $options=array())
adodb_throw($dbms, $fn, $errno, $errmsg, $p1, $p2, $thisConnection)
Load($where=null, $bindarr=false)
const ADODB_JOIN_AR
adodb_GetActiveRecordsClass(&$db, $class, $tableObj, $whereOrderBy, $bindarr, $primkeyArr, $extra, $relations)
const ADODB_WORK_AR
global $ADODB_ACTIVE_DEFVALS
hasMany($foreignRef, $foreignKey=false)
static SetDatabaseAdapter(&$db, $index=false)
ADODB_SetDatabaseAdapter(&$db)
belongsTo($foreignRef, $foreignKey=false)
UpdateActiveTable($pkeys=false, $forceUpdate=false)
static UseDefaultValues($bool=null)
$sql
Definition: server.php:84
Find($whereOrderBy, $bindarr=false, $pkeysArr=false, $extra=array())
global $ACTIVE_RECORD_SAFETY
adodb_write_file($filename, $contents, $debug=false)