/src/typo3_src-4.2.0alpha1/typo3/sysext/adodb/adodb/adodb-active-record.inc.php

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

This documentation has been generated automatically from TYPO3 source code using Doxygen and is provided as is by Cast Iron Coding as a courtesy to other TYPO3 developers and users. Please consider Cast Iron Coding — a full-service web development agency in Portland, Oregon specializing in TYPO3 extension development — for all of your TYPO3 development and consulting needs!