model_php5.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: model__php5_8php-source.html 691 2010-01-30 00:05:51Z predominant $ */
00003 /**
00004  * Object-relational mapper.
00005  *
00006  * DBO-backed object data model, for mapping database tables to Cake objects.
00007  *
00008  * PHP versions 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
00023  * @since           CakePHP(tm) v 0.10.0.0
00024  * @version         $Revision: 691 $
00025  * @modifiedby      $LastChangedBy: predominant $
00026  * @lastmodified    $Date: 2010-01-29 18:05:51 -0600 (Fri, 29 Jan 2010) $
00027  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00028  */
00029 /**
00030  * Included libs
00031  */
00032 uses('class_registry', 'validators', 'model' . DS . 'connection_manager', 'set');
00033 /**
00034  * Object-relational mapper.
00035  *
00036  * DBO-backed object data model.
00037  * Automatically selects a database table name based on a pluralized lowercase object class name
00038  * (i.e. class 'User' => table 'users'; class 'Man' => table 'men')
00039  * The table is required to have at least 'id auto_increment', 'created datetime',
00040  * and 'modified datetime' fields.
00041  *
00042  * @package     cake
00043  * @subpackage  cake.cake.libs.model
00044  */
00045 class Model extends Object{
00046 /**
00047  * The name of the DataSource connection that this Model uses
00048  *
00049  * @var string
00050  * @access public
00051  */
00052     var $useDbConfig = 'default';
00053 /**
00054  * Custom database table name.
00055  *
00056  * @var string
00057  * @access public
00058  */
00059     var $useTable = null;
00060 /**
00061  * Custom display field name. Display fields are used by Scaffold, in SELECT boxes' OPTION elements.
00062  *
00063  * @var string
00064  * @access public
00065  */
00066     var $displayField = null;
00067 
00068 /**
00069  * Value of the primary key ID of the record that this model is currently pointing to
00070  *
00071  * @var string
00072  * @access public
00073  */
00074     var $id = false;
00075 /**
00076  * Container for the data that this model gets from persistent storage (the database).
00077  *
00078  * @var array
00079  * @access public
00080  */
00081     var $data = array();
00082 /**
00083  * Table name for this Model.
00084  *
00085  * @var string
00086  * @access public
00087  */
00088     var $table = false;
00089 /**
00090  * The name of the ID field for this Model.
00091  *
00092  * @var string
00093  * @access public
00094  */
00095     var $primaryKey = null;
00096 /**
00097  * Table metadata
00098  *
00099  * @var array
00100  * @access protected
00101  */
00102     var $_tableInfo = null;
00103 /**
00104  * List of validation rules. Append entries for validation as ('field_name' => '/^perl_compat_regexp$/')
00105  * that have to match with preg_match(). Use these rules with Model::validate()
00106  *
00107  * @var array
00108  * @access public
00109  */
00110     var $validate = array();
00111 /**
00112  * Errors in validation
00113  * @var array
00114  * @access public
00115  */
00116     var $validationErrors = array();
00117 /**
00118  * Database table prefix for tables in model.
00119  *
00120  * @var string
00121  * @access public
00122  */
00123     var $tablePrefix = null;
00124 /**
00125  * Name of the model.
00126  *
00127  * @var string
00128  * @access public
00129  */
00130     var $name = null;
00131 /**
00132  * Name of the current model.
00133  *
00134  * @var string
00135  * @access public
00136  */
00137     var $currentModel = null;
00138 /**
00139  * List of table names included in the Model description. Used for associations.
00140  *
00141  * @var array
00142  * @access public
00143  */
00144     var $tableToModel = array();
00145 /**
00146  * List of Model names by used tables. Used for associations.
00147  *
00148  * @var array
00149  * @access public
00150  */
00151     var $modelToTable = array();
00152 /**
00153  * List of Foreign Key names to used tables. Used for associations.
00154  *
00155  * @var array
00156  * @access public
00157  */
00158     var $keyToTable = array();
00159 /**
00160  * Alias name for model.
00161  *
00162  * @var array
00163  * @access public
00164  */
00165     var $alias = null;
00166 /**
00167  * Whether or not transactions for this model should be logged
00168  *
00169  * @var boolean
00170  * @access public
00171  */
00172     var $logTransactions = false;
00173 /**
00174  * Whether or not to enable transactions for this model (i.e. BEGIN/COMMIT/ROLLBACK)
00175  *
00176  * @var boolean
00177  * @access public
00178  */
00179     var $transactional = false;
00180 /**
00181  * Whether or not to cache queries for this model.  This enables in-memory
00182  * caching only, the results are not stored beyond this execution.
00183  *
00184  * @var boolean
00185  * @access public
00186  */
00187     var $cacheQueries = true;
00188 /**
00189  * belongsTo association
00190  *
00191  * @var array
00192  * @access public
00193  */
00194     var $belongsTo = array();
00195 /**
00196  * hasOne association
00197  *
00198  * @var array
00199  * @access public
00200  */
00201     var $hasOne = array();
00202 /**
00203  * hasMany association
00204  *
00205  * @var array
00206  * @access public
00207  */
00208     var $hasMany = array();
00209 /**
00210  * hasAndBelongsToMany association
00211  *
00212  * @var array
00213  * @access public
00214  */
00215     var $hasAndBelongsToMany = array();
00216 /**
00217  * Depth of recursive association
00218  *
00219  * @var int
00220  * @access public
00221  */
00222     var $recursive = 1;
00223 /**
00224  * Whitelist of fields allowed to be saved
00225  *
00226  * @var array
00227  */
00228     var $whitelist = array();
00229 /**
00230  * Enter description here...
00231  *
00232  * @var boolean
00233  */
00234     var $cacheSources = true;
00235 /**
00236  * Default association keys
00237  *
00238  * @var array
00239  * @access private
00240  */
00241     var $__associationKeys = array('belongsTo' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'counterCache'),
00242                                                 'hasOne' => array('className', 'foreignKey','conditions', 'fields','order', 'dependent'),
00243                                                 'hasMany' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'dependent', 'exclusive', 'finderQuery', 'counterQuery'),
00244                                                 'hasAndBelongsToMany' => array('className', 'joinTable', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery'));
00245 /**
00246  * Holds provided/generated association key names and other data for all associations
00247  *
00248  * @var array
00249  * @access private
00250  */
00251     var $__associations = array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany');
00252 /**
00253  * The last inserted ID of the data that this model created
00254  *
00255  * @var int
00256  * @access private
00257  */
00258     var $__insertID = null;
00259 /**
00260  * The number of records returned by the last query
00261  *
00262  * @var int
00263  * @access private
00264  */
00265     var $__numRows = null;
00266 /**
00267  * The number of records affected by the last query
00268  *
00269  * @var int
00270  * @access private
00271  */
00272     var $__affectedRows = null;
00273 /**
00274  * Holds model associations temporarily to allow for dynamic (un)binding
00275  *
00276  * @var array
00277  * @access private
00278  */
00279     var $__backAssociation = array();
00280 /**
00281  * Constructor. Binds the Model's database table to the object.
00282  *
00283  * @param integer $id
00284  * @param string $table Name of database table to use.
00285  * @param DataSource $ds DataSource connection object.
00286  */
00287     function __construct($id = false, $table = null, $ds = null) {
00288         parent::__construct();
00289 
00290         if (is_array($id) && isset($id['name'])) {
00291             $options = array_merge(array('id' => false, 'table' => null, 'ds' => null, 'alias' => null), $id);
00292             list($id, $table, $ds) = array($options['id'], $options['table'], $options['ds']);
00293             $this->name = $options['name'];
00294         }
00295 
00296         if ($this->name === null) {
00297             $this->name = get_class($this);
00298         }
00299 
00300         if ($this->primaryKey === null) {
00301             $this->primaryKey = 'id';
00302         }
00303 
00304         if (isset($options['alias']) || !empty($options['alias'])) {
00305             $this->alias = $options['alias'];
00306             unset($options);
00307         } else {
00308             $this->alias = $this->name;
00309         }
00310         ClassRegistry::addObject($this->alias, $this);
00311 
00312         $this->id = $id;
00313         unset($id);
00314 
00315         if ($table === false) {
00316             $this->useTable = false;
00317         } elseif ($table) {
00318             $this->useTable = $table;
00319         }
00320 
00321         if ($this->useTable !== false) {
00322             $this->setDataSource($ds);
00323 
00324             if ($this->useTable === null) {
00325                 $this->useTable = Inflector::tableize($this->name);
00326             }
00327 
00328             if (in_array('settableprefix', get_class_methods($this))) {
00329                 $this->setTablePrefix();
00330             }
00331 
00332             $this->setSource($this->useTable);
00333             $this->__createLinks();
00334 
00335             if ($this->displayField == null) {
00336                 if ($this->hasField('title')) {
00337                     $this->displayField = 'title';
00338                 }
00339 
00340                 if ($this->hasField('name')) {
00341                     $this->displayField = 'name';
00342                 }
00343 
00344                 if ($this->displayField == null) {
00345                     $this->displayField = $this->primaryKey;
00346                 }
00347             }
00348         }
00349     }
00350 
00351 /**
00352  * Handles custom method calls, like findBy<field> for DB models,
00353  * and custom RPC calls for remote data sources
00354  *
00355  * @param unknown_type $method
00356  * @param array $params
00357  * @return unknown
00358  * @access protected
00359  */
00360     function __call($method, $params) {
00361         $db =& ConnectionManager::getDataSource($this->useDbConfig);
00362         return $db->query($method, $params, $this);
00363     }
00364 /**
00365  * Bind model associations on the fly.
00366  *
00367  * @param array $params
00368  * @return true
00369  * @access public
00370  */
00371     function bindModel($params) {
00372         foreach ($params as $assoc => $model) {
00373             if(!isset($this->__backAssociation[$assoc])) {
00374                 $this->__backAssociation[$assoc] = $this->{$assoc};
00375             }
00376 
00377             foreach ($model as $key => $value) {
00378                 $assocName = $key;
00379 
00380                 if (is_numeric($key)) {
00381                     $assocName = $value;
00382                     $value = array();
00383                 }
00384                 $modelName = $assocName;
00385                 $this->{$assoc}[$assocName] = $value;
00386             }
00387         }
00388         $this->__createLinks();
00389         return true;
00390     }
00391 /**
00392  * Turn off associations on the fly.
00393  *
00394  * @param array $params
00395  * @return true
00396  * @access public
00397  */
00398     function unbindModel($params) {
00399         foreach ($params as $assoc => $models) {
00400             if(!isset($this->__backAssociation[$assoc])) {
00401                 $this->__backAssociation[$assoc] = $this->{$assoc};
00402             }
00403 
00404             foreach ($models as $model) {
00405                 $this->__backAssociation = array_merge($this->__backAssociation, $this->{$assoc});
00406                 unset ($this->{$assoc}[$model]);
00407             }
00408         }
00409         return true;
00410     }
00411 /**
00412  * Private helper method to create a set of associations.
00413  *
00414  * @access private
00415  */
00416     function __createLinks() {
00417 
00418         foreach ($this->__associations as $type) {
00419             if (!is_array($this->{$type})) {
00420                 $this->{$type} = explode(',', $this->{$type});
00421 
00422                 foreach ($this->{$type} as $i => $className) {
00423                     $className = trim($className);
00424                     unset ($this->{$type}[$i]);
00425                     $this->{$type}[$className] = array();
00426                 }
00427             }
00428 
00429             foreach ($this->{$type} as $assoc => $value) {
00430                 if (is_numeric($assoc)) {
00431                     unset ($this->{$type}[$assoc]);
00432                     $assoc = $value;
00433                     $value = array();
00434                     $this->{$type}[$assoc] = $value;
00435                 }
00436 
00437                 $className = $assoc;
00438 
00439                 if (isset($value['className']) && !empty($value['className'])) {
00440                     $className = $value['className'];
00441                 }
00442                 $this->__constructLinkedModel($assoc, $className);
00443             }
00444         }
00445 
00446         foreach ($this->__associations as $type) {
00447             $this->__generateAssociation($type);
00448         }
00449     }
00450 
00451 /**
00452  * Private helper method to create associated models of given class.
00453  * @param string $assoc
00454  * @param string $className Class name
00455  * @param string $type Type of assocation
00456  * @access private
00457  */
00458     function __constructLinkedModel($assoc, $className) {
00459         if(empty($className)) {
00460             $className = $assoc;
00461         }
00462 
00463         if (!class_exists($className)) {
00464             loadModel($className);
00465         }
00466         $colKey = Inflector::underscore($className);
00467         $model = array('name' => $className, 'alias' => $assoc);
00468 
00469         if (ClassRegistry::isKeySet($colKey)) {
00470             $this->{$assoc} = ClassRegistry::getObject($colKey);
00471             $this->{$className} = $this->{$assoc};
00472         } else {
00473             $this->{$assoc} = new $className($model);
00474             $this->{$className} = $this->{$assoc};
00475         }
00476         $this->tableToModel[$this->{$assoc}->table] = $className;
00477         $this->modelToTable[$assoc] = $this->{$assoc}->table;
00478     }
00479 /**
00480  * Build array-based association from string.
00481  *
00482  * @param string $type "Belongs", "One", "Many", "ManyTo"
00483  * @access private
00484  */
00485     function __generateAssociation($type) {
00486         foreach ($this->{$type}as $assocKey => $assocData) {
00487             $class = $assocKey;
00488 
00489             foreach ($this->__associationKeys[$type] as $key) {
00490                 if (!isset($this->{$type}[$assocKey][$key]) || $this->{$type}[$assocKey][$key] == null) {
00491                     $data = '';
00492 
00493                     switch($key) {
00494                         case 'fields':
00495                             $data = '';
00496                         break;
00497 
00498                         case 'foreignKey':
00499                             $data = Inflector::singularize($this->table) . '_id';
00500 
00501                             if ($type == 'belongsTo') {
00502                                 $data = Inflector::singularize($this->{$class}->table) . '_id';
00503                             }
00504                         break;
00505 
00506                         case 'associationForeignKey':
00507                             $data = Inflector::singularize($this->{$class}->table) . '_id';
00508                         break;
00509 
00510                         case 'joinTable':
00511                             $tables = array($this->table, $this->{$class}->table);
00512                             sort ($tables);
00513                             $data = $tables[0] . '_' . $tables[1];
00514                         break;
00515 
00516                         case 'className':
00517                             $data = $class;
00518                         break;
00519                     }
00520 
00521                     $this->{$type}[$assocKey][$key] = $data;
00522                 }
00523 
00524                 if ($key == 'foreignKey' && !isset($this->keyToTable[$this->{$type}[$assocKey][$key]])) {
00525                     $this->keyToTable[$this->{$type}[$assocKey][$key]][0] = $this->{$class}->table;
00526                     $this->keyToTable[$this->{$type}[$assocKey][$key]][1] = $this->{$class}->alias;
00527                 }
00528             }
00529         }
00530     }
00531 /**
00532  * Sets a custom table for your controller class. Used by your controller to select a database table.
00533  *
00534  * @param string $tableName Name of the custom table
00535  * @access public
00536  */
00537     function setSource($tableName) {
00538         $this->setDataSource($this->useDbConfig);
00539         $db =& ConnectionManager::getDataSource($this->useDbConfig);
00540         $db->cacheSources = $this->cacheSources;
00541 
00542         if ($db->isInterfaceSupported('listSources')) {
00543             $sources = $db->listSources();
00544             if (is_array($sources) && !in_array(low($this->tablePrefix . $tableName), array_map('low', $sources))) {
00545                 return $this->cakeError('missingTable', array(array(
00546                                                 'className' => $this->alias,
00547                                                 'table' => $this->tablePrefix . $tableName)));
00548 
00549             }
00550             $this->_tableInfo = null;
00551         }
00552         $this->table = $this->useTable = $tableName;
00553         $this->tableToModel[$this->table] = $this->alias;
00554         $this->loadInfo();
00555     }
00556 /**
00557  * This function does two things: 1) it scans the array $one for the primary key,
00558  * and if that's found, it sets the current id to the value of $one[id].
00559  * For all other keys than 'id' the keys and values of $one are copied to the 'data' property of this object.
00560  * 2) Returns an array with all of $one's keys and values.
00561  * (Alternative indata: two strings, which are mangled to
00562  * a one-item, two-dimensional array using $one for a key and $two as its value.)
00563  *
00564  * @param mixed $one Array or string of data
00565  * @param string $two Value string for the alternative indata method
00566  * @return array
00567  * @access public
00568  */
00569     function set($one, $two = null) {
00570         if (is_array($one)) {
00571             if (countdim($one) == 1) {
00572                 $data = array($this->alias => $one);
00573             } else {
00574                 $data = $one;
00575             }
00576         } else {
00577             $data = array($this->alias => array($one => $two));
00578         }
00579 
00580         foreach ($data as $n => $v) {
00581             if (is_array($v)) {
00582 
00583                 foreach ($v as $x => $y) {
00584                     if (empty($this->whitelist) || (in_array($x, $this->whitelist) || $n !== $this->alias)) {
00585                         if (isset($this->validationErrors[$x])) {
00586                             unset ($this->validationErrors[$x]);
00587                         }
00588 
00589                         if ($n == $this->name || is_array($y)) {
00590                             if ($x === $this->primaryKey) {
00591                                 $this->id = $y;
00592                             }
00593                             $this->data[$n][$x] = $y;
00594                         }
00595                     }
00596                 }
00597             }
00598         }
00599         return $data;
00600     }
00601 /**
00602  * Returns an array of table metadata (column names and types) from the database.
00603  *
00604  * @return array Array of table metadata
00605  * @access public
00606  */
00607     function loadInfo() {
00608         $db =& ConnectionManager::getDataSource($this->useDbConfig);
00609         $db->cacheSources = $this->cacheSources;
00610 
00611         if (!is_object($this->_tableInfo) && $db->isInterfaceSupported('describe') && $this->useTable !== false) {
00612             $info = new Set($db->describe($this));
00613 
00614             foreach($info->value as $field => $value) {
00615                 $fields[] = am(array('name'=> $field), $value);
00616             }
00617             unset($info);
00618             $this->_tableInfo = new Set($fields);
00619         } elseif ($this->useTable === false) {
00620             $this->_tableInfo = new Set();
00621         }
00622         return $this->_tableInfo;
00623     }
00624 /**
00625  * Returns an associative array of field names and column types.
00626  *
00627  * @return array
00628  * @access public
00629  */
00630     function getColumnTypes() {
00631         $columns = $this->loadInfo();
00632         $columns = $columns->value;
00633         $db =& ConnectionManager::getDataSource($this->useDbConfig);
00634         $cols = array();
00635 
00636         foreach ($columns as $col) {
00637             $cols[$col['name']] = $col['type'];
00638         }
00639         return $cols;
00640     }
00641 /**
00642  * Returns the column type of a column in the model
00643  *
00644  * @param string $column The name of the model column
00645  * @return string
00646  * @access public
00647  */
00648     function getColumnType($column) {
00649         $columns = $this->loadInfo();
00650         $columns = $columns->value;
00651         $cols = array();
00652 
00653         foreach ($columns as $col) {
00654             if ($col['name'] == $column) {
00655                 return $col['type'];
00656             }
00657         }
00658         return null;
00659     }
00660 /**
00661  * Returns true if this Model has given field in its database table.
00662  *
00663  * @param string $name Name of field to look for
00664  * @return boolean
00665  * @access public
00666  */
00667     function hasField($name) {
00668         if (is_array($name)) {
00669             foreach ($name as $n) {
00670                 if ($this->hasField($n)) {
00671                     return $n;
00672                 }
00673             }
00674             return false;
00675         }
00676 
00677         if (empty($this->_tableInfo)) {
00678             $this->loadInfo();
00679         }
00680 
00681         if ($this->_tableInfo != null) {
00682             return in_array($name, $this->_tableInfo->extract('{n}.name'));
00683         }
00684         return false;
00685     }
00686 /**
00687  * Initializes the model for writing a new record.
00688  *
00689  * @return boolean True
00690  * @access public
00691  */
00692     function create() {
00693         $this->id = false;
00694         unset ($this->data);
00695         $this->data = $this->validationErrors = array();
00696         return true;
00697     }
00698 /**
00699  * @deprecated
00700  */
00701     function setId($id) {
00702         $this->id = $id;
00703     }
00704 /**
00705  * Use query() instead.
00706  * @deprecated
00707  */
00708     function findBySql($sql) {
00709         return $this->query($sql);
00710     }
00711 /**
00712  * Returns a list of fields from the database
00713  *
00714  * @param mixed $id The ID of the record to read
00715  * @param mixed $fields String of single fieldname, or an array of fieldnames.
00716  * @return array Array of database fields
00717  * @access public
00718  */
00719     function read($fields = null, $id = null) {
00720         $this->validationErrors = array();
00721 
00722         if ($id != null) {
00723             $this->id = $id;
00724         }
00725 
00726         $id = $this->id;
00727 
00728         if (is_array($this->id)) {
00729             $id = $this->id[0];
00730         }
00731 
00732         if ($this->id !== null && $this->id !== false) {
00733             $db =& ConnectionManager::getDataSource($this->useDbConfig);
00734             $field = $db->name($this->alias) . '.' . $db->name($this->primaryKey);
00735             return $this->find($field . ' = ' . $db->value($id, $this->getColumnType($this->primaryKey)), $fields);
00736         } else {
00737             return false;
00738         }
00739     }
00740 /**
00741  * Returns contents of a field in a query matching given conditions.
00742  *
00743  * @param string $name Name of field to get
00744  * @param array $conditions SQL conditions (defaults to NULL)
00745  * @param string $order SQL ORDER BY fragment
00746  * @return field contents
00747  * @access public
00748  */
00749     function field($name, $conditions = null, $order = null) {
00750         if ($conditions === null && $this->id !== false) {
00751             $conditions = array($this->alias . '.' . $this->primaryKey => $this->id);
00752         }
00753 
00754         if ($data = $this->find($conditions, $name, $order, 0)) {
00755 
00756             if (strpos($name, '.') === false) {
00757                 if (isset($data[$this->alias][$name])) {
00758                     return $data[$this->alias][$name];
00759                 } else {
00760                     return false;
00761                 }
00762             } else {
00763                 $name = explode('.', $name);
00764 
00765                 if (isset($data[$name[0]][$name[1]])) {
00766                     return $data[$name[0]][$name[1]];
00767                 } else {
00768                     return false;
00769                 }
00770             }
00771         } else {
00772             return false;
00773         }
00774     }
00775 /**
00776  * Saves a single field to the database.
00777  *
00778  * @param string $name Name of the table field
00779  * @param mixed $value Value of the field
00780  * @param array $validate See $options param in Model::save(). Does not respect 'fieldList' key if passed
00781  * @return boolean See Model::save()
00782  * @access public
00783  * @see Model::save()
00784  */
00785     function saveField($name, $value, $validate = false) {
00786         $id = $this->id;
00787         $this->create();
00788 
00789         if (is_array($validate)) {
00790             $options = array_merge(array('validate' => false, 'fieldList' => array($name)), $validate);
00791         } else {
00792             $options = array('validate' => $validate, 'fieldList' => array($name));
00793         }
00794 
00795         return $this->save(array($this->alias => array($this->primaryKey => $id, $name => $value)), $options);
00796     }
00797 /**
00798  * Saves model data to the database.
00799  * By default, validation occurs before save.
00800  *
00801  * @param array $data Data to save.
00802  * @param boolean $validate If set, validation will be done before the save
00803  * @param array $fieldList List of fields to allow to be written
00804  * @return boolean success
00805  * @access public
00806  */
00807     function save($data = null, $validate = true, $fieldList = array()) {
00808         $db =& ConnectionManager::getDataSource($this->useDbConfig);
00809         $_whitelist = $this->whitelist;
00810 
00811         if (!empty($fieldList)) {
00812             $this->whitelist = $fieldList;
00813         } elseif ($fieldList === null) {
00814             $this->whitelist = array();
00815         }
00816 
00817         if ($data) {
00818             if (countdim($data) == 1) {
00819                 $this->set(array($this->alias => $data));
00820             } else {
00821                 $this->set($data);
00822             }
00823         }
00824 
00825         if ($validate && !$this->validates()) {
00826             $this->whitelist = $_whitelist;
00827             return false;
00828         }
00829 
00830         if (!$this->beforeSave()) {
00831             $this->whitelist = $_whitelist;
00832             return false;
00833         }
00834         $fields = $values = array();
00835 
00836         if (isset($this->data[$this->alias][$this->primaryKey]) && empty($this->data[$this->alias][$this->primaryKey])) {
00837             unset($this->data[$this->alias][$this->primaryKey]);
00838         }
00839 
00840         if (count($this->data) > 1) {
00841             $weHaveMulti = true;
00842             $joined = false;
00843         } else {
00844             $weHaveMulti = false;
00845         }
00846 
00847         foreach ($this->data as $n => $v) {
00848             if (isset($weHaveMulti) && isset($v[$n]) && in_array($n, array_keys($this->hasAndBelongsToMany))) {
00849                 $joined[] = $v;
00850             } else {
00851                 if ($n === $this->alias) {
00852                     foreach (array('created', 'updated', 'modified') as $field) {
00853                         if (array_key_exists($field, $v) && (empty($v[$field]) || $v[$field] === null)) {
00854                             unset($v[$field]);
00855                         }
00856                     }
00857 
00858                     foreach ($v as $x => $y) {
00859                         if ($this->hasField($x)) {
00860                             $fields[] = $x;
00861                             $values[] = $y;
00862                         }
00863                     }
00864                 }
00865             }
00866         }
00867         $exists = $this->exists();
00868 
00869         if (!$exists && $this->hasField('created') && !in_array('created', $fields)) {
00870             $fields[] = 'created';
00871             $values[] = date('Y-m-d H:i:s');
00872         }
00873 
00874         if ($this->hasField('modified') && !in_array('modified', $fields)) {
00875             $fields[] = 'modified';
00876             $values[] = date('Y-m-d H:i:s');
00877         }
00878 
00879         if ($this->hasField('updated') && !in_array('updated', $fields)) {
00880             $fields[] = 'updated';
00881             $values[] = date('Y-m-d H:i:s');
00882         }
00883 
00884         if (!$exists) {
00885             $this->id = false;
00886         }
00887         $this->whitelist = $_whitelist;
00888 
00889 
00890         if (count($fields)) {
00891             if (!empty($this->id)) {
00892                 if ($db->update($this, $fields, $values)) {
00893                     if (!empty($joined)) {
00894                         $this->__saveMulti($joined, $this->id);
00895                     }
00896 
00897                     $this->afterSave();
00898                     $this->data = false;
00899                     $this->_clearCache();
00900                     return true;
00901                 }
00902                 return false;
00903             }
00904 
00905             if ($db->create($this, $fields, $values)) {
00906                 if (!empty($joined)) {
00907                     $this->__saveMulti($joined, $this->id);
00908                 }
00909 
00910                 $this->afterSave();
00911                 $this->data = false;
00912                 $this->_clearCache();
00913                 $this->validationErrors = array();
00914                 return true;
00915             }
00916             return false;
00917         }
00918         return false;
00919     }
00920 /**
00921  * Saves model hasAndBelongsToMany data to the database.
00922  *
00923  * @param array $joined Data to save.
00924  * @param string $id
00925  * @return void
00926  * @access private
00927  */
00928     function __saveMulti($joined, $id) {
00929         $db =& ConnectionManager::getDataSource($this->useDbConfig);
00930         foreach ($joined as $x => $y) {
00931             foreach ($y as $assoc => $value) {
00932                 if (isset($this->hasAndBelongsToMany[$assoc])) {
00933                     $joinTable[$assoc] = $this->hasAndBelongsToMany[$assoc]['joinTable'];
00934                     $mainKey[$assoc] = $this->hasAndBelongsToMany[$assoc]['foreignKey'];
00935                     $keys[] = $this->hasAndBelongsToMany[$assoc]['foreignKey'];
00936                     $keys[] = $this->hasAndBelongsToMany[$assoc]['associationForeignKey'];
00937                     $fields[$assoc]  = join(',', $keys);
00938                     unset($keys);
00939 
00940                     foreach ($value as $update) {
00941                         if (!empty($update)) {
00942                             $values[]  = $db->value($id, $this->getColumnType($this->primaryKey));
00943                             $values[]  = $db->value($update);
00944                             $values    = join(',', $values);
00945                             $newValues[] = "({$values})";
00946                             unset ($values);
00947                         }
00948                     }
00949 
00950                     if (!empty($newValues)) {
00951                         $newValue[$assoc] = $newValues;
00952                         unset($newValues);
00953                     } else {
00954                         $newValue[$assoc] = array();
00955                     }
00956                 }
00957             }
00958         }
00959 
00960         if (isset($joinTable)) {
00961             $total = count($joinTable);
00962 
00963             if (is_array($newValue)) {
00964                 foreach ($newValue as $loopAssoc => $val) {
00965                     $db =& ConnectionManager::getDataSource($this->useDbConfig);
00966                     $table = $db->name($db->fullTableName($joinTable[$loopAssoc]));
00967                     $db->query("DELETE FROM {$table} WHERE {$mainKey[$loopAssoc]} = '{$id}'");
00968 
00969                     if (!empty($newValue[$loopAssoc])) {
00970                         $secondCount = count($newValue[$loopAssoc]);
00971                         for ($x = 0; $x < $secondCount; $x++) {
00972                             $db->query("INSERT INTO {$table} ({$fields[$loopAssoc]}) VALUES {$newValue[$loopAssoc][$x]}");
00973                         }
00974                     }
00975                 }
00976             }
00977         }
00978     }
00979 /**
00980  * Synonym for del().
00981  *
00982  * @param mixed $id
00983  * @see function del
00984  * @return boolean True on success
00985  * @access public
00986  */
00987     function remove($id = null, $cascade = true) {
00988         return $this->del($id, $cascade);
00989     }
00990 /**
00991  * Removes record for given id. If no id is given, the current id is used. Returns true on success.
00992  *
00993  * @param mixed $id Id of record to delete
00994  * @return boolean True on success
00995  * @access public
00996  */
00997     function del($id = null, $cascade = true) {
00998         if ($id) {
00999             $this->id = $id;
01000         }
01001         $id = $this->id;
01002 
01003         if ($this->exists() && $this->beforeDelete()) {
01004             $db =& ConnectionManager::getDataSource($this->useDbConfig);
01005 
01006             $this->_deleteMulti($id);
01007             $this->_deleteHasMany($id, $cascade);
01008             $this->_deleteHasOne($id, $cascade);
01009             $this->id = $id;
01010 
01011             if ($db->delete($this)) {
01012                 $this->afterDelete();
01013                 $this->_clearCache();
01014                 $this->id = false;
01015                 return true;
01016             }
01017         }
01018 
01019         return false;
01020     }
01021 /**
01022  * Alias for del()
01023  *
01024  * @param mixed $id Id of record to delete
01025  * @return boolean True on success
01026  * @access public
01027  */
01028     function delete($id = null, $cascade = true) {
01029         return $this->del($id, $cascade);
01030     }
01031 /**
01032  * Cascades model deletes to hasMany relationships.
01033  *
01034  * @param string $id
01035  * @return null
01036  * @access protected
01037  */
01038     function _deleteHasMany($id, $cascade) {
01039         if (!empty($this->__backAssociation)) {
01040             $savedAssociatons = $this->__backAssociation;
01041             $this->__backAssociation = array();
01042         }
01043         foreach ($this->hasMany as $assoc => $data) {
01044             if ($data['dependent'] === true && $cascade === true) {
01045                 $model =& $this->{$data['className']};
01046                 $field = $model->escapeField($data['foreignKey']);
01047                 $model->recursive = 0;
01048                 $records = $model->findAll("$field = '$id'", $model->primaryKey, null, null);
01049 
01050                 if ($records != false) {
01051                     foreach ($records as $record) {
01052                         $model->del($record[$data['className']][$model->primaryKey]);
01053                     }
01054                 }
01055             }
01056         }
01057         if (isset($savedAssociatons)) {
01058             $this->__backAssociation = $savedAssociatons;
01059         }
01060     }
01061 /**
01062  * Cascades model deletes to hasOne relationships.
01063  *
01064  * @param string $id
01065  * @return null
01066  * @access protected
01067  */
01068     function _deleteHasOne($id, $cascade) {
01069         if (!empty($this->__backAssociation)) {
01070             $savedAssociatons = $this->__backAssociation;
01071             $this->__backAssociation = array();
01072         }
01073         foreach ($this->hasOne as $assoc => $data) {
01074             if ($data['dependent'] === true && $cascade === true) {
01075                 $model =& $this->{$data['className']};
01076                 $field = $model->escapeField($data['foreignKey']);
01077                 $model->recursive = 0;
01078                 $records = $model->findAll("$field = '$id'", $model->primaryKey, null, null);
01079 
01080                 if ($records != false) {
01081                     foreach ($records as $record) {
01082                         $model->del($record[$data['className']][$model->primaryKey]);
01083                     }
01084                 }
01085             }
01086         }
01087         if (isset($savedAssociatons)) {
01088             $this->__backAssociation = $savedAssociatons;
01089         }
01090     }
01091 /**
01092  * Cascades model deletes to HABTM join keys.
01093  *
01094  * @param string $id
01095  * @return null
01096  * @access protected
01097  */
01098     function _deleteMulti($id) {
01099         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01100         foreach ($this->hasAndBelongsToMany as $assoc => $data) {
01101             $db->execute("DELETE FROM " . $db->name($db->fullTableName($data['joinTable'])) . " WHERE " . $db->name($data['foreignKey']) . " = '{$id}'");
01102         }
01103     }
01104 /**
01105  * Returns true if a record with set id exists.
01106  *
01107  * @return boolean True if such a record exists
01108  * @access public
01109  */
01110     function exists() {
01111         if ($this->id) {
01112             $id = $this->id;
01113 
01114             if (is_array($id)) {
01115                 $id = $id[0];
01116             }
01117 
01118             $db =& ConnectionManager::getDataSource($this->useDbConfig);
01119             return $db->hasAny($this, array($this->primaryKey => $id));
01120         }
01121         return false;
01122     }
01123 /**
01124  * Returns true if a record that meets given conditions exists
01125  *
01126  * @param array $conditions SQL conditions array
01127  * @return boolean True if such a record exists
01128  * @access public
01129  */
01130     function hasAny($conditions = null) {
01131         return ($this->findCount($conditions) != false);
01132     }
01133 /**
01134  * Return a single row as a resultset array.
01135  * By using the $recursive parameter, the call can access further "levels of association" than
01136  * the ones this model is directly associated to.
01137  *
01138  * @param array $conditions SQL conditions array
01139  * @param mixed $fields Either a single string of a field name, or an array of field names
01140  * @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC")
01141  * @param int $recursive The number of levels deep to fetch associated records
01142  * @return array Array of records
01143  * @access public
01144  */
01145     function find($conditions = null, $fields = null, $order = null, $recursive = null) {
01146         $data = $this->findAll($conditions, $fields, $order, 1, null, $recursive);
01147 
01148         if (empty($data[0])) {
01149             return false;
01150         }
01151 
01152         return $data[0];
01153     }
01154 /**
01155  * Returns a resultset array with specified fields from database matching given conditions.
01156  * By using the $recursive parameter, the call can access further "levels of association" than
01157  * the ones this model is directly associated to.
01158  *
01159  * @param mixed $conditions SQL conditions as a string or as an array('field' =>'value',...)
01160  * @param mixed $fields Either a single string of a field name, or an array of field names
01161  * @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC")
01162  * @param int $limit SQL LIMIT clause, for calculating items per page.
01163  * @param int $page Page number, for accessing paged data
01164  * @param int $recursive The number of levels deep to fetch associated records
01165  * @return array Array of records
01166  * @access public
01167  */
01168     function findAll($conditions = null, $fields = null, $order = null, $limit = null, $page = 1, $recursive = null) {
01169 
01170         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01171         $this->id = $this->getID();
01172         $offset = null;
01173 
01174         if ($page > 1 && $limit != null) {
01175             $offset = ($page - 1) * $limit;
01176         }
01177 
01178         if ($order == null) {
01179             $order = array();
01180         } else {
01181             $order = array($order);
01182         }
01183 
01184         $queryData = array('conditions' => $conditions,
01185                             'fields'    => $fields,
01186                             'joins'     => array(),
01187                             'limit'     => $limit,
01188                             'offset'    => $offset,
01189                             'order'     => $order
01190         );
01191 
01192         $ret = $this->beforeFind($queryData);
01193         if (is_array($ret)) {
01194             $queryData = $ret;
01195         } elseif ($ret === false) {
01196             return null;
01197         }
01198 
01199         $return = $this->afterFind($db->read($this, $queryData, $recursive));
01200 
01201         if (!empty($this->__backAssociation)) {
01202             $this->__resetAssociations();
01203         }
01204 
01205         return $return;
01206     }
01207 /**
01208  * Method is called only when bindTo<ModelName>() is used.
01209  * This resets the association arrays for the model back
01210  * to the original as set in the model.
01211  *
01212  * @return boolean
01213  * @access private
01214  */
01215     function __resetAssociations() {
01216         foreach ($this->__associations as $type) {
01217             if (isset($this->__backAssociation[$type])) {
01218                 $this->{$type} = $this->__backAssociation[$type];
01219             }
01220         }
01221 
01222         $this->__backAssociation = array();
01223         return true;
01224     }
01225 /**
01226  * Runs a direct query against the bound DataSource, and returns the result.
01227  *
01228  * @param string $data Query data
01229  * @return array
01230  * @access public
01231  */
01232     function execute($data) {
01233         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01234         $data = $db->fetchAll($data, $this->cacheQueries);
01235 
01236         foreach ($data as $key => $value) {
01237             foreach ($this->tableToModel as $key1 => $value1) {
01238                 if (isset($data[$key][$key1])) {
01239                     $newData[$key][$value1] = $data[$key][$key1];
01240                 }
01241             }
01242         }
01243 
01244         if (!empty($newData)) {
01245             return $newData;
01246         }
01247 
01248         return $data;
01249     }
01250 /**
01251  * Returns number of rows matching given SQL condition.
01252  *
01253  * @param array $conditions SQL conditions array for findAll
01254  * @param int $recursize The number of levels deep to fetch associated records
01255  * @return int Number of matching rows
01256  * @see Model::findAll
01257  * @access public
01258  */
01259     function findCount($conditions = null, $recursive = 0) {
01260         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01261 
01262         list($data) = $this->findAll($conditions, 'COUNT(*) AS ' . $db->name('count'), null, null, 1, $recursive);
01263 
01264         if (isset($data[0]['count'])) {
01265             return $data[0]['count'];
01266         } elseif (isset($data[$this->alias]['count'])) {
01267             return $data[$this->alias]['count'];
01268         }
01269 
01270         return false;
01271     }
01272 /**
01273  * Special findAll variation for tables joined to themselves.
01274  * The table needs the fields id and parent_id to work.
01275  *
01276  * @param array $conditions Conditions for the findAll() call
01277  * @param array $fields Fields for the findAll() call
01278  * @param string $sort SQL ORDER BY statement
01279  * @return array
01280  * @access public
01281  * @todo Perhaps create a Component with this logic
01282  */
01283     function findAllThreaded($conditions = null, $fields = null, $sort = null) {
01284         return $this->__doThread(Model::findAll($conditions, $fields, $sort), null);
01285     }
01286 /**
01287  * Private, recursive helper method for findAllThreaded.
01288  *
01289  * @param array $data
01290  * @param string $root NULL or id for root node of operation
01291  * @return array
01292  * @access private
01293  * @see findAllThreaded
01294  */
01295     function __doThread($data, $root) {
01296         $out = array();
01297         $sizeOf = sizeof($data);
01298 
01299         for ($ii = 0; $ii < $sizeOf; $ii++) {
01300             if (($data[$ii][$this->alias]['parent_id'] == $root) || (($root === null) && ($data[$ii][$this->alias]['parent_id'] == '0'))) {
01301                 $tmp = $data[$ii];
01302 
01303                 if (isset($data[$ii][$this->alias][$this->primaryKey])) {
01304                     $tmp['children'] = $this->__doThread($data, $data[$ii][$this->alias][$this->primaryKey]);
01305                 } else {
01306                     $tmp['children'] = null;
01307                 }
01308 
01309                 $out[] = $tmp;
01310             }
01311         }
01312 
01313         return $out;
01314     }
01315 /**
01316  * Returns an array with keys "prev" and "next" that holds the id's of neighbouring data,
01317  * which is useful when creating paged lists.
01318  *
01319  * @param string $conditions SQL conditions for matching rows
01320  * @param string $field Field name (parameter for findAll)
01321  * @param unknown_type $value
01322  * @return array Array with keys "prev" and "next" that holds the id's
01323  * @access public
01324  */
01325     function findNeighbours($conditions = null, $field, $value) {
01326         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01327 
01328         if (!is_null($conditions)) {
01329                 $conditions = $conditions . ' AND ';
01330         }
01331 
01332         @list($prev) = Model::findAll($conditions . $field . ' < ' . $db->value($value), $field, $field . ' DESC', 1, null, 0);
01333         @list($next) = Model::findAll($conditions . $field . ' > ' . $db->value($value), $field, $field . ' ASC', 1, null, 0);
01334 
01335         if (!isset($prev)) {
01336             $prev = null;
01337         }
01338 
01339         if (!isset($next)) {
01340             $next = null;
01341         }
01342 
01343         return array('prev' => $prev, 'next' => $next);
01344     }
01345 /**
01346  * Returns a resultset for given SQL statement. Generic SQL queries should be made with this method.
01347  *
01348  * @param string $sql SQL statement
01349  * @return array Resultset
01350  * @access public
01351  */
01352     function query() {
01353         $params = func_get_args();
01354         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01355         return call_user_func_array(array(&$db, 'query'), $params);
01356     }
01357 /**
01358  * Returns true if all fields pass validation, otherwise false.
01359  *
01360  * @param array $data POST data
01361  * @return boolean True if there are no errors
01362  * @access public
01363  */
01364     function validates($data = array()) {
01365         $errors = $this->invalidFields($data);
01366         return count($errors) == 0;
01367     }
01368 /**
01369  * Returns an array of invalid fields.
01370  *
01371  * @param array $data
01372  * @return array Array of invalid fields or boolean case any error occurs
01373  * @access public
01374  */
01375     function invalidFields($data = array()) {
01376         if (empty($data)) {
01377             $data = $this->data;
01378         }
01379 
01380         if (!$this->beforeValidate()) {
01381             return $this->validationErrors;
01382         }
01383 
01384         if (!isset($this->validate)) {
01385             return $this->validationErrors;
01386         }
01387 
01388         if (!empty($data)) {
01389             $data = $data;
01390         } elseif (isset($this->data)) {
01391             $data = $this->data;
01392         }
01393 
01394         if (isset($data[$this->alias])) {
01395             $data = $data[$this->alias];
01396         }
01397 
01398         foreach ($this->validate as $field_name => $validator) {
01399             if (isset($data[$field_name]) && !preg_match($validator, $data[$field_name])) {
01400                 $this->invalidate($field_name);
01401             }
01402         }
01403         return $this->validationErrors;
01404     }
01405 /**
01406  * Sets a field as invalid
01407  *
01408  * @param string $field The name of the field to invalidate
01409  * @return void
01410  * @access public
01411  */
01412     function invalidate($field) {
01413         if (!is_array($this->validationErrors)) {
01414             $this->validationErrors = array();
01415         }
01416         $this->validationErrors[$field] = 1;
01417     }
01418 /**
01419  * Returns true if given field name is a foreign key in this Model.
01420  *
01421  * @param string $field Returns true if the input string ends in "_id"
01422  * @return True if the field is a foreign key listed in the belongsTo array.
01423  * @access public
01424  */
01425     function isForeignKey($field) {
01426         $foreignKeys = array();
01427 
01428         if (count($this->belongsTo)) {
01429             foreach ($this->belongsTo as $assoc => $data) {
01430                 $foreignKeys[] = $data['foreignKey'];
01431             }
01432         }
01433         return (bool)(in_array($field, $foreignKeys));
01434     }
01435 /**
01436  * Gets the display field for this model
01437  *
01438  * @return string The name of the display field for this Model (i.e. 'name', 'title').
01439  * @access public
01440  */
01441     function getDisplayField() {
01442         return $this->displayField;
01443     }
01444 /**
01445  * Returns a resultset array with specified fields from database matching given conditions.
01446  * Method can be used to generate option lists for SELECT elements.
01447  *
01448  * @param mixed $conditions SQL conditions as a string or as an array('field' =>'value',...)
01449  * @param string $order SQL ORDER BY conditions (e.g. "price DESC" or "name ASC")
01450  * @param int $limit SQL LIMIT clause, for calculating items per page
01451  * @param string $keyPath A string path to the key, i.e. "{n}.Post.id"
01452  * @param string $valuePath A string path to the value, i.e. "{n}.Post.title"
01453  * @return array An associative array of records, where the id is the key, and the display field is the value
01454  * @access public
01455  */
01456     function generateList($conditions = null, $order = null, $limit = null, $keyPath = null, $valuePath = null) {
01457         if ($keyPath == null && $valuePath == null && $this->hasField($this->displayField)) {
01458             $fields = array($this->primaryKey, $this->displayField);
01459         } else {
01460             $fields = null;
01461         }
01462         $recursive = $this->recursive;
01463 
01464         if ($recursive >= 1) {
01465             $this->recursive = -1;
01466         }
01467         $result = $this->findAll($conditions, $fields, $order, $limit);
01468         $this->recursive = $recursive;
01469 
01470         if (!$result) {
01471             return false;
01472         }
01473 
01474         if ($keyPath == null) {
01475             $keyPath = '{n}.' . $this->alias . '.' . $this->primaryKey;
01476         }
01477 
01478         if ($valuePath == null) {
01479             $valuePath = '{n}.' . $this->alias . '.' . $this->displayField;
01480         }
01481 
01482         $keys = Set::extract($result, $keyPath);
01483         $vals = Set::extract($result, $valuePath);
01484 
01485         if (!empty($keys) && !empty($vals)) {
01486             $return = array_combine($keys, $vals);
01487             return $return;
01488         }
01489         return null;
01490     }
01491 /**
01492  * Escapes the field name and prepends the model name. Escaping will be done according to the current database driver's rules.
01493  *
01494  * @param unknown_type $field
01495  * @return string The name of the escaped field for this Model (i.e. id becomes `Post`.`id`).
01496  * @access public
01497  */
01498     function escapeField($field) {
01499         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01500         return $db->name($this->alias) . '.' . $db->name($field);
01501     }
01502 /**
01503  * Returns the current record's ID
01504  *
01505  * @param unknown_type $list
01506  * @return mixed The ID of the current record
01507  * @access public
01508  */
01509     function getID($list = 0) {
01510         if (!is_array($this->id)) {
01511             return $this->id;
01512         }
01513 
01514         if (count($this->id) == 0) {
01515             return false;
01516         }
01517 
01518         if (isset($this->id[$list])) {
01519             return $this->id[$list];
01520         }
01521 
01522         foreach ($this->id as $id) {
01523             return $id;
01524         }
01525 
01526         return false;
01527     }
01528 /**
01529  * Returns the ID of the last record this Model inserted
01530  *
01531  * @return mixed
01532  * @access public
01533  */
01534     function getLastInsertID() {
01535         return $this->getInsertID();
01536     }
01537 /**
01538  * Returns the ID of the last record this Model inserted
01539  *
01540  * @return mixed
01541  * @access public
01542  */
01543     function getInsertID() {
01544         return $this->__insertID;
01545     }
01546 /**
01547  * Sets the ID of the last record this Model inserted
01548  *
01549  * @param mixed $id
01550  * @return void
01551  */
01552     function setInsertID($id) {
01553         $this->__insertID = $id;
01554     }
01555 /**
01556  * Returns the number of rows returned from the last query
01557  *
01558  * @return int
01559  * @access public
01560  */
01561     function getNumRows() {
01562         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01563         return $db->lastNumRows();
01564     }
01565 /**
01566  * Returns the number of rows affected by the last query
01567  *
01568  * @return int
01569  * @access public
01570  */
01571     function getAffectedRows() {
01572         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01573         return $db->lastAffected();
01574     }
01575 /**
01576  * Sets the DataSource to which this model is bound
01577  *
01578  * @param string $dataSource The name of the DataSource, as defined in Connections.php
01579  * @return boolean True on success
01580  * @access public
01581  */
01582     function setDataSource($dataSource = null) {
01583         if ($dataSource != null) {
01584             $this->useDbConfig = $dataSource;
01585         }
01586         $db =& ConnectionManager::getDataSource($this->useDbConfig);
01587 
01588         if (!empty($db->config['prefix']) && $this->tablePrefix === null) {
01589             $this->tablePrefix = $db->config['prefix'];
01590         }
01591 
01592         if (empty($db) || $db == null || !is_object($db)) {
01593             return $this->cakeError('missingConnection', array(array('className' => $this->alias)));
01594         }
01595     }
01596 /**
01597  * Before find callback
01598  *
01599  * @param array $queryData Data used to execute this query, i.e. conditions, order, etc.
01600  * @return boolean True if the operation should continue, false if it should abort
01601  * @access public
01602  */
01603     function beforeFind(&$queryData) {
01604         return true;
01605     }
01606 /**
01607  * After find callback. Can be used to modify any results returned by find and findAll.
01608  *
01609  * @param mixed $results The results of the find operation
01610  * @return mixed Result of the find operation
01611  * @access public
01612  */
01613     function afterFind($results) {
01614         return $results;
01615     }
01616 /**
01617  * Before save callback
01618  *
01619  * @return boolean True if the operation should continue, false if it should abort
01620  * @access public
01621  */
01622     function beforeSave() {
01623         return true;
01624     }
01625 /**
01626  * After save callback
01627  *
01628  * @return boolean
01629  * @access public
01630  */
01631     function afterSave() {
01632         return true;
01633     }
01634 /**
01635  * Before delete callback
01636  *
01637  * @return boolean True if the operation should continue, false if it should abort
01638  * @access public
01639  */
01640     function beforeDelete() {
01641         return true;
01642     }
01643 /**
01644  * After delete callback
01645  *
01646  * @return boolean
01647  * @access public
01648  */
01649     function afterDelete() {
01650         return true;
01651     }
01652 /**
01653  * Before validate callback
01654  *
01655  * @return boolean
01656  * @access public
01657  */
01658     function beforeValidate() {
01659         return true;
01660     }
01661 /**
01662  * DataSource error callback
01663  *
01664  * @return void
01665  */
01666     function onError() {
01667     }
01668 /**
01669  * Private method.  Clears cache for this model
01670  *
01671  * @param string $type If null this deletes cached views if CACHE_CHECK is true
01672  *                     Will be used to allow deleting query cache also
01673  * @return boolean true on delete
01674  * @access protected
01675  */
01676     function _clearCache($type = null) {
01677         if ($type === null) {
01678             if (defined('CACHE_CHECK') && CACHE_CHECK === true) {
01679                 $assoc[] = strtolower(Inflector::pluralize($this->alias));
01680 
01681                 foreach ($this->__associations as $key => $association) {
01682                     foreach ($this->$association as $key => $className) {
01683                         $check = strtolower(Inflector::pluralize($className['className']));
01684 
01685                         if (!in_array($check, $assoc)) {
01686                             $assoc[] = strtolower(Inflector::pluralize($className['className']));
01687                         }
01688                     }
01689                 }
01690                 clearCache($assoc);
01691                 return true;
01692             }
01693         } else {
01694             //Will use for query cache deleting
01695         }
01696     }
01697 /**
01698  * Called when serializing a model
01699  *
01700  * @return array
01701  * @access public
01702  */
01703     function __sleep() {
01704         $return = array_keys(get_object_vars($this));
01705         return $return;
01706     }
01707 /**
01708  * Called when unserializing a model
01709  *
01710  * @return void
01711  * @access public
01712  */
01713     function __wakeup() {
01714     }
01715 }
01716 ?>