Zikula 1.0.1
[ class tree: Zikula 1.0.1 ] [ index: Zikula 1.0.1 ] [ all elements ]

Source for file adodb-active-record.inc.php

Documentation is available at adodb-active-record.inc.php

  1. <?php
  2. /*
  3.  
  4. @version V4.97 22 Jan 2008  (c) 2000-2008 John Lim (jlim#natsoft.com.my). All rights reserved.
  5.   Latest version is available at http://adodb.sourceforge.net
  6.  
  7.   Released under both BSD license and Lesser GPL library license. 
  8.   Whenever there is any discrepancy between the two licenses, 
  9.   the BSD license will take precedence.
  10.   
  11.   Active Record implementation. Superset of Zend Framework's.
  12.   
  13.   Version 0.09
  14.   
  15.   See http://www-128.ibm.com/developerworks/java/library/j-cb03076/?ca=dgr-lnxw01ActiveRecord 
  16.       for info on Ruby on Rails Active Record implementation
  17. */
  18.  
  19. global $_ADODB_ACTIVE_DBS;
  20. global $ADODB_ACTIVE_CACHESECS// set to true to enable caching of metadata such as field info
  21. global $ACTIVE_RECORD_SAFETY// set to false to disable safety checks
  22. global $ADODB_ACTIVE_DEFVALS// use default values of table definition when creating new active record.
  23.  
  24. // array of ADODB_Active_DB's, indexed by ADODB_Active_Record->_dbat
  25. $_ADODB_ACTIVE_DBS array();
  26. $ACTIVE_RECORD_SAFETY true;
  27. $ADODB_ACTIVE_DEFVALS false;
  28.  
  29. class ADODB_Active_DB {
  30.     var $db// ADOConnection
  31.     var $tables// assoc array of ADODB_Active_Table objects, indexed by tablename
  32. }
  33.  
  34.     var $name// table name
  35.     var $flds// assoc array of adofieldobjs, indexed by fieldname
  36.     var $keys// assoc array of primary keys, indexed by fieldname
  37.     var $_created// only used when stored as a cached file
  38. }
  39.  
  40. // returns index into $_ADODB_ACTIVE_DBS
  41. function ADODB_SetDatabaseAdapter(&$db)
  42. {
  43.     global $_ADODB_ACTIVE_DBS;
  44.     
  45.         foreach($_ADODB_ACTIVE_DBS as $k => $d{
  46.             if (PHP_VERSION >= 5{
  47.                 if ($d->db === $dbreturn $k;
  48.             else {
  49.                 if ($d->db->_connectionID === $db->_connectionID && $db->database == $d->db->database
  50.                     return $k;
  51.             }
  52.         }
  53.         
  54.         $obj new ADODB_Active_DB();
  55.         $obj->db =$db;
  56.         $obj->tables array();
  57.         
  58.         $_ADODB_ACTIVE_DBS[$obj;
  59.         
  60.         return sizeof($_ADODB_ACTIVE_DBS)-1;
  61. }
  62.  
  63.  
  64.     var $_dbat// associative index pointing to ADODB_Active_DB eg. $ADODB_Active_DBS[_dbat]
  65.     var $_table// tablename, if set in class definition then use it as table name
  66.     var $_tableat// associative index pointing to ADODB_Active_Table, eg $ADODB_Active_DBS[_dbat]->tables[$this->_tableat]
  67.     var $_where// where clause set in Load()
  68.     var $_saved = false// indicates whether data is already inserted.
  69.     var $_lasterr = false// last error message
  70.     var $_original = false// the original values loaded or inserted, refreshed on update
  71.     
  72.     // should be static
  73.     function UseDefaultValues($bool=null)
  74.     {
  75.     global $ADODB_ACTIVE_DEFVALS;
  76.         if (isset($bool)) $ADODB_ACTIVE_DEFVALS $bool;
  77.         return $ADODB_ACTIVE_DEFVALS;
  78.     }
  79.  
  80.     // should be static
  81.     function SetDatabaseAdapter(&$db
  82.     {
  83.         return ADODB_SetDatabaseAdapter($db);
  84.     }
  85.     
  86.     // php4 constructor
  87.     function ADODB_Active_Record($table false$pkeyarr=false$db=false)
  88.     {
  89.         ADODB_Active_Record::__construct($table,$pkeyarr,$db);
  90.     }
  91.     
  92.     // php5 constructor
  93.     function __construct($table false$pkeyarr=false$db=false)
  94.     {
  95.     global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS;
  96.     
  97.         if ($db == false && is_object($pkeyarr)) {
  98.             $db $pkeyarr;
  99.             $pkeyarr false;
  100.         }
  101.         
  102.         if (!$table
  103.             if (!empty($this->_table)) $table $this->_table;
  104.             else $table $this->_pluralize(get_class($this));
  105.         }
  106.         if ($db{
  107.             $this->_dbat = ADODB_Active_Record::SetDatabaseAdapter($db);
  108.         else
  109.             $this->_dbat = sizeof($_ADODB_ACTIVE_DBS)-1;
  110.         
  111.         
  112.         if ($this->_dbat < 0$this->Error("No database connection set; use ADOdb_Active_Record::SetDatabaseAdapter(\$db)",'ADODB_Active_Record::__constructor');
  113.         
  114.         $this->_table = $table;
  115.         $this->_tableat = $table# reserved for setting the assoc value to a non-table name, eg. the sql string in future
  116.         $this->UpdateActiveTable($pkeyarr);
  117.     }
  118.     
  119.     function __wakeup()
  120.     {
  121.           $class get_class($this);
  122.           new $class;
  123.     }
  124.     
  125.     function _pluralize($table)
  126.     {
  127.         $ut strtoupper($table);
  128.         $len strlen($table);
  129.         $lastc $ut[$len-1];
  130.         $lastc2 substr($ut,$len-2);
  131.         switch ($lastc{
  132.         case 'S':
  133.             return $table.'es';    
  134.         case 'Y':
  135.             return substr($table,0,$len-1).'ies';
  136.         case 'X':    
  137.             return $table.'es';
  138.         case 'H'
  139.             if ($lastc2 == 'CH' || $lastc2 == 'SH')
  140.                 return $table.'es';
  141.         default:
  142.             return $table.'s';
  143.         }
  144.     }
  145.     
  146.     //////////////////////////////////
  147.     
  148.     // update metadata
  149.     function UpdateActiveTable($pkeys=false,$forceUpdate=false)
  150.     {
  151.     global $ADODB_ASSOC_CASE,$_ADODB_ACTIVE_DBS $ADODB_CACHE_DIR$ADODB_ACTIVE_CACHESECS;
  152.     global $ADODB_ACTIVE_DEFVALS;
  153.  
  154.         $activedb =$_ADODB_ACTIVE_DBS[$this->_dbat];
  155.  
  156.         $table $this->_table;
  157.         $tables $activedb->tables;
  158.         $tableat $this->_tableat;
  159.         if (!$forceUpdate && !empty($tables[$tableat])) {
  160.             $tobj =$tables[$tableat];
  161.             foreach($tobj->flds as $name => $fld{
  162.                 if ($ADODB_ACTIVE_DEFVALS && isset($fld->default_value)) 
  163.                     $this->$name $fld->default_value;
  164.                 else
  165.                     $this->$name null;
  166.             }
  167.             return;
  168.         }
  169.         
  170.         $db =$activedb->db;
  171.         $fname $ADODB_CACHE_DIR '/adodb_' $db->databaseType '_active_'$table '.cache';
  172.         if (!$forceUpdate && $ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR && file_exists($fname)) {
  173.             $fp fopen($fname,'r');
  174.             @flock($fpLOCK_SH);
  175.             $acttab unserialize(fread($fp,100000));
  176.             fclose($fp);
  177.             if ($acttab->_created $ADODB_ACTIVE_CACHESECS (abs(rand()) 16time()) 
  178.                 // abs(rand()) randomizes deletion, reducing contention to delete/refresh file
  179.                 // ideally, you should cache at least 32 secs
  180.                 $activedb->tables[$table$acttab;
  181.                 
  182.                 //if ($db->debug) ADOConnection::outp("Reading cached active record file: $fname");
  183.                   return;
  184.             else if ($db->debug{
  185.                 ADOConnection::outp("Refreshing cached active record file: $fname");
  186.             }
  187.         }
  188.         $activetab new ADODB_Active_Table();
  189.         $activetab->name $table;
  190.         
  191.         
  192.         $cols $db->MetaColumns($table);
  193.         if (!$cols{
  194.             $this->Error("Invalid table name: $table",'UpdateActiveTable')
  195.             return false;
  196.         }
  197.         $fld reset($cols);
  198.         if (!$pkeys{
  199.             if (isset($fld->primary_key)) {
  200.                 $pkeys array();
  201.                 foreach($cols as $name => $fld{
  202.                     if (!empty($fld->primary_key)) $pkeys[$name;
  203.                 }
  204.             else    
  205.                 $pkeys $this->GetPrimaryKeys($db$table);
  206.         }
  207.         if (empty($pkeys)) {
  208.             $this->Error("No primary key found for table $table",'UpdateActiveTable');
  209.             return false;
  210.         }
  211.         
  212.         $attr array();
  213.         $keys array();
  214.         
  215.         switch($ADODB_ASSOC_CASE{
  216.         case 0:
  217.             foreach($cols as $name => $fldobj{
  218.                 $name strtolower($name);
  219.                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  220.                     $this->$name $fldobj->default_value;
  221.                 else
  222.                     $this->$name null;
  223.                 $attr[$name$fldobj;
  224.             }
  225.             foreach($pkeys as $k => $name{
  226.                 $keys[strtolower($name)strtolower($name);
  227.             }
  228.             break;
  229.             
  230.         case 1
  231.             foreach($cols as $name => $fldobj{
  232.                 $name strtoupper($name);
  233.                
  234.                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  235.                     $this->$name $fldobj->default_value;
  236.                 else
  237.                     $this->$name null;
  238.                 $attr[$name$fldobj;
  239.             }
  240.             
  241.             foreach($pkeys as $k => $name{
  242.                 $keys[strtoupper($name)strtoupper($name);
  243.             }
  244.             break;
  245.         default:
  246.             foreach($cols as $name => $fldobj{
  247.                 $name ($fldobj->name);
  248.                 
  249.                 if ($ADODB_ACTIVE_DEFVALS && isset($fldobj->default_value))
  250.                     $this->$name $fldobj->default_value;
  251.                 else
  252.                     $this->$name null;
  253.                 $attr[$name$fldobj;
  254.             }
  255.             foreach($pkeys as $k => $name{
  256.                 $keys[$name$cols[$name]->name;
  257.             }
  258.             break;
  259.         }
  260.         
  261.         $activetab->keys $keys;
  262.         $activetab->flds $attr;
  263.  
  264.         if ($ADODB_ACTIVE_CACHESECS && $ADODB_CACHE_DIR{
  265.             $activetab->_created time();
  266.             $s serialize($activetab);
  267.             if (!function_exists('adodb_write_file')) include(ADODB_DIR.'/adodb-csvlib.inc.php');
  268.             adodb_write_file($fname,$s);
  269.         }
  270.         $activedb->tables[$table$activetab;
  271.     }
  272.     
  273.     function GetPrimaryKeys(&$db$table)
  274.     {
  275.         return $db->MetaPrimaryKeys($table);
  276.     }
  277.     
  278.     // error handler for both PHP4+5. 
  279.     function Error($err,$fn)
  280.     {
  281.     global $_ADODB_ACTIVE_DBS;
  282.     
  283.         $fn get_class($this).'::'.$fn;
  284.         $this->_lasterr = $fn.': '.$err;
  285.         
  286.         if ($this->_dbat < 0$db false;
  287.         else {
  288.             $activedb $_ADODB_ACTIVE_DBS[$this->_dbat];
  289.             $db =$activedb->db;
  290.         }
  291.         
  292.         if (function_exists('adodb_throw')) {    
  293.             if (!$dbadodb_throw('ADOdb_Active_Record'$fn-1$err00false);
  294.             else adodb_throw($db->databaseType$fn-1$err00$db);
  295.         else
  296.             if (!$db || $db->debugADOConnection::outp($this->_lasterr);
  297.         
  298.     }
  299.     
  300.     // return last error message
  301.     function ErrorMsg()
  302.     {
  303.         if (!function_exists('adodb_throw')) {
  304.             if ($this->_dbat < 0$db false;
  305.             else $db $this->DB();
  306.         
  307.             // last error could be database error too
  308.             if ($db && $db->ErrorMsg()) return $db->ErrorMsg();
  309.         }
  310.         return $this->_lasterr;
  311.     }
  312.     
  313.     function ErrorNo(
  314.     {
  315.         if ($this->_dbat < 0return -9999// no database connection...
  316.         $db $this->DB();
  317.         
  318.         return (int) $db->ErrorNo();
  319.     }
  320.  
  321.  
  322.     // retrieve ADOConnection from _ADODB_Active_DBs
  323.     function &DB()
  324.     {
  325.     global $_ADODB_ACTIVE_DBS;
  326.     
  327.         if ($this->_dbat < 0{
  328.             $false false;
  329.             $this->Error("No database connection set: use ADOdb_Active_Record::SetDatabaseAdaptor(\$db)""DB");
  330.             return $false;
  331.         }
  332.         $activedb $_ADODB_ACTIVE_DBS[$this->_dbat];
  333.         $db =$activedb->db;
  334.         return $db;
  335.     }
  336.     
  337.     // retrieve ADODB_Active_Table
  338.     function &TableInfo()
  339.     {
  340.     global $_ADODB_ACTIVE_DBS;
  341.     
  342.         $activedb $_ADODB_ACTIVE_DBS[$this->_dbat];
  343.         $table =$activedb->tables[$this->_tableat];
  344.         return $table;
  345.     }
  346.     
  347.     // set a numeric array (using natural table field ordering) as object properties
  348.     function Set(&$row)
  349.     {
  350.     global $ACTIVE_RECORD_SAFETY;
  351.     
  352.         $db =$this->DB();
  353.         
  354.         if (!$row{
  355.             $this->_saved = false;        
  356.             return false;
  357.         }
  358.         
  359.         $this->_saved = true;
  360.         
  361.         $table =$this->TableInfo();
  362.         if ($ACTIVE_RECORD_SAFETY && sizeof($table->flds!= sizeof($row)) {
  363.             $bad_size TRUE;
  364.             if (sizeof($row== sizeof($table->flds)) {
  365.                 // Only keep string keys
  366.                 $keys array_filter(array_keys($row)'is_string');
  367.                 if (sizeof($keys== sizeof($table->flds))
  368.                     $bad_size FALSE;
  369.             }
  370.             if ($bad_size{
  371.                 $this->Error("Table structure of $this->_table has changed","Load");
  372.                 return false;
  373.             }
  374.         }
  375.         else
  376.             $keys array_keys($row);
  377.       
  378.         reset($keys);
  379.         $this->_original = array();
  380.         foreach($table->flds as $name=>$fld{
  381.             $value $row[current($keys)];
  382.             $this->$name $value;
  383.             $this->_original[$value;
  384.             next($keys);
  385.         }
  386.         # </AP>
  387.         return true;
  388.     }
  389.     
  390.     // get last inserted id for INSERT
  391.     function LastInsertID(&$db,$fieldname)
  392.     {
  393.         if ($db->hasInsertID)
  394.             $val $db->Insert_ID($this->_table,$fieldname);
  395.         else
  396.             $val false;
  397.             
  398.         if (is_null($val|| $val === false{
  399.             // this might not work reliably in multi-user environment
  400.             return $db->GetOne("select max(".$fieldname.") from ".$this->_table);
  401.         }
  402.         return $val;
  403.     }
  404.     
  405.     // quote data in where clause
  406.     function doquote(&$db$val,$t)
  407.     {
  408.         switch($t{
  409.         case 'D':
  410.         case 'T':
  411.             if (empty($val)) return 'null';
  412.             
  413.         case 'C':
  414.         case 'X':
  415.             if (is_null($val)) return 'null';
  416.             
  417.             if (strncmp($val,"'",1!= && substr($val,strlen($val)-1,1!= "'"
  418.                 return $db->qstr($val);
  419.                 break;
  420.             }
  421.         default:
  422.             return $val;
  423.             break;
  424.         }
  425.     }
  426.     
  427.     // generate where clause for an UPDATE/SELECT
  428.     function GenWhere(&$db&$table)
  429.     {
  430.         $keys $table->keys;
  431.         $parr array();
  432.         
  433.         foreach($keys as $k{
  434.             $f $table->flds[$k];
  435.             if ($f{
  436.                 $parr[$k.' = '.$this->doquote($db,$this->$k,$db->MetaType($f->type));
  437.             }
  438.         }
  439.         return implode(' and '$parr);
  440.     }
  441.     
  442.     
  443.     //------------------------------------------------------------ Public functions below
  444.     
  445.     function Load($where,$bindarr=false)
  446.     {
  447.         $db =$this->DB()if (!$dbreturn false;
  448.         $this->_where = $where;
  449.         
  450.         $save $db->SetFetchMode(ADODB_FETCH_NUM);
  451.         $row $db->GetRow("select * from ".$this->_table.' WHERE '.$where,$bindarr);
  452.         $db->SetFetchMode($save);
  453.         
  454.         return $this->Set($row);
  455.     }
  456.     
  457.     // false on error
  458.     function Save()
  459.     {
  460.         if ($this->_saved$ok $this->Update();
  461.         else $ok $this->Insert();
  462.         
  463.         return $ok;
  464.     }
  465.     
  466.     // false on error
  467.     function Insert()
  468.     {
  469.         $db =$this->DB()if (!$dbreturn false;
  470.         $cnt 0;
  471.         $table =$this->TableInfo();
  472.         
  473.         $valarr array();
  474.         $names array();
  475.         $valstr array();
  476.  
  477.         foreach($table->flds as $name=>$fld{
  478.             $val $this->$name;
  479.             if(!is_null($val|| !array_key_exists($name$table->keys)) {
  480.                 $valarr[$val;
  481.                 $names[$name;
  482.                 $valstr[$db->Param($cnt);
  483.                 $cnt += 1;
  484.             }
  485.         }
  486.         
  487.         if (empty($names)){
  488.             foreach($table->flds as $name=>$fld{
  489.                 $valarr[null;
  490.                 $names[$name;
  491.                 $valstr[$db->Param($cnt);
  492.                 $cnt += 1;
  493.             }
  494.         }
  495.         $sql 'INSERT INTO '.$this->_table."(".implode(',',$names).') VALUES ('.implode(',',$valstr).')';
  496.         $ok $db->Execute($sql,$valarr);
  497.         
  498.         if ($ok{
  499.             $this->_saved = true;
  500.             $autoinc false;
  501.             foreach($table->keys as $k{
  502.                 if (is_null($this->$k)) {
  503.                     $autoinc true;
  504.                     break;
  505.                 }
  506.             }
  507.             if ($autoinc && sizeof($table->keys== 1{
  508.                 $k reset($table->keys);
  509.                 $this->$k $this->LastInsertID($db,$k);
  510.             }
  511.         }
  512.         
  513.         $this->_original = $valarr;
  514.         return !empty($ok);
  515.     }
  516.     
  517.     function Delete()
  518.     {
  519.         $db =$this->DB()if (!$dbreturn false;
  520.         $table =$this->TableInfo();
  521.         
  522.         $where $this->GenWhere($db,$table);
  523.         $sql 'DELETE FROM '.$this->_table.' WHERE '.$where;
  524.         $ok $db->Execute($sql);
  525.         
  526.         return $ok true false;
  527.     }
  528.     
  529.     // returns an array of active record objects
  530.     function &Find($whereOrderBy,$bindarr=false,$pkeysArr=false)
  531.     {
  532.         $db =$this->DB()if (!$db || empty($this->_table)) return false;
  533.         $arr =$db->GetActiveRecordsClass(get_class($this),$this->_table$whereOrderBy,$bindarr,$pkeysArr);
  534.         return $arr;
  535.     }
  536.     
  537.     // returns 0 on error, 1 on update, 2 on insert
  538.     function Replace()
  539.     {
  540.     global $ADODB_ASSOC_CASE;
  541.         
  542.         $db =$this->DB()if (!$dbreturn false;
  543.         $table =$this->TableInfo();
  544.         
  545.         $pkey $table->keys;
  546.         
  547.         foreach($table->flds as $name=>$fld{
  548.             $val $this->$name;
  549.             /*
  550.             if (is_null($val)) {
  551.                 if (isset($fld->not_null) && $fld->not_null) {
  552.                     if (isset($fld->default_value) && strlen($fld->default_value)) continue;
  553.                     else {
  554.                         $this->Error("Cannot update null into $name","Replace");
  555.                         return false;
  556.                     }
  557.                 }
  558.             }*/
  559.             if (is_null($val&& !empty($fld->auto_increment)) {
  560.                 continue;
  561.             }
  562.             $t $db->MetaType($fld->type);
  563.             $arr[$name$this->doquote($db,$val,$t);
  564.             $valarr[$val;
  565.         }
  566.         
  567.         if (!is_array($pkey)) $pkey array($pkey);
  568.         
  569.         
  570.         if ($ADODB_ASSOC_CASE == 0
  571.             foreach($pkey as $k => $v)
  572.                 $pkey[$kstrtolower($v);
  573.         elseif ($ADODB_ASSOC_CASE == 1
  574.             foreach($pkey as $k => $v)
  575.                 $pkey[$kstrtoupper($v);
  576.                 
  577.         $ok $db->Replace($this->_table,$arr,$pkey);
  578.         if ($ok{
  579.             $this->_saved = true// 1= update 2=insert
  580.             if ($ok == 2{
  581.                 $autoinc false;
  582.                 foreach($table->keys as $k{
  583.                     if (is_null($this->$k)) {
  584.                         $autoinc true;
  585.                         break;
  586.                     }
  587.                 }
  588.                 if ($autoinc && sizeof($table->keys== 1{
  589.                     $k reset($table->keys);
  590.                     $this->$k $this->LastInsertID($db,$k);
  591.                 }
  592.             }
  593.             
  594.             $this->_original =$valarr;
  595.         
  596.         return $ok;
  597.     }
  598.  
  599.     // returns 0 on error, 1 on update, -1 if no change in data (no update)
  600.     function Update()
  601.     {
  602.         $db =$this->DB()if (!$dbreturn false;
  603.         $table =$this->TableInfo();
  604.         
  605.         $where $this->GenWhere($db$table);
  606.         
  607.         if (!$where{
  608.             $this->error("Where missing for table $table""Update");
  609.             return false;
  610.         }
  611.         $valarr array()
  612.         $neworig array();
  613.         $pairs array();
  614.         $i = -1;
  615.         $cnt 0;
  616.         foreach($table->flds as $name=>$fld{
  617.             $i += 1;
  618.             $val $this->$name;
  619.             $neworig[$val;
  620.             
  621.             if (isset($table->keys[$name])) {
  622.                 continue;
  623.             }
  624.             
  625.             if (is_null($val)) {
  626.                 if (isset($fld->not_null&& $fld->not_null{
  627.                     if (isset($fld->default_value&& strlen($fld->default_value)) continue;
  628.                     else {
  629.                         $this->Error("Cannot set field $name to NULL","Update");
  630.                         return false;
  631.                     }
  632.                 }
  633.             }
  634.             
  635.             if (isset($this->_original[$i]&& $val == $this->_original[$i]{
  636.                 continue;
  637.             }            
  638.             $valarr[$val;
  639.             $pairs[$name.'='.$db->Param($cnt);
  640.             $cnt += 1;
  641.         }
  642.         
  643.         
  644.         if (!$cntreturn -1;
  645.         $sql 'UPDATE '.$this->_table." SET ".implode(",",$pairs)." WHERE ".$where;
  646.         $ok $db->Execute($sql,$valarr);
  647.         if ($ok{
  648.             $this->_original =$neworig;
  649.             return 1;
  650.         }
  651.         return 0;
  652.     }
  653.     
  654.     function GetAttributeNames()
  655.     {
  656.         $table =$this->TableInfo();
  657.         if (!$tablereturn false;
  658.         return array_keys($table->flds);
  659.     }
  660.     
  661. };
  662.  
  663. ?>

Documentation generated on Fri, 18 Jul 2008 21:38:54 +0200 by phpDocumentor 1.4.1