datasource.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: datasource_8php-source.html 580 2008-07-01 14:45:49Z gwoo $ */
00003 /**
00004  * DataSource base class
00005  *
00006  * Long description for file
00007  *
00008  * PHP versions 4 and 5
00009  *
00010  * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
00011  * Copyright 2005-2008, Cake Software Foundation, Inc.
00012  *                              1785 E. Sahara Avenue, Suite 490-204
00013  *                              Las Vegas, Nevada 89104
00014  *
00015  * Licensed under The MIT License
00016  * Redistributions of files must retain the above copyright notice.
00017  *
00018  * @filesource
00019  * @copyright       Copyright 2005-2008, Cake Software Foundation, Inc.
00020  * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00021  * @package         cake
00022  * @subpackage      cake.cake.libs.model.datasources
00023  * @since           CakePHP(tm) v 0.10.5.1790
00024  * @version         $Revision: 580 $
00025  * @modifiedby      $LastChangedBy: gwoo $
00026  * @lastmodified    $Date: 2008-07-01 09:45:49 -0500 (Tue, 01 Jul 2008) $
00027  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00028  */
00029 /**
00030  * DataSource base class
00031  *
00032  * Long description for file
00033  *
00034  * @package     cake
00035  * @subpackage  cake.cake.libs.model.datasources
00036  */
00037 class DataSource extends Object {
00038 /**
00039  * Are we connected to the DataSource?
00040  *
00041  * @var boolean
00042  * @access public
00043  */
00044     var $connected = false;
00045 /**
00046  * Print full query debug info?
00047  *
00048  * @var boolean
00049  * @access public
00050  */
00051     var $fullDebug = false;
00052 /**
00053  * Error description of last query
00054  *
00055  * @var unknown_type
00056  * @access public
00057  */
00058     var $error = null;
00059 /**
00060  * String to hold how many rows were affected by the last SQL operation.
00061  *
00062  * @var string
00063  * @access public
00064  */
00065     var $affected = null;
00066 /**
00067  * Number of rows in current resultset
00068  *
00069  * @var int
00070  * @access public
00071  */
00072     var $numRows = null;
00073 /**
00074  * Time the last query took
00075  *
00076  * @var int
00077  * @access public
00078  */
00079     var $took = null;
00080 /**
00081  * Enter description here...
00082  *
00083  * @var array
00084  * @access private
00085  */
00086     var $_result = null;
00087 /**
00088  * Queries count.
00089  *
00090  * @var int
00091  * @access private
00092  */
00093     var $_queriesCnt = 0;
00094 /**
00095  * Total duration of all queries.
00096  *
00097  * @var unknown_type
00098  * @access private
00099  */
00100     var $_queriesTime = null;
00101 /**
00102  * Log of queries executed by this DataSource
00103  *
00104  * @var unknown_type
00105  * @access private
00106  */
00107     var $_queriesLog = array();
00108 /**
00109  * Maximum number of items in query log, to prevent query log taking over
00110  * too much memory on large amounts of queries -- I we've had problems at
00111  * >6000 queries on one system.
00112  *
00113  * @var int Maximum number of queries in the queries log.
00114  * @access private
00115  */
00116     var $_queriesLogMax = 200;
00117 /**
00118  * Caches serialzed results of executed queries
00119  *
00120  * @var array Maximum number of queries in the queries log.
00121  * @access private
00122  */
00123     var $_queryCache = array();
00124 /**
00125  * The default configuration of a specific DataSource
00126  *
00127  * @var array
00128  * @access public
00129  */
00130     var $_baseConfig = array();
00131 /**
00132  * Holds references to descriptions loaded by the DataSource
00133  *
00134  * @var array
00135  * @access private
00136  */
00137     var $__descriptions = array();
00138 /**
00139  * Holds a list of sources (tables) contained in the DataSource
00140  *
00141  * @var array
00142  * @access protected
00143  */
00144     var $_sources = null;
00145 /**
00146  * A reference to the physical connection of this DataSource
00147  *
00148  * @var array
00149  * @access public
00150  */
00151     var $connection = null;
00152 /**
00153  * The DataSource configuration
00154  *
00155  * @var array
00156  * @access public
00157  */
00158     var $config = array();
00159 /**
00160  * The DataSource configuration key name
00161  *
00162  * @var string
00163  * @access public
00164  */
00165     var $configKeyName = null;
00166 /**
00167  * Whether or not this DataSource is in the middle of a transaction
00168  *
00169  * @var boolean
00170  * @access protected
00171  */
00172     var $_transactionStarted = false;
00173 /**
00174  * Whether or not source data like available tables and schema descriptions
00175  * should be cached
00176  *
00177  * @var boolean
00178  */
00179     var $cacheSources = true;
00180 /**
00181  * Constructor.
00182  */
00183     function __construct() {
00184         parent::__construct();
00185         if (func_num_args() > 0) {
00186             $this->setConfig(func_get_arg(0));
00187         }
00188     }
00189 /**
00190  * Caches/returns cached results for child instances
00191  *
00192  * @return array
00193  */
00194     function listSources($data = null) {
00195         if ($this->cacheSources === false) {
00196             return null;
00197         }
00198         if ($this->_sources != null) {
00199             return $this->_sources;
00200         }
00201 
00202         if (Configure::read() > 0) {
00203             $expires = "+30 seconds";
00204         } else {
00205             $expires = "+999 days";
00206         }
00207 
00208         $key = ConnectionManager::getSourceName($this) . '_' . Inflector::slug($this->config['database']) . '_list';
00209         $sources = Cache::read($key, '_cake_model_');
00210 
00211         if ($sources == null) {
00212             $sources = $data;
00213             Cache::write($key, $data, array('duration' => $expires, 'config' => '_cake_model_'));
00214         }
00215 
00216         $this->_sources = $sources;
00217         return $sources;
00218     }
00219 /**
00220  * Convenience method for DboSource::listSources().  Returns source names in lowercase.
00221  *
00222  * @return array
00223  */
00224     function sources() {
00225         $return = array_map('strtolower', $this->listSources());
00226         return $return;
00227     }
00228 /**
00229  * Returns a Model description (metadata) or null if none found.
00230  *
00231  * @param Model $model
00232  * @return mixed
00233  */
00234     function describe($model) {
00235         if ($this->cacheSources === false) {
00236             return null;
00237         }
00238         if (isset($this->__descriptions[$model->tablePrefix . $model->table])) {
00239             return $this->__descriptions[$model->tablePrefix . $model->table];
00240         }
00241         $cache = $this->__cacheDescription($model->tablePrefix . $model->table);
00242 
00243         if ($cache !== null) {
00244             $this->__descriptions[$model->tablePrefix . $model->table] =& $cache;
00245             return $cache;
00246         }
00247         return null;
00248     }
00249 /**
00250  * Begin a transaction
00251  *
00252  * @return boolean Returns true if a transaction is not in progress
00253  */
00254     function begin(&$model) {
00255         return !$this->_transactionStarted;
00256     }
00257 /**
00258  * Commit a transaction
00259  *
00260  * @return boolean Returns true if a transaction is in progress
00261  */
00262     function commit(&$model) {
00263         return $this->_transactionStarted;
00264     }
00265 /**
00266  * Rollback a transaction
00267  *
00268  * @return boolean Returns true if a transaction is in progress
00269  */
00270     function rollback(&$model) {
00271         return $this->_transactionStarted;
00272     }
00273 /**
00274  * Converts column types to basic types
00275  *
00276  * @param string $real Real  column type (i.e. "varchar(255)")
00277  * @return string Abstract column type (i.e. "string")
00278  */
00279     function column($real) {
00280         return false;
00281     }
00282 /**
00283  * To-be-overridden in subclasses.
00284  *
00285  * @param unknown_type $model
00286  * @param unknown_type $fields
00287  * @param unknown_type $values
00288  * @return unknown
00289  */
00290     function create(&$model, $fields = null, $values = null) {
00291         return false;
00292     }
00293 /**
00294  * To-be-overridden in subclasses.
00295  *
00296  * @param unknown_type $model
00297  * @param unknown_type $queryData
00298  * @return unknown
00299  */
00300     function read(&$model, $queryData = array()) {
00301         return false;
00302     }
00303 /**
00304  * To-be-overridden in subclasses.
00305  *
00306  * @param unknown_type $model
00307  * @param unknown_type $fields
00308  * @param unknown_type $values
00309  * @return unknown
00310  */
00311     function update(&$model, $fields = null, $values = null) {
00312         return false;
00313     }
00314 /**
00315  * To-be-overridden in subclasses.
00316  *
00317  * @param unknown_type $model
00318  * @param unknown_type $id
00319  */
00320     function delete(&$model, $id = null) {
00321         if ($id == null) {
00322             $id = $model->id;
00323         }
00324     }
00325 /**
00326  * Returns the ID generated from the previous INSERT operation.
00327  *
00328  * @param unknown_type $source
00329  * @return in
00330  */
00331     function lastInsertId($source = null) {
00332         return false;
00333     }
00334 /**
00335  * Returns the ID generated from the previous INSERT operation.
00336  *
00337  * @param unknown_type $source
00338  * @return in
00339  */
00340     function lastNumRows($source = null) {
00341         return false;
00342     }
00343 /**
00344  * Returns the ID generated from the previous INSERT operation.
00345  *
00346  * @param unknown_type $source
00347  * @return in
00348  */
00349     function lastAffected($source = null) {
00350         return false;
00351     }
00352 /**
00353  * Returns true if the DataSource supports the given interface (method)
00354  *
00355  * @param string $interface The name of the interface (method)
00356  * @return boolean True on success
00357  */
00358     function isInterfaceSupported($interface) {
00359         $methods = get_class_methods(get_class($this));
00360         $methods = strtolower(implode('|', $methods));
00361         $methods = explode('|', $methods);
00362         $return = in_array(strtolower($interface), $methods);
00363         return $return;
00364     }
00365 /**
00366  * Sets the configuration for the DataSource
00367  *
00368  * @param array $config The configuration array
00369  */
00370     function setConfig($config) {
00371         if (is_array($this->_baseConfig)) {
00372             $this->config = $this->_baseConfig;
00373             foreach ($config as $key => $val) {
00374                 $this->config[$key] = $val;
00375             }
00376         }
00377     }
00378 /**
00379  * Cache the DataSource description
00380  *
00381  * @param string $object The name of the object (model) to cache
00382  * @param mixed $data The description of the model, usually a string or array
00383  */
00384     function __cacheDescription($object, $data = null) {
00385         if ($this->cacheSources === false) {
00386             return null;
00387         }
00388         if (Configure::read() > 0) {
00389             $expires = "+15 seconds";
00390         } else {
00391             $expires = "+999 days";
00392         }
00393 
00394         if ($data !== null) {
00395             $this->__descriptions[$object] =& $data;
00396         }
00397 
00398         $key = ConnectionManager::getSourceName($this) . '_' . $object;
00399         $cache = Cache::read($key, '_cake_model_');
00400 
00401         if (empty($cache)) {
00402             $cache = $data;
00403             Cache::write($key, $cache, array('duration' => $expires, 'config' => '_cake_model_'));
00404         }
00405 
00406         return $cache;
00407     }
00408 /**
00409  * Enter description here...
00410  *
00411  * @param unknown_type $query
00412  * @param unknown_type $data
00413  * @param unknown_type $association
00414  * @param unknown_type $assocData
00415  * @param Model $model
00416  * @param Model $linkModel
00417  * @param array $stack
00418  * @return unknown
00419  */
00420     function insertQueryData($query, $data, $association, $assocData, &$model, &$linkModel, $stack) {
00421         $keys = array('{$__cakeID__$}', '{$__cakeForeignKey__$}');
00422 
00423         foreach ($keys as $key) {
00424             $val = null;
00425 
00426             if (strpos($query, $key) !== false) {
00427                 switch($key) {
00428                     case '{$__cakeID__$}':
00429                         if (isset($data[$model->alias]) || isset($data[$association])) {
00430                             if (isset($data[$model->alias][$model->primaryKey])) {
00431                                 $val = $data[$model->alias][$model->primaryKey];
00432                             } elseif (isset($data[$association][$model->primaryKey])) {
00433                                 $val = $data[$association][$model->primaryKey];
00434                             }
00435                         } else {
00436                             $found = false;
00437                             foreach (array_reverse($stack) as $assoc) {
00438                                 if (isset($data[$assoc]) && isset($data[$assoc][$model->primaryKey])) {
00439                                     $val = $data[$assoc][$model->primaryKey];
00440                                     $found = true;
00441                                     break;
00442                                 }
00443                             }
00444                             if (!$found) {
00445                                 $val = '';
00446                             }
00447                         }
00448                     break;
00449                     case '{$__cakeForeignKey__$}':
00450                         foreach ($model->__associations as $id => $name) {
00451                             foreach ($model->$name as $assocName => $assoc) {
00452                                 if ($assocName === $association) {
00453                                     if (isset($assoc['foreignKey'])) {
00454                                         $foreignKey = $assoc['foreignKey'];
00455 
00456                                         if (isset($data[$model->alias][$foreignKey])) {
00457                                             $val = $data[$model->alias][$foreignKey];
00458                                         } elseif (isset($data[$association][$foreignKey])) {
00459                                             $val = $data[$association][$foreignKey];
00460                                         } else {
00461                                             $found = false;
00462                                             foreach (array_reverse($stack) as $assoc) {
00463                                                 if (isset($data[$assoc]) && isset($data[$assoc][$foreignKey])) {
00464                                                     $val = $data[$assoc][$foreignKey];
00465                                                     $found = true;
00466                                                     break;
00467                                                 }
00468                                             }
00469                                             if (!$found) {
00470                                                 $val = '';
00471                                             }
00472                                         }
00473                                     }
00474                                     break 3;
00475                                 }
00476                             }
00477                         }
00478                     break;
00479                 }
00480                 if (empty($val) && $val !== '0') {
00481                     return false;
00482                 }
00483                 $query = str_replace($key, $this->value($val, $model->getColumnType($model->primaryKey)), $query);
00484             }
00485         }
00486         return $query;
00487     }
00488 /**
00489  * To-be-overridden in subclasses.
00490  *
00491  * @param unknown_type $model
00492  * @param unknown_type $key
00493  * @return unknown
00494  */
00495     function resolveKey($model, $key) {
00496         return $model->alias . $key;
00497     }
00498 /**
00499  * Closes the current datasource.
00500  *
00501  */
00502     function __destruct() {
00503         if ($this->_transactionStarted) {
00504             $null = null;
00505             $this->rollback($null);
00506         }
00507         if ($this->connected) {
00508             $this->close();
00509         }
00510     }
00511 }
00512 ?>