"TYPO3 4.0.1: typo3_src-4.0.1/typo3/sysext/adodb/adodb/adodb-active-record.inc.php Source File", "datetime" => "Sat Dec 2 19:22:24 2006", "date" => "2 Dec 2006", "doxygenversion" => "1.4.6", "projectname" => "TYPO3 4.0.1", "projectnumber" => "4.0.1" ); get_header($doxygen_vars); ?>

adodb-active-record.inc.php

00001 <?php
00002 /*
00003 
00004 @version V4.90 8 June 2006  (c) 2000-2006 John Lim (jlim#natsoft.com.my). All rights reserved.
00005   Latest version is available at http://adodb.sourceforge.net
00006  
00007   Released under both BSD license and Lesser GPL library license. 
00008   Whenever there is any discrepancy between the two licenses, 
00009   the BSD license will take precedence.
00010   
00011   Active Record implementation. Superset of Zend Framework's.
00012   
00013   Version 0.04
00014   
00015   See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
00016         for info on Ruby on Rails Active Record implementation
00017 */
00018 
00019 global $_ADODB_ACTIVE_DBS;
00020 global $ADODB_ACTIVE_CACHESECS; // set to true to enable caching of metadata such as field info
00021 
00022 // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
00023 $_ADODB_ACTIVE_DBS = array();
00024 
00025 
00026 class ADODB_Active_DB {
00027         var $db; // ADOConnection
00028         var $tables; // assoc array of ADODB_Active_Table objects, indexed by tablename
00029 }
00030 
00031 class ADODB_Active_Table {
00032         var $name; // table name
00033         var $flds; // assoc array of adofieldobjs, indexed by fieldname
00034         var $keys; // assoc array of primary keys, indexed by fieldname
00035         var $_created; // only used when stored as a cached file
00036 }
00037 
00038 // returns index into $_ADODB_ACTIVE_DBS
00039 function ADODB_SetDatabaseAdapter(&$db)
00040 {
00041         global $_ADODB_ACTIVE_DBS;
00042         
00043                 foreach($_ADODB_ACTIVE_DBS as $k => $d) {
00044                         if ($d->db == $db) return $k;
00045                 }
00046                 
00047                 $obj = new ADODB_Active_DB();
00048                 $obj->db =& $db;
00049                 $obj->tables = array();
00050                 
00051                 $_ADODB_ACTIVE_DBS[] = $obj;
00052                 
00053                 return sizeof($_ADODB_ACTIVE_DBS)-1;
00054 }
00055 
00056 
00057 class ADODB_Active_Record {
00058         var $_dbat; // associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
00059         var $_table; // tablename, if set in class definition then use it as table name
00060         var $_tableat; // associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
00061         var $_where; // where clause set in Load()
00062         var $_saved = false; // indicates whether data is already inserted.
00063         var $_lasterr = false; // last error message
00064         var $_original = false; // the original values loaded or inserted, refreshed on update
00065         
00066         // should be static
00067         function SetDatabaseAdapter(&$db) 
00068         {
00069                 return ADODB_SetDatabaseAdapter($db);
00070         }
00071         
00072         // php4 constructor
00073         function ADODB_Active_Record($table = false, $pkeyarr=false, $db=false)
00074         {
00075                 ADODB_Active_Record::__construct($table,$pkeyarr,$db);
00076         }
00077         
00078         // php5 constructor
00079         function __construct($table = false, $pkeyarr=false, $db=false)
00080         {
00081         global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
00082         
00083                 if ($db == false && is_object($pkeyarr)) {
00084                         $db = $pkeyarr;
00085                         $pkeyarr = false;
00086                 }
00087                 
00088                 if (!$table) { 
00089                         if (!empty($this->_table)) $table = $this->_table;
00090                         else $table = $this->_pluralize(get_class($this));
00091                 }
00092                 if ($db) {
00093                         $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
00094                 } else
00095                         $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
00096                 
00097                 
00098                 if ($this->_dbat < 0) $this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
00099                 
00100                 $this->_table = $table;
00101                 $this->_tableat = $table; # reserved for setting the assoc value to a non-table name, eg. the sql string in future
00102                 $this->UpdateActiveTable($pkeyarr);
00103         }
00104         
00105         function _pluralize($table)
00106         {
00107                 $ut = strtoupper($table);
00108                 $len = strlen($table);
00109                 $lastc = $ut[$len-1];
00110                 $lastc2 = substr($ut,$len-2);
00111                 switch ($lastc) {
00112                 case 'S':
00113                         return $table.'es';     
00114                 case 'Y':
00115                         return substr($table,0,$len-1).'ies';
00116                 case 'X':       
00117                         return $table.'es';
00118                 case 'H': 
00119                         if ($lastc2 == 'CH' || $lastc2 == 'SH')
00120                                 return $table.'es';
00121                 default:
00122                         return $table.'s';
00123                 }
00124         }
00125         
00127         
00128         // update metadata
00129         function UpdateActiveTable($pkeys=false,$forceUpdate=false)
00130         {
00131         global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS , $ADODB_CACHE_DIR, $ADODB_ACTIVE_CACHESECS;
00132         
00133                 $activedb =& $_ADODB_ACTIVE_DBS[$this->_dbat];
00134 
00135                 $table = $this->_table;
00136                 $tables = $activedb->tables;
00137                 $tableat = $this->_tableat;
00138                 if (!$forceUpdate && !empty($tables[$tableat])) {
00139                         $tobj =& $tables[$tableat];
00140                         foreach($tobj->flds as $name => $fld) 
00141                                 $this->$name = null;
00142                         return;
00143                 }
00144                 
00145                 $db =& $activedb->db;
00146                 $fname = $ADODB_CACHE_DIR . '/adodb_' . $db->databaseType . '_active_'. $table . '.cache';
00147                 if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
00148                         $fp = fopen($fname,'r');
00149                         @flock($fp, LOCK_SH);
00150                         $acttab = unserialize(fread($fp,100000));
00151                         fclose($fp);
00152                         if ($acttab->_created + $ADODB_ACTIVE_CACHESECS - (abs(rand()) % 16) > time()) { 
00153                                 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
00154                                 // ideally, you should cache at least 32 secs
00155                                 $activedb->tables[$table] = $acttab;
00156                                 
00157                                 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
00158                                 return;
00159                         } else if ($db->debug) {
00160                                 ADOConnection::outp("Refreshing cached active record file: $fname");
00161                         }
00162                 }
00163                 $activetab = new ADODB_Active_Table();
00164                 $activetab->name = $table;
00165                 
00166                 
00167                 $cols = $db->MetaColumns($table);
00168                 if (!$cols) {
00169                         $this->Error("Invalid table name: $table",'UpdateActiveTable'); 
00170                         return false;
00171                 }
00172                 $fld = reset($cols);
00173                 if (!$pkeys) {
00174                         if (isset($fld->primary_key)) {
00175                                 $pkeys = array();
00176                                 foreach($cols as $name => $fld) {
00177                                         if (!empty($fld->primary_key)) $pkeys[] = $name;
00178                                 }
00179                         } else  
00180                                 $pkeys = $this->GetPrimaryKeys($db, $table);
00181                 }
00182                 if (empty($pkeys)) {
00183                         $this->Error("No primary key found for table $table",'UpdateActiveTable');
00184                         return false;
00185                 }
00186                 
00187                 $attr = array();
00188                 $keys = array();
00189                 
00190                 switch($ADODB_ASSOC_CASE) {
00191                 case 0:
00192                         foreach($cols as $name => $fldobj) {
00193                                 $name = strtolower($name);
00194                                 $this->$name = null;
00195                                 $attr[$name] = $fldobj;
00196                         }
00197                         foreach($pkeys as $k => $name) {
00198                                 $keys[strtolower($name)] = strtolower($name);
00199                         }
00200                         break;
00201                         
00202                 case 1: 
00203                         foreach($cols as $name => $fldobj) {
00204                                 $name = strtoupper($name);
00205                                 $this->$name = null;
00206                                 $attr[$name] = $fldobj;
00207                         }
00208                         
00209                         foreach($pkeys as $k => $name) {
00210                                 $keys[strtoupper($name)] = strtoupper($name);
00211                         }
00212                         break;
00213                 default:
00214                         foreach($cols as $name => $fldobj) {
00215                                 $name = ($name);
00216                                 $this->$name = null;
00217                                 $attr[$name] = $fldobj;
00218                         }
00219                         foreach($pkeys as $k => $name) {
00220                                 $keys[$name] = ($name);
00221                         }
00222                         break;
00223                 }
00224                 
00225                 $activetab->keys = $keys;
00226                 $activetab->flds = $attr;
00227 
00228                 if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR) {
00229                         $activetab->_created = time();
00230                         $s = serialize($activetab);
00231                         if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
00232                         adodb_write_file($fname,$s);
00233                 }
00234                 $activedb->tables[$table] = $activetab;
00235         }
00236         
00237         function GetPrimaryKeys(&$db, $table)
00238         {
00239                 return $db->MetaPrimaryKeys($table);
00240         }
00241         
00242         // error handler for both PHP4+5. 
00243         function Error($err,$fn)
00244         {
00245         global $_ADODB_ACTIVE_DBS;
00246         
00247                 $fn = get_class($this).'::'.$fn;
00248                 $this->_lasterr = $fn.': '.$err;
00249                 
00250                 if ($this->_dbat < 0) $db = false;
00251                 else {
00252                         $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00253                         $db =& $activedb->db;
00254                 }
00255                 
00256                 if (function_exists('adodb_throw')) {   
00257                         if (!$db) adodb_throw('ADOdb_Active_Record', $fn, -1, $err, 0, 0, false);
00258                         else adodb_throw($db->databaseType, $fn, -1, $err, 0, 0, $db);
00259                 } else
00260                         if (!$db || $db->debug) ADOConnection::outp($this->_lasterr);
00261                 
00262         }
00263         
00264         // return last error message
00265         function ErrorMsg()
00266         {
00267                 if (!function_exists('adodb_throw')) {
00268                         if ($this->_dbat < 0) $db = false;
00269                         else $db = $this->DB();
00270                 
00271                         // last error could be database error too
00272                         if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
00273                 }
00274                 return $this->_lasterr;
00275         }
00276         
00277         // retrieve ADOConnection from _ADODB_Active_DBs
00278         function &DB()
00279         {
00280         global $_ADODB_ACTIVE_DBS;
00281         
00282                 if ($this->_dbat < 0) {
00283                         $false = false;
00284                         $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
00285                         return $false;
00286                 }
00287                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00288                 $db =& $activedb->db;
00289                 return $db;
00290         }
00291         
00292         // retrieve ADODB_Active_Table
00293         function &TableInfo()
00294         {
00295         global $_ADODB_ACTIVE_DBS;
00296         
00297                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00298                 $table =& $activedb->tables[$this->_tableat];
00299                 return $table;
00300         }
00301         
00302         // set a numeric array (using natural table field ordering) as object properties
00303         function Set(&$row)
00304         {
00305                 $db =& $this->DB();
00306                 
00307                 if (!$row) {
00308                         $this->_saved = false;          
00309                         return false;
00310                 }
00311                 
00312                 $this->_saved = true;
00313                 
00314                 $table =& $this->TableInfo();
00315                 if (sizeof($table->flds) != sizeof($row)) {
00316                         $this->Error("Table structure of $this->_table has changed","Load");
00317                         return false;
00318                 }
00319                 
00320                 $cnt = 0;
00321                 foreach($table->flds as $name=>$fld) {
00322                         $this->$name = $row[$cnt];
00323                         $cnt += 1;
00324                 }
00325                 $this->_original = $row;
00326                 return true;
00327         }
00328         
00329         // get last inserted id for INSERT
00330         function LastInsertID(&$db,$fieldname)
00331         {
00332                 if ($db->hasInsertID)
00333                         $val = $db->Insert_ID($this->_table,$fieldname);
00334                 else
00335                         $val = false;
00336                         
00337                 if (is_null($val) || $val === false) {
00338                         // this might not work reliably in multi-user environment
00339                         return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
00340                 }
00341                 return $val;
00342         }
00343         
00344         // quote data in where clause
00345         function doquote(&$db, $val,$t)
00346         {
00347                 switch($t) {
00348                 case 'D':
00349                 case 'T':
00350                         if (empty($val)) return 'null';
00351                         
00352                 case 'C':
00353                 case 'X':
00354                         if (is_null($val)) return 'null';
00355                         
00356                         if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
00357                                 return $db->qstr($val);
00358                                 break;
00359                         }
00360                 default:
00361                         return $val;
00362                         break;
00363                 }
00364         }
00365         
00366         // generate where clause for an UPDATE/SELECT
00367         function GenWhere(&$db, &$table)
00368         {
00369                 $keys = $table->keys;
00370                 $parr = array();
00371                 
00372                 foreach($keys as $k) {
00373                         $f = $table->flds[$k];
00374                         if ($f) {
00375                                 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
00376                         }
00377                 }
00378                 return implode(' and ', $parr);
00379         }
00380         
00381         
00382         //------------------------------------------------------------ Public functions below
00383         
00384         function Load($where,$bindarr=false)
00385         {
00386                 $db =& $this->DB(); if (!$db) return false;
00387                 $this->_where = $where;
00388                 
00389                 $save = $db->SetFetchMode(ADODB_FETCH_NUM);
00390                 $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
00391                 $db->SetFetchMode($save);
00392                 
00393                 return $this->Set($row);
00394         }
00395         
00396         // false on error
00397         function Save()
00398         {
00399                 if ($this->_saved) $ok = $this->Update();
00400                 else $ok = $this->Insert();
00401                 
00402                 return $ok;
00403         }
00404         
00405         // false on error
00406         function Insert()
00407         {
00408                 $db =& $this->DB(); if (!$db) return false;
00409                 $cnt = 0;
00410                 $table =& $this->TableInfo();
00411 
00412                 foreach($table->flds as $name=>$fld) {
00413                         $val = $this->$name;
00414                         /*
00415                         if (is_null($val)) {
00416                                 if (isset($fld->not_null) && $fld->not_null) {
00417                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00418                                         else $this->Error("Cannot insert null into $name","Insert");
00419                                 }
00420                         }*/
00421                         
00422                         $valarr[] = $val;
00423                         $names[] = $name;
00424                         $valstr[] = $db->Param($cnt);
00425                         $cnt += 1;
00426                 }
00427                 
00428                 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
00429                 $ok = $db->Execute($sql,$valarr);
00430                 
00431                 if ($ok) {
00432                         $this->_saved = true;
00433                         $autoinc = false;
00434                         foreach($table->keys as $k) {
00435                                 if (is_null($this->$k)) {
00436                                         $autoinc = true;
00437                                         break;
00438                                 }
00439                         }
00440                         if ($autoinc && sizeof($table->keys) == 1) {
00441                                 $k = reset($table->keys);
00442                                 $this->$k = $this->LastInsertID($db,$k);
00443                         }
00444                 }
00445                 
00446                 $this->_original = $valarr;
00447                 return !empty($ok);
00448         }
00449         
00450         function Delete()
00451         {
00452                 $db =& $this->DB(); if (!$db) return false;
00453                 $table =& $this->TableInfo();
00454                 
00455                 $where = $this->GenWhere($db,$table);
00456                 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
00457                 $db->Execute($sql);
00458         }
00459         
00460         // returns an array of active record objects
00461         function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
00462         {
00463                 $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
00464                 $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
00465                 return $arr;
00466         }
00467         
00468         // returns 0 on error, 1 on update, 2 on insert
00469         function Replace()
00470         {
00471         global $ADODB_ASSOC_CASE;
00472                 
00473                 $db =& $this->DB(); if (!$db) return false;
00474                 $table =& $this->TableInfo();
00475                 
00476                 $pkey = $table->keys;
00477                 
00478                 foreach($table->flds as $name=>$fld) {
00479                         $val = $this->$name;
00480                         /*
00481                         if (is_null($val)) {
00482                                 if (isset($fld->not_null) && $fld->not_null) {
00483                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00484                                         else {
00485                                                 $this->Error("Cannot update null into $name","Replace");
00486                                                 return false;
00487                                         }
00488                                 }
00489                         }*/
00490                         if (is_null($val) && !empty($fld->auto_increment)) {
00491                 continue;
00492             }
00493                         $t = $db->MetaType($fld->type);
00494                         $arr[$name] = $this->doquote($db,$val,$t);
00495                         $valarr[] = $val;
00496                 }
00497                 
00498                 if (!is_array($pkey)) $pkey = array($pkey);
00499                 
00500                 
00501                 if ($ADODB_ASSOC_CASE == 0) 
00502                         foreach($pkey as $k => $v)
00503                                 $pkey[$k] = strtolower($v);
00504                 elseif ($ADODB_ASSOC_CASE == 0) 
00505                         foreach($pkey as $k => $v)
00506                                 $pkey[$k] = strtoupper($v);
00507                                 
00508                 $ok = $db->Replace($this->_table,$arr,$pkey);
00509                 if ($ok) {
00510                         $this->_saved = true; // 1= update 2=insert
00511                         if ($ok == 2) {
00512                                 $autoinc = false;
00513                                 foreach($table->keys as $k) {
00514                                         if (is_null($this->$k)) {
00515                                                 $autoinc = true;
00516                                                 break;
00517                                         }
00518                                 }
00519                                 if ($autoinc && sizeof($table->keys) == 1) {
00520                                         $k = reset($table->keys);
00521                                         $this->$k = $this->LastInsertID($db,$k);
00522                                 }
00523                         }
00524                         
00525                         $this->_original =& $valarr;
00526                 } 
00527                 return $ok;
00528         }
00529 
00530         // returns 0 on error, 1 on update, -1 if no change in data (no update)
00531         function Update()
00532         {
00533                 $db =& $this->DB(); if (!$db) return false;
00534                 $table =& $this->TableInfo();
00535                 
00536                 $where = $this->GenWhere($db, $table);
00537                 
00538                 if (!$where) {
00539                         $this->error("Where missing for table $table", "Update");
00540                         return false;
00541                 }
00542                 $valarr = array(); 
00543                 $neworig = array();
00544                 $pairs = array();
00545                 $i = -1;
00546                 $cnt = 0;
00547                 foreach($table->flds as $name=>$fld) {
00548                         $i += 1;
00549                         $val = $this->$name;
00550                         $neworig[] = $val;
00551                         
00552                         if (isset($table->keys[$name])) {
00553                                 continue;
00554                         }
00555                         
00556                         
00557                         if (is_null($val)) {
00558                                 if (isset($fld->not_null) && $fld->not_null) {
00559                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00560                                         else {
00561                                                 $this->Error("Cannot set field $name to NULL","Update");
00562                                                 return false;
00563                                         }
00564                                 }
00565                         }
00566                         
00567                         if ( $val == $this->_original[$i]) {
00568                                 continue;
00569                         }                       
00570                         $valarr[] = $val;
00571                         $pairs[] = $name.'='.$db->Param($cnt);
00572                         $cnt += 1;
00573                 }
00574                 
00575                 
00576                 if (!$cnt) return -1;
00577                 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
00578                 $ok = $db->Execute($sql,$valarr);
00579                 if ($ok) {
00580                         $this->_original =& $neworig;
00581                         return 1;
00582                 }
00583                 return 0;
00584         }
00585         
00586         function GetAttributeNames()
00587         {
00588                 $table =& $this->TableInfo();
00589                 if (!$table) return false;
00590                 return array_keys($table->flds);
00591         }
00592         
00593 };
00594 
00595 ?>