dbo_adodb.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: dbo__adodb_8php-source.html 675 2008-12-26 00:27:14Z gwoo $ */
00003 
00004 /**
00005  * AdoDB layer for DBO.
00006  *
00007  * Long description for file
00008  *
00009  * PHP versions 4 and 5
00010  *
00011  * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
00012  * Copyright 2005-2008, Cake Software Foundation, Inc.
00013  *                              1785 E. Sahara Avenue, Suite 490-204
00014  *                              Las Vegas, Nevada 89104
00015  *
00016  * Licensed under The MIT License
00017  * Redistributions of files must retain the above copyright notice.
00018  *
00019  * @filesource
00020  * @copyright       Copyright 2005-2008, Cake Software Foundation, Inc.
00021  * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00022  * @package         cake
00023  * @subpackage      cake.cake.libs.model.dbo
00024  * @since           CakePHP(tm) v 0.2.9
00025  * @version         $Revision: 675 $
00026  * @modifiedby      $LastChangedBy: gwoo $
00027  * @lastmodified    $Date: 2008-12-25 16:27:14 -0800 (Thu, 25 Dec 2008) $
00028  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00029  */
00030 
00031 /**
00032  * Include AdoDB files.
00033  */
00034 vendor ('adodb' . DS . 'adodb.inc');
00035 
00036 /**
00037  * AdoDB DBO implementation.
00038  *
00039  * Database abstraction implementation for the AdoDB library.
00040  *
00041  * @package     cake
00042  * @subpackage  cake.cake.libs.model.dbo
00043  */
00044 class DboAdodb extends DboSource {
00045 /**
00046  * Enter description here...
00047  *
00048  * @var string
00049  */
00050      var $description = "ADOdb DBO Driver";
00051 
00052 /**
00053  * ADOConnection object with which we connect.
00054  *
00055  * @var ADOConnection The connection object.
00056  * @access private
00057  */
00058      var $_adodb = null;
00059 
00060 /**
00061  * Array translating ADOdb column MetaTypes to cake-supported metatypes
00062  *
00063  * @var array
00064  * @access private
00065  */
00066      var $_adodb_column_types = array(
00067         'C' => 'string',
00068         'X' => 'text',
00069         'D' => 'date',
00070         'T' => 'timestamp',
00071         'L' => 'boolean',
00072         'N' => 'float',
00073         'I' => 'integer',
00074         'R' => 'integer', // denotes auto-increment or counter field
00075         'B' => 'binary'
00076     );
00077 
00078 /**
00079  * Connects to the database using options in the given configuration array.
00080  *
00081  * @param array $config Configuration array for connecting
00082  */
00083      function connect() {
00084         $config = $this->config;
00085         $persistent = strrpos($config['connect'], '|p');
00086 
00087         if ($persistent === false) {
00088             $adodb_driver = $config['connect'];
00089             $connect = 'Connect';
00090         } else {
00091             $adodb_driver = substr($config['connect'], 0, $persistent);
00092             $connect = 'PConnect';
00093         }
00094 
00095         $this->_adodb = NewADOConnection($adodb_driver);
00096 
00097         $this->startQuote = $this->_adodb->nameQuote;
00098         $this->endQuote = $this->_adodb->nameQuote;
00099 
00100         $this->connected = $this->_adodb->$connect($config['host'], $config['login'], $config['password'], $config['database']);
00101         return $this->connected;
00102     }
00103 /**
00104  * Disconnects from database.
00105  *
00106  * @return boolean True if the database could be disconnected, else false
00107  */
00108      function disconnect() {
00109           return $this->_adodb->Close();
00110      }
00111 /**
00112  * Executes given SQL statement.
00113  *
00114  * @param string $sql SQL statement
00115  * @return resource Result resource identifier
00116  */
00117     function _execute($sql) {
00118         global $ADODB_FETCH_MODE;
00119         $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC;
00120         return $this->_adodb->execute($sql);
00121     }
00122 /**
00123  * Returns a row from given resultset as an array .
00124  *
00125  * @return array The fetched row as an array
00126  */
00127 /**
00128  * Returns a row from current resultset as an array .
00129  *
00130  * @return array The fetched row as an array
00131  */
00132     function fetchRow($sql = null) {
00133 
00134         if (!empty($sql) && is_string($sql) && strlen($sql) > 5) {
00135             if (!$this->execute($sql)) {
00136                 return null;
00137             }
00138         }
00139 
00140         if (!is_object($this->_result) || $this->_result->EOF) {
00141             return null;
00142         } else {
00143             $resultRow = $this->_result->FetchRow();
00144             $this->resultSet($resultRow);
00145             return $this->fetchResult();
00146         }
00147     }
00148 /**
00149  * Begin a transaction
00150  *
00151  * @param unknown_type $model
00152  * @return boolean True on success, false on fail
00153  * (i.e. if the database/model does not support transactions).
00154  */
00155     function begin(&$model) {
00156         if (parent::begin($model)) {
00157             if ($this->_adodb->BeginTrans()) {
00158                 $this->_transactionStarted = true;
00159                 return true;
00160             }
00161         }
00162         return false;
00163     }
00164 /**
00165  * Commit a transaction
00166  *
00167  * @param unknown_type $model
00168  * @return boolean True on success, false on fail
00169  * (i.e. if the database/model does not support transactions,
00170  * or a transaction has not started).
00171  */
00172     function commit(&$model) {
00173         if (parent::commit($model)) {
00174             $this->_transactionStarted = false;
00175             return $this->_adodb->CommitTrans();
00176         }
00177         return false;
00178     }
00179 /**
00180  * Rollback a transaction
00181  *
00182  * @param unknown_type $model
00183  * @return boolean True on success, false on fail
00184  * (i.e. if the database/model does not support transactions,
00185  * or a transaction has not started).
00186  */
00187     function rollback(&$model) {
00188         if (parent::rollback($model)) {
00189             return $this->_adodb->RollbackTrans();
00190         }
00191         return false;
00192     }
00193 /**
00194  * Returns an array of tables in the database. If there are no tables, an error is raised and the application exits.
00195  *
00196  * @return array Array of tablenames in the database
00197  */
00198     function listSources() {
00199         $tables = $this->_adodb->MetaTables('TABLES');
00200 
00201           if (!sizeof($tables) > 0) {
00202                 trigger_error(ERROR_NO_TABLE_LIST, E_USER_NOTICE);
00203                 exit;
00204           }
00205 
00206           return $tables;
00207      }
00208 /**
00209  * Returns an array of the fields in the table used by the given model.
00210  *
00211  * @param AppModel $model Model object
00212  * @return array Fields in table. Keys are name and type
00213  */
00214     function describe(&$model) {
00215         $cache = parent::describe($model);
00216         if ($cache != null) {
00217             return $cache;
00218         }
00219 
00220         $fields = false;
00221         $cols = $this->_adodb->MetaColumns($this->fullTableName($model, false));
00222 
00223         foreach ($cols as $column) {
00224             $fields[$column->name] = array(
00225                                         'type' => $this->column($column->type)
00226                                     );
00227         }
00228 
00229         $this->__cacheDescription($this->fullTableName($model, false), $fields);
00230         return $fields;
00231     }
00232 /**
00233  * Returns a formatted error message from previous database operation.
00234  *
00235  * @return string Error message
00236  */
00237     function lastError() {
00238         return $this->_adodb->ErrorMsg();
00239     }
00240 /**
00241  * Returns number of affected rows in previous database operation, or false if no previous operation exists.
00242  *
00243  * @return int Number of affected rows
00244  */
00245     function lastAffected() {
00246         return $this->_adodb->Affected_Rows();
00247     }
00248 /**
00249  * Returns number of rows in previous resultset, or false if no previous resultset exists.
00250  *
00251  * @return int Number of rows in resultset
00252  */
00253     function lastNumRows() {
00254         return $this->_result ? $this->_result->RecordCount() : false;
00255     }
00256 /**
00257  * Returns the ID generated from the previous INSERT operation.
00258  *
00259  * @return int
00260  *
00261  * @Returns the last autonumbering ID inserted. Returns false if function not supported.
00262  */
00263      function lastInsertId() {
00264           return $this->_adodb->Insert_ID();
00265      }
00266 
00267 /**
00268  * Returns a LIMIT statement in the correct format for the particular database.
00269  *
00270  * @param int $limit Limit of results returned
00271  * @param int $offset Offset from which to start results
00272  * @return string SQL limit/offset statement
00273  * @todo Please change output string to whatever select your database accepts. adodb doesn't allow us to get the correct limit string out of it.
00274  */
00275      function limit($limit, $offset = null) {
00276         if (empty($limit)) {
00277             return null;
00278         }
00279         return " LIMIT {$limit}" . ($offset ? "{$offset}" : null);
00280      // please change to whatever select your database accepts
00281      // adodb doesn't allow us to get the correct limit string out of it
00282      }
00283 
00284 /**
00285  * Converts database-layer column types to basic types
00286  *
00287  * @param string $real Real database-layer column type (i.e. "varchar(255)")
00288  * @return string Abstract column type (i.e. "string")
00289  */
00290     function column($real) {
00291         if (isset($this->_result)) {
00292             $adodb_metatyper = &$this->_result;
00293         } else {
00294             $adodb_metatyper = &$this->_adodb->execute('Select 1');
00295         }
00296 
00297         $interpreted_type = $adodb_metatyper->MetaType($real);
00298         if (!isset($this->_adodb_column_types[$interpreted_type])) {
00299             return 'text';
00300         }
00301 
00302         return $this->_adodb_column_types[$interpreted_type];
00303     }
00304 /**
00305  * Returns a quoted and escaped string of $data for use in an SQL statement.
00306  *
00307  * @param string $data String to be prepared for use in an SQL statement
00308  * @param string $column_type The type of the column into which this data will be inserted
00309  * @param boolean $safe Whether or not numeric data should be handled automagically if no column data is provided
00310  * @return string Quoted and escaped data
00311  */
00312     function value($data, $column = null, $safe = false) {
00313         $parent = parent::value($data, $column, $safe);
00314         if ($parent != null) {
00315             return $parent;
00316         }
00317 
00318         if ($data === null) {
00319             return 'NULL';
00320         }
00321 
00322         if ($data === '') {
00323             return "''";
00324         }
00325         return $this->_adodb->qstr($data);
00326     }
00327 /**
00328  * Generates the fields list of an SQL query.
00329  *
00330  * @param Model $model
00331  * @param string $alias Alias tablename
00332  * @param mixed $fields
00333  * @return array
00334  */
00335     function fields(&$model, $alias = null, $fields = null, $quote = true) {
00336         if (empty($alias)) {
00337             $alias = $model->name;
00338         }
00339 
00340         if (!is_array($fields)) {
00341             if ($fields != null) {
00342                 if (strpos($fields, ',')) {
00343                     $fields = explode(',', $fields);
00344                 } else {
00345                     $fields = array($fields);
00346                 }
00347                 $fields = array_map('trim', $fields);
00348             } else {
00349                 foreach ($model->_tableInfo->value as $field) {
00350                     $fields[] = $field['name'];
00351                 }
00352             }
00353         }
00354 
00355         $count = count($fields);
00356 
00357         if ($count >= 1 && $fields[0] != '*' && strpos($fields[0], 'COUNT(*)') === false) {
00358             for ($i = 0; $i < $count; $i++) {
00359                 if (!preg_match('/^.+\\(.*\\)/', $fields[$i])) {
00360                     $prepend = '';
00361                     if (strpos($fields[$i], 'DISTINCT') !== false) {
00362                         $prepend = 'DISTINCT ';
00363                         $fields[$i] = trim(r('DISTINCT', '', $fields[$i]));
00364                     }
00365 
00366                     $dot = strrpos($fields[$i], '.');
00367                     if ($dot === false) {
00368                         $fields[$i] = $prepend . $this->name($alias) . '.' . $this->name($fields[$i]) . ' AS ' . $this->name($alias . '__' . $fields[$i]);
00369                     } else {
00370                         $build = explode('.', $fields[$i]);
00371                         $fields[$i] = $prepend . $this->name($build[0]) . '.' . $this->name($build[1]) . ' AS ' . $this->name($build[0] . '__' . $build[1]);
00372                     }
00373                 }
00374             }
00375         }
00376         return $fields;
00377     }
00378 /**
00379  * Enter description here...
00380  *
00381  * @param unknown_type $results
00382  */
00383     function resultSet(&$results) {
00384         $num_fields = count($results);
00385         $fields = array_keys($results);
00386         $this->results =& $results;
00387         $this->map = array();
00388         $index = 0;
00389         $j = 0;
00390 
00391         while ($j < $num_fields) {
00392             $columnName = $fields[$j];
00393 
00394             if (strpos($columnName, '__')) {
00395                 $parts = explode('__', $columnName);
00396                 $this->map[$index++] = array($parts[0], $parts[1]);
00397             } else {
00398                 $this->map[$index++] = array(0, $columnName);
00399             }
00400             $j++;
00401         }
00402     }
00403 /**
00404  * Fetches the next row from the current result set
00405  *
00406  * @return unknown
00407  */
00408     function fetchResult() {
00409         if (!empty($this->results) && $row = $this->results) {
00410             $resultRow = array();
00411             $fields = array_keys($row);
00412             $count = count($fields);
00413             $i = 0;
00414             for ($i = 0; $i < $count; $i++) { //$row as $index => $field) {
00415                 list($table, $column) = $this->map[$i];
00416                 $resultRow[$table][$column] = $row[$fields[$i]];
00417             }
00418             return $resultRow;
00419         } else {
00420             return false;
00421         }
00422     }
00423 /**
00424  * Inserts multiple values into a join table
00425  *
00426  * @param string $table
00427  * @param string $fields
00428  * @param array $values
00429  */
00430     function insertMulti($table, $fields, $values) {
00431         $count = count($values);
00432         for ($x = 0; $x < $count; $x++) {
00433             $this->query("INSERT INTO {$table} ({$fields}) VALUES {$values[$x]}");
00434         }
00435     }
00436 }
00437 ?>