Documentation TYPO3 par Ameos

adodb-active-record.inc.php

00001 <?php
00002 /*
00003 
00004 @version V4.93 10 Oct 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 (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         // retrieve ADOConnection from _ADODB_Active_DBs
00289         function &DB()
00290         {
00291         global $_ADODB_ACTIVE_DBS;
00292         
00293                 if ($this->_dbat < 0) {
00294                         $false = false;
00295                         $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)", "DB");
00296                         return $false;
00297                 }
00298                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00299                 $db =& $activedb->db;
00300                 return $db;
00301         }
00302         
00303         // retrieve ADODB_Active_Table
00304         function &TableInfo()
00305         {
00306         global $_ADODB_ACTIVE_DBS;
00307         
00308                 $activedb = $_ADODB_ACTIVE_DBS[$this->_dbat];
00309                 $table =& $activedb->tables[$this->_tableat];
00310                 return $table;
00311         }
00312         
00313         // set a numeric array (using natural table field ordering) as object properties
00314         function Set(&$row)
00315         {
00316                 $db =& $this->DB();
00317                 
00318                 if (!$row) {
00319                         $this->_saved = false;          
00320                         return false;
00321                 }
00322                 
00323                 $this->_saved = true;
00324                 
00325                 $table =& $this->TableInfo();
00326                 if (sizeof($table->flds) != sizeof($row)) {
00327                         $this->Error("Table structure of $this->_table has changed","Load");
00328                         return false;
00329                 }
00330                 
00331                 $cnt = 0;
00332                 foreach($table->flds as $name=>$fld) {
00333                         $this->$name = $row[$cnt];
00334                         $cnt += 1;
00335                 }
00336                 $this->_original = $row;
00337                 return true;
00338         }
00339         
00340         // get last inserted id for INSERT
00341         function LastInsertID(&$db,$fieldname)
00342         {
00343                 if ($db->hasInsertID)
00344                         $val = $db->Insert_ID($this->_table,$fieldname);
00345                 else
00346                         $val = false;
00347                         
00348                 if (is_null($val) || $val === false) {
00349                         // this might not work reliably in multi-user environment
00350                         return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
00351                 }
00352                 return $val;
00353         }
00354         
00355         // quote data in where clause
00356         function doquote(&$db, $val,$t)
00357         {
00358                 switch($t) {
00359                 case 'D':
00360                 case 'T':
00361                         if (empty($val)) return 'null';
00362                         
00363                 case 'C':
00364                 case 'X':
00365                         if (is_null($val)) return 'null';
00366                         
00367                         if (strncmp($val,"'",1) != 0 && substr($val,strlen($val)-1,1) != "'") { 
00368                                 return $db->qstr($val);
00369                                 break;
00370                         }
00371                 default:
00372                         return $val;
00373                         break;
00374                 }
00375         }
00376         
00377         // generate where clause for an UPDATE/SELECT
00378         function GenWhere(&$db, &$table)
00379         {
00380                 $keys = $table->keys;
00381                 $parr = array();
00382                 
00383                 foreach($keys as $k) {
00384                         $f = $table->flds[$k];
00385                         if ($f) {
00386                                 $parr[] = $k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
00387                         }
00388                 }
00389                 return implode(' and ', $parr);
00390         }
00391         
00392         
00393         //------------------------------------------------------------ Public functions below
00394         
00395         function Load($where,$bindarr=false)
00396         {
00397                 $db =& $this->DB(); if (!$db) return false;
00398                 $this->_where = $where;
00399                 
00400                 $save = $db->SetFetchMode(ADODB_FETCH_NUM);
00401                 $row = $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
00402                 $db->SetFetchMode($save);
00403                 
00404                 return $this->Set($row);
00405         }
00406         
00407         // false on error
00408         function Save()
00409         {
00410                 if ($this->_saved) $ok = $this->Update();
00411                 else $ok = $this->Insert();
00412                 
00413                 return $ok;
00414         }
00415         
00416         // false on error
00417         function Insert()
00418         {
00419                 $db =& $this->DB(); if (!$db) return false;
00420                 $cnt = 0;
00421                 $table =& $this->TableInfo();
00422                 
00423                 $valarr = array();
00424                 $names = array();
00425                 $valstr = array();
00426 
00427                 foreach($table->flds as $name=>$fld) {
00428                         $val = $this->$name;
00429                         if(!is_null($val) || !array_key_exists($name, $table->keys)) {
00430                                 $valarr[] = $val;
00431                                 $names[] = $name;
00432                                 $valstr[] = $db->Param($cnt);
00433                                 $cnt += 1;
00434                         }
00435                 }
00436                 
00437                 if (empty($names)){
00438                         foreach($table->flds as $name=>$fld) {
00439                                 $valarr[] = null;
00440                                 $names[] = $name;
00441                                 $valstr[] = $db->Param($cnt);
00442                                 $cnt += 1;
00443                         }
00444                 }
00445                 $sql = 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
00446                 $ok = $db->Execute($sql,$valarr);
00447                 
00448                 if ($ok) {
00449                         $this->_saved = true;
00450                         $autoinc = false;
00451                         foreach($table->keys as $k) {
00452                                 if (is_null($this->$k)) {
00453                                         $autoinc = true;
00454                                         break;
00455                                 }
00456                         }
00457                         if ($autoinc && sizeof($table->keys) == 1) {
00458                                 $k = reset($table->keys);
00459                                 $this->$k = $this->LastInsertID($db,$k);
00460                         }
00461                 }
00462                 
00463                 $this->_original = $valarr;
00464                 return !empty($ok);
00465         }
00466         
00467         function Delete()
00468         {
00469                 $db =& $this->DB(); if (!$db) return false;
00470                 $table =& $this->TableInfo();
00471                 
00472                 $where = $this->GenWhere($db,$table);
00473                 $sql = 'DELETE FROM '.$this->_table.' WHERE '.$where;
00474                 $ok = $db->Execute($sql);
00475                 
00476                 return $ok ? true : false;
00477         }
00478         
00479         // returns an array of active record objects
00480         function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
00481         {
00482                 $db =& $this->DB(); if (!$db || empty($this->_table)) return false;
00483                 $arr =& $db->GetActiveRecordsClass(get_class($this),$this->_table, $whereOrderBy,$bindarr,$pkeysArr);
00484                 return $arr;
00485         }
00486         
00487         // returns 0 on error, 1 on update, 2 on insert
00488         function Replace()
00489         {
00490         global $ADODB_ASSOC_CASE;
00491                 
00492                 $db =& $this->DB(); if (!$db) return false;
00493                 $table =& $this->TableInfo();
00494                 
00495                 $pkey = $table->keys;
00496                 
00497                 foreach($table->flds as $name=>$fld) {
00498                         $val = $this->$name;
00499                         /*
00500                         if (is_null($val)) {
00501                                 if (isset($fld->not_null) && $fld->not_null) {
00502                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00503                                         else {
00504                                                 $this->Error("Cannot update null into $name","Replace");
00505                                                 return false;
00506                                         }
00507                                 }
00508                         }*/
00509                         if (is_null($val) && !empty($fld->auto_increment)) {
00510                 continue;
00511             }
00512                         $t = $db->MetaType($fld->type);
00513                         $arr[$name] = $this->doquote($db,$val,$t);
00514                         $valarr[] = $val;
00515                 }
00516                 
00517                 if (!is_array($pkey)) $pkey = array($pkey);
00518                 
00519                 
00520                 if ($ADODB_ASSOC_CASE == 0) 
00521                         foreach($pkey as $k => $v)
00522                                 $pkey[$k] = strtolower($v);
00523                 elseif ($ADODB_ASSOC_CASE == 0) 
00524                         foreach($pkey as $k => $v)
00525                                 $pkey[$k] = strtoupper($v);
00526                                 
00527                 $ok = $db->Replace($this->_table,$arr,$pkey);
00528                 if ($ok) {
00529                         $this->_saved = true; // 1= update 2=insert
00530                         if ($ok == 2) {
00531                                 $autoinc = false;
00532                                 foreach($table->keys as $k) {
00533                                         if (is_null($this->$k)) {
00534                                                 $autoinc = true;
00535                                                 break;
00536                                         }
00537                                 }
00538                                 if ($autoinc && sizeof($table->keys) == 1) {
00539                                         $k = reset($table->keys);
00540                                         $this->$k = $this->LastInsertID($db,$k);
00541                                 }
00542                         }
00543                         
00544                         $this->_original =& $valarr;
00545                 } 
00546                 return $ok;
00547         }
00548 
00549         // returns 0 on error, 1 on update, -1 if no change in data (no update)
00550         function Update()
00551         {
00552                 $db =& $this->DB(); if (!$db) return false;
00553                 $table =& $this->TableInfo();
00554                 
00555                 $where = $this->GenWhere($db, $table);
00556                 
00557                 if (!$where) {
00558                         $this->error("Where missing for table $table", "Update");
00559                         return false;
00560                 }
00561                 $valarr = array(); 
00562                 $neworig = array();
00563                 $pairs = array();
00564                 $i = -1;
00565                 $cnt = 0;
00566                 foreach($table->flds as $name=>$fld) {
00567                         $i += 1;
00568                         $val = $this->$name;
00569                         $neworig[] = $val;
00570                         
00571                         if (isset($table->keys[$name])) {
00572                                 continue;
00573                         }
00574                         
00575                         if (is_null($val)) {
00576                                 if (isset($fld->not_null) && $fld->not_null) {
00577                                         if (isset($fld->default_value) && strlen($fld->default_value)) continue;
00578                                         else {
00579                                                 $this->Error("Cannot set field $name to NULL","Update");
00580                                                 return false;
00581                                         }
00582                                 }
00583                         }
00584                         
00585                         if (isset($this->_original[$i]) && $val == $this->_original[$i]) {
00586                                 continue;
00587                         }                       
00588                         $valarr[] = $val;
00589                         $pairs[] = $name.'='.$db->Param($cnt);
00590                         $cnt += 1;
00591                 }
00592                 
00593                 
00594                 if (!$cnt) return -1;
00595                 $sql = 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
00596                 $ok = $db->Execute($sql,$valarr);
00597                 if ($ok) {
00598                         $this->_original =& $neworig;
00599                         return 1;
00600                 }
00601                 return 0;
00602         }
00603         
00604         function GetAttributeNames()
00605         {
00606                 $table =& $this->TableInfo();
00607                 if (!$table) return false;
00608                 return array_keys($table->flds);
00609         }
00610         
00611 };
00612 
00613 ?>


Généré par L'expert TYPO3 avec  doxygen 1.4.6