2005-08-21 06:49:02 +00:00
< ? php
/* SVN FILE: $Id$ */
2005-06-23 13:59:02 +00:00
/**
2005-09-07 01:52:45 +00:00
* Object - relational mapper .
2005-12-22 01:07:28 +00:00
*
2005-09-07 01:52:45 +00:00
* DBO - backed object data model , for mapping database tables to Cake objects .
2005-06-23 13:59:02 +00:00
*
2006-07-30 12:24:03 +00:00
* PHP versions 5
2005-08-21 06:49:02 +00:00
*
2007-02-02 10:39:45 +00:00
* CakePHP ( tm ) : Rapid Development Framework < http :// www . cakephp . org />
* Copyright 2005 - 2007 , Cake Software Foundation , Inc .
2006-05-26 05:29:17 +00:00
* 1785 E . Sahara Avenue , Suite 490 - 204
* Las Vegas , Nevada 89104
2005-12-27 03:33:44 +00:00
*
2005-12-23 21:57:26 +00:00
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
2005-06-23 13:59:02 +00:00
*
2005-12-22 01:07:28 +00:00
* @ filesource
2007-02-02 10:39:45 +00:00
* @ copyright Copyright 2005 - 2007 , Cake Software Foundation , Inc .
* @ link http :// www . cakefoundation . org / projects / info / cakephp CakePHP ( tm ) Project
2006-05-26 05:29:17 +00:00
* @ package cake
* @ subpackage cake . cake . libs . model
2007-02-02 10:39:45 +00:00
* @ since CakePHP ( tm ) v 0.10 . 0.0
2006-05-26 05:29:17 +00:00
* @ version $Revision $
* @ modifiedby $LastChangedBy $
* @ lastmodified $Date $
* @ license http :// www . opensource . org / licenses / mit - license . php The MIT License
2005-06-23 13:59:02 +00:00
*/
2006-07-22 14:13:07 +00:00
/**
2006-07-30 12:24:03 +00:00
* Included libs
2006-07-22 14:13:07 +00:00
*/
2006-12-25 06:53:19 +00:00
uses ( 'class_registry' , 'validation' , 'overloadable' , 'model' . DS . 'behavior' , 'model' . DS . 'connection_manager' , 'set' );
2007-09-20 15:16:25 +00:00
2006-01-17 17:52:23 +00:00
/**
2006-07-30 12:24:03 +00:00
* Object - relational mapper .
*
* DBO - backed object data model .
* Automatically selects a database table name based on a pluralized lowercase object class name
* ( i . e . class ' User ' => table ' users '; class ' Man ' => table ' men ' )
* The table is required to have at least 'id auto_increment' , 'created datetime' ,
* and 'modified datetime' fields .
*
* @ package cake
* @ subpackage cake . cake . libs . model
*/
class Model extends Overloadable {
/**
* The name of the DataSource connection that this Model uses
*
* @ var string
* @ access public
*/
var $useDbConfig = 'default' ;
/**
* Enter description here ... Still used ?
*
* @ var unknown_type
* @ access public
* @ todo Is this still used ? - OJ 22 nov 2006
*/
var $parent = false ;
/**
* Custom database table name .
*
* @ var string
* @ access public
*/
var $useTable = null ;
/**
* Custom display field name . Display fields are used by Scaffold , in SELECT boxes ' OPTION elements .
*
* @ var string
* @ access public
*/
var $displayField = null ;
/**
* Value of the primary key ID of the record that this model is currently pointing to
*
* @ var integer
* @ access public
*/
var $id = false ;
/**
* Container for the data that this model gets from persistent storage ( the database ) .
*
* @ var array
* @ access public
*/
var $data = array ();
/**
* Table name for this Model .
*
* @ var string
* @ access public
*/
var $table = false ;
/**
* The name of the ID field for this Model .
*
* @ var string
* @ access public
*/
var $primaryKey = null ;
/**
* Table metadata
*
* @ var array
2007-08-21 21:46:59 +00:00
* @ access protected
*/
var $_schema = null ;
/**
*
* @ deprecated see $_schema
2006-07-30 12:24:03 +00:00
*/
var $_tableInfo = null ;
/**
* List of validation rules . Append entries for validation as ( 'field_name' => '/^perl_compat_regexp$/' )
* that have to match with preg_match () . Use these rules with Model :: validate ()
*
* @ var array
* @ access public
*/
var $validate = array ();
/**
* Errors in validation
* @ var array
* @ access public
*/
var $validationErrors = array ();
/**
* Database table prefix for tables in model .
*
* @ var string
* @ access public
*/
var $tablePrefix = null ;
/**
* Name of the model .
*
* @ var string
*/
var $name = null ;
/**
* Name of the current model .
*
* @ var string
*/
var $currentModel = null ;
/**
* List of table names included in the Model description . Used for associations .
*
* @ var array
* @ access public
*/
var $tableToModel = array ();
/**
* List of Model names by used tables . Used for associations .
*
* @ var array
* @ access public
*/
var $modelToTable = array ();
/**
* List of Foreign Key names to used tables . Used for associations .
*
* @ var array
* @ access public
*/
var $keyToTable = array ();
/**
* Alias table names for model , for use in SQL JOIN statements .
*
* @ var array
* @ access public
*/
var $alias = array ();
/**
* Whether or not transactions for this model should be logged
*
* @ var boolean
* @ access public
*/
var $logTransactions = false ;
/**
* Whether or not to enable transactions for this model ( i . e . BEGIN / COMMIT / ROLLBACK )
*
* @ var boolean
* @ access public
*/
var $transactional = false ;
/**
* Whether or not to cache queries for this model . This enables in - memory
* caching only , the results are not stored beyond this execution .
*
* @ var boolean
* @ access public
*/
2006-11-21 22:40:30 +00:00
var $cacheQueries = false ;
2006-07-30 12:24:03 +00:00
/**
* belongsTo association
*
* @ var array
* @ access public
*/
var $belongsTo = array ();
/**
* hasOne association
*
* @ var array
* @ access public
*/
var $hasOne = array ();
/**
* hasMany association
*
* @ var array
* @ access public
*/
var $hasMany = array ();
/**
* hasAndBelongsToMany association
*
* @ var array
* @ access public
*/
var $hasAndBelongsToMany = array ();
/**
* List of behaviors to use
*
* @ var array
*/
var $actsAs = null ;
/**
* Behavior objects
*
* @ var array
*/
var $behaviors = array ();
2007-04-08 23:30:31 +00:00
/**
* Enter description here ...
*
* @ var boolean
*/
var $cacheSources = true ;
2006-07-30 12:24:03 +00:00
/**
* Mapped behavior methods
*
* @ var array
* @ access private
*/
var $__behaviorMethods = array ();
/**
* Depth of recursive association
*
* @ var integer
* @ access public
*/
var $recursive = 1 ;
/**
* Default ordering of model records
*
* @ var mixed
*/
var $order = null ;
2007-10-01 16:49:37 +00:00
/**
* whether or not the model record exists , set by Model :: exists ()
*
* @ var bool
*/
var $__exists = null ;
2006-07-30 12:24:03 +00:00
/**
* Default association keys
*
* @ var array
2006-08-03 06:49:51 +00:00
* @ access protected
2006-07-30 12:24:03 +00:00
*/
var $__associationKeys = array (
2006-09-28 16:44:02 +00:00
'belongsTo' => array ( 'className' , 'foreignKey' , 'conditions' , 'fields' , 'order' , 'counterCache' ),
'hasOne' => array ( 'className' , 'foreignKey' , 'conditions' , 'fields' , 'order' , 'dependent' ),
'hasMany' => array ( 'className' , 'foreignKey' , 'conditions' , 'fields' , 'order' , 'limit' , 'offset' , 'dependent' , 'exclusive' , 'finderQuery' , 'counterQuery' ),
2007-08-29 10:14:14 +00:00
'hasAndBelongsToMany' => array ( 'className' , 'joinTable' , 'with' , 'foreignKey' , 'associationForeignKey' , 'conditions' , 'fields' , 'order' , 'limit' , 'offset' , 'unique' , 'finderQuery' , 'deleteQuery' , 'insertQuery' )
2006-07-30 12:24:03 +00:00
);
/**
* Holds provided / generated association key names and other data for all associations
*
* @ var array
2006-08-03 06:49:51 +00:00
* @ access protected
2006-07-30 12:24:03 +00:00
*/
var $__associations = array ( 'belongsTo' , 'hasOne' , 'hasMany' , 'hasAndBelongsToMany' );
2007-03-26 17:16:43 +00:00
/**
2007-05-20 05:05:18 +00:00
* Holds model associations temporarily to allow for dynamic ( un ) binding
2007-03-26 17:16:43 +00:00
*
* @ var array
2007-05-20 05:05:18 +00:00
* @ access private
2007-03-26 17:16:43 +00:00
*/
var $__backAssociation = array ();
2006-07-30 12:24:03 +00:00
/**
* The last inserted ID of the data that this model created
*
* @ var integer
2006-08-03 06:49:51 +00:00
* @ access protected
2006-07-30 12:24:03 +00:00
*/
var $__insertID = null ;
/**
* The number of records returned by the last query
*
* @ var integer
2006-08-03 06:49:51 +00:00
* @ access protected
2006-07-30 12:24:03 +00:00
*/
var $__numRows = null ;
/**
* The number of records affected by the last query
*
* @ var integer
2006-08-03 06:49:51 +00:00
* @ access protected
2006-07-30 12:24:03 +00:00
*/
var $__affectedRows = null ;
/**
* Constructor . Binds the Model ' s database table to the object .
*
* @ param integer $id
* @ param string $table Name of database table to use .
* @ param DataSource $ds DataSource connection object .
*/
function __construct ( $id = false , $table = null , $ds = null ) {
parent :: __construct ();
2007-08-04 17:20:50 +00:00
if ( is_array ( $id ) && isset ( $id [ 'name' ])) {
$options = am ( array (
'id' => false ,
'table' => null ,
'ds' => null
), $id );
list ( $id , $table , $ds ) = array ( $options [ 'id' ], $options [ 'table' ], $options [ 'ds' ]);
$this -> name = $options [ 'name' ];
}
2006-07-30 12:24:03 +00:00
if ( $this -> name === null ) {
$this -> name = get_class ( $this );
}
if ( $this -> primaryKey === null ) {
$this -> primaryKey = 'id' ;
}
$this -> currentModel = Inflector :: underscore ( $this -> name );
ClassRegistry :: addObject ( $this -> currentModel , $this );
2007-02-05 04:53:31 +00:00
ClassRegistry :: map ( $this -> currentModel , $this -> currentModel );
2007-05-20 05:05:18 +00:00
2006-07-30 12:24:03 +00:00
$this -> id = $id ;
2007-05-20 05:05:18 +00:00
2007-06-20 06:15:35 +00:00
if ( $table === false ) {
2007-05-13 01:09:40 +00:00
$this -> useTable = false ;
2007-06-20 06:15:35 +00:00
} elseif ( $table ) {
2007-05-13 01:09:40 +00:00
$this -> useTable = $table ;
}
2007-05-20 05:05:18 +00:00
2006-07-30 12:24:03 +00:00
if ( $this -> useTable !== false ) {
$this -> setDataSource ( $ds );
2007-05-20 05:05:18 +00:00
2007-05-13 01:09:40 +00:00
if ( $this -> useTable === null ) {
$this -> useTable = Inflector :: tableize ( $this -> name );
2006-07-30 12:24:03 +00:00
}
if ( in_array ( 'settableprefix' , get_class_methods ( $this ))) {
$this -> setTablePrefix ();
}
2007-05-13 01:09:40 +00:00
$this -> setSource ( $this -> useTable );
2006-07-30 12:24:03 +00:00
$this -> __createLinks ();
if ( $this -> displayField == null ) {
if ( $this -> hasField ( 'title' )) {
$this -> displayField = 'title' ;
}
if ( $this -> hasField ( 'name' )) {
$this -> displayField = 'name' ;
}
if ( $this -> displayField == null ) {
$this -> displayField = $this -> primaryKey ;
}
}
}
2007-09-20 15:16:25 +00:00
if ( is_subclass_of ( $this , 'AppModel' )) {
$appVars = get_class_vars ( 'AppModel' );
$actsAs = $appVars [ 'actsAs' ];
$merge = array ( 'actsAs' );
if ( $this -> actsAs !== null || $this -> actsAs !== false ) {
$merge [] = 'actsAs' ;
}
foreach ( $merge as $var ) {
if ( isset ( $appVars [ $var ]) && ! empty ( $appVars [ $var ]) && is_array ( $this -> { $var })) {
$this -> { $var } = array_merge ( $this -> { $var }, array_diff ( $appVars [ $var ], $this -> { $var }));
}
}
}
2006-07-30 12:24:03 +00:00
if ( $this -> actsAs !== null && empty ( $this -> behaviors )) {
$callbacks = array ( 'setup' , 'beforeFind' , 'afterFind' , 'beforeSave' , 'afterSave' , 'beforeDelete' , 'afterDelete' , 'afterError' );
2007-01-20 20:50:57 +00:00
$this -> actsAs = Set :: normalize ( $this -> actsAs );
2006-07-30 12:24:03 +00:00
foreach ( $this -> actsAs as $behavior => $config ) {
2006-10-20 17:24:37 +00:00
$className = $behavior . 'Behavior' ;
2006-07-30 12:24:03 +00:00
if ( ! loadBehavior ( $behavior )) {
// Raise an error
} else {
2006-10-20 17:24:37 +00:00
if ( ClassRegistry :: isKeySet ( $className )) {
if ( PHP5 ) {
$this -> behaviors [ $behavior ] = ClassRegistry :: getObject ( $className );
} else {
$this -> behaviors [ $behavior ] =& ClassRegistry :: getObject ( $className );
}
} else {
if ( PHP5 ) {
$this -> behaviors [ $behavior ] = new $className ;
} else {
$this -> behaviors [ $behavior ] =& new $className ;
}
ClassRegistry :: addObject ( $className , $this -> behaviors [ $behavior ]);
}
2006-07-30 12:24:03 +00:00
$this -> behaviors [ $behavior ] -> setup ( $this , $config );
$methods = $this -> behaviors [ $behavior ] -> mapMethods ;
foreach ( $methods as $method => $alias ) {
if ( ! array_key_exists ( $method , $this -> __behaviorMethods )) {
$this -> __behaviorMethods [ $method ] = array ( $alias , $behavior );
}
}
$methods = get_class_methods ( $this -> behaviors [ $behavior ]);
$parentMethods = get_class_methods ( 'ModelBehavior' );
foreach ( $methods as $m ) {
if ( ! in_array ( $m , $parentMethods )) {
if ( strpos ( $m , '_' ) !== 0 && ! array_key_exists ( $m , $this -> __behaviorMethods ) && ! in_array ( $m , $callbacks )) {
$this -> __behaviorMethods [ $m ] = array ( $m , $behavior );
}
}
}
}
}
}
}
/**
* Handles custom method calls , like findBy < field > for DB models ,
* and custom RPC calls for remote data sources .
*
2006-08-03 06:49:51 +00:00
* @ param string $method Name of method to call .
2006-07-30 12:24:03 +00:00
* @ param array $params Parameters for the method .
* @ return unknown
* @ access protected
*/
2006-12-26 16:17:37 +00:00
function call__ ( $method , $params ) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 16:49:40 +00:00
2006-10-20 17:24:37 +00:00
$methods = array_map ( 'strtolower' , array_keys ( $this -> __behaviorMethods ));
2006-07-30 12:24:03 +00:00
$call = array_values ( $this -> __behaviorMethods );
2006-10-20 17:24:37 +00:00
$map = array ();
2006-10-27 21:42:29 +00:00
2006-10-20 17:24:37 +00:00
if ( ! empty ( $methods ) && ! empty ( $call )) {
$map = array_combine ( $methods , $call );
}
2006-07-30 12:24:03 +00:00
$count = count ( $call );
2007-02-08 17:50:47 +00:00
$pass = array ( & $this );
if ( ! in_array ( low ( $method ), $methods )) {
$pass [] = $method ;
}
foreach ( $params as $param ) {
$pass [] = $param ;
}
2006-07-30 12:24:03 +00:00
2006-10-20 17:24:37 +00:00
if ( in_array ( low ( $method ), $methods )) {
2007-02-08 17:50:47 +00:00
$it = $map [ low ( $method )];
return call_user_func_array ( array ( & $this -> behaviors [ $it [ 1 ]], $it [ 0 ]), $pass );
2006-10-20 17:24:37 +00:00
}
2007-06-20 06:15:35 +00:00
for ( $i = 0 ; $i < $count ; $i ++ ) {
2006-10-20 17:24:37 +00:00
if ( strpos ( $methods [ $i ], '/' ) === 0 && preg_match ( $methods [ $i ] . 'i' , $method )) {
2007-02-08 17:50:47 +00:00
return call_user_func_array ( array ( $this -> behaviors [ $call [ $i ][ 1 ]], $call [ $i ][ 0 ]), $pass );
2006-07-30 12:24:03 +00:00
}
}
2006-11-27 05:57:53 +00:00
$return = $db -> query ( $method , $params , $this );
2006-12-19 19:26:02 +00:00
2006-11-27 05:57:53 +00:00
if ( ! PHP5 ) {
2007-03-26 17:16:43 +00:00
if ( ! empty ( $this -> __backAssociation )) {
2006-11-27 05:57:53 +00:00
$this -> __resetAssociations ();
}
}
return $return ;
2006-07-30 12:24:03 +00:00
}
2007-01-06 04:58:24 +00:00
/**
* Bind model associations on the fly .
*
2007-01-06 08:41:48 +00:00
* If $permanent is true , association will not be reset
2007-01-06 04:58:24 +00:00
* to the originals defined in the model
*
* @ param array $params
2007-01-06 08:41:48 +00:00
* @ param boolean $permanent
2007-01-06 04:58:24 +00:00
* @ return void
*/
2007-01-31 23:25:05 +00:00
function bind ( $model , $options , $permanent = true ) {
if ( ! is_array ( $model )) {
$model = array ( $model => $options );
}
2007-06-20 06:15:35 +00:00
foreach ( $model as $name => $options ) {
2007-01-31 23:25:05 +00:00
if ( isset ( $options [ 'type' ])) {
$assoc = $options [ 'type' ];
} elseif ( isset ( $options [ 0 ])) {
$assoc = $options [ 0 ];
}
2007-06-20 06:15:35 +00:00
if ( ! $permanent ) {
2007-01-31 23:25:05 +00:00
$this -> __backAssociation [ $assoc ] = $this -> { $assoc };
}
2007-06-20 06:15:35 +00:00
foreach ( $model as $key => $value ) {
2007-01-31 23:25:05 +00:00
$assocName = $key ;
$modelName = $key ;
if ( isset ( $value [ 'className' ])) {
$modelName = $value [ 'className' ];
}
2007-01-24 10:47:12 +00:00
2007-01-31 23:25:05 +00:00
$this -> __constructLinkedModel ( $assocName , $modelName );
$this -> { $assoc }[ $assocName ] = $model [ $assocName ];
$this -> __generateAssociation ( $assoc );
}
}
2007-01-06 04:58:24 +00:00
}
2006-07-30 12:24:03 +00:00
/**
* Bind model associations on the fly .
2006-12-28 04:02:38 +00:00
*
* If $reset is false , association will not be reset
* to the originals defined in the model
2006-07-30 12:24:03 +00:00
*
* @ param array $params
2006-12-28 04:02:38 +00:00
* @ param boolean $reset
2006-07-30 12:24:03 +00:00
* @ return boolean Always true
*/
2007-02-01 18:45:38 +00:00
function bindModel ( $params , $reset = true ) {
2006-07-30 12:24:03 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $params as $assoc => $model ) {
if ( $reset === true ) {
2007-02-01 18:45:38 +00:00
$this -> __backAssociation [ $assoc ] = $this -> { $assoc };
}
2006-07-30 12:24:03 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $model as $key => $value ) {
2006-07-30 12:24:03 +00:00
$assocName = $key ;
2007-02-01 18:37:42 +00:00
if ( is_numeric ( $key )) {
$assocName = $value ;
$value = array ();
2006-07-30 12:24:03 +00:00
}
2007-02-01 18:37:42 +00:00
$modelName = $assocName ;
$this -> { $assoc }[ $assocName ] = $value ;
2006-07-30 12:24:03 +00:00
}
}
2007-02-01 18:37:42 +00:00
$this -> __createLinks ();
2006-07-30 12:24:03 +00:00
return true ;
}
/**
* Turn off associations on the fly .
*
2006-12-28 04:02:38 +00:00
* If $reset is false , association will not be reset
* to the originals defined in the model
*
* Example : Turn off the associated Model Support request ,
2006-08-03 06:49:51 +00:00
* to temporarily lighten the User model :
* < code >
* $this -> User -> unbindModel ( array ( 'hasMany' => array ( 'Supportrequest' )) );
* </ code >
*
2006-07-30 12:24:03 +00:00
* @ param array $params
2006-12-28 04:02:38 +00:00
* @ param boolean $reset
2006-07-30 12:24:03 +00:00
* @ return boolean Always true
*/
2006-12-28 04:02:38 +00:00
function unbindModel ( $params , $reset = true ) {
2007-06-20 06:15:35 +00:00
foreach ( $params as $assoc => $models ) {
if ( $reset === true ) {
2006-12-28 04:02:38 +00:00
$this -> __backAssociation [ $assoc ] = $this -> { $assoc };
}
2006-07-30 12:24:03 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $models as $model ) {
2006-07-30 12:24:03 +00:00
$this -> __backAssociation = array_merge ( $this -> __backAssociation , $this -> { $assoc });
unset ( $this -> { $assoc }[ $model ]);
}
}
return true ;
}
/**
* Private helper method to create a set of associations .
*
* @ access private
*/
function __createLinks () {
2007-06-20 06:15:35 +00:00
foreach ( $this -> __associations as $type ) {
2006-07-30 12:24:03 +00:00
if ( ! is_array ( $this -> { $type })) {
$this -> { $type } = explode ( ',' , $this -> { $type });
2007-06-20 06:15:35 +00:00
foreach ( $this -> { $type } as $i => $className ) {
2006-07-30 12:24:03 +00:00
$className = trim ( $className );
unset ( $this -> { $type }[ $i ]);
$this -> { $type }[ $className ] = array ();
}
}
2007-06-20 06:15:35 +00:00
foreach ( $this -> { $type } as $assoc => $value ) {
2006-07-30 12:24:03 +00:00
if ( is_numeric ( $assoc )) {
unset ( $this -> { $type }[ $assoc ]);
$assoc = $value ;
$value = array ();
$this -> { $type }[ $assoc ] = $value ;
}
$className = $assoc ;
if ( isset ( $value [ 'className' ]) && ! empty ( $value [ 'className' ])) {
$className = $value [ 'className' ];
}
$this -> __constructLinkedModel ( $assoc , $className );
2007-01-28 01:53:35 +00:00
}
2006-07-30 12:24:03 +00:00
$this -> __generateAssociation ( $type );
}
}
/**
* Private helper method to create associated models of given class .
* @ param string $assoc
* @ param string $className Class name
* @ param mixed $id Primary key ID of linked model
* @ param string $table Database table associated with linked model
* @ param string $ds Name of DataSource the model should be bound to
2007-08-29 20:47:03 +00:00
* @ deprecated $this -> $className use $this -> $assoc instead . $assoc is the 'key' in the associations array ;
* examples : var $hasMany = array ( 'Assoc' => array ( 'className' => 'ModelName' ));
* usage : $this -> Assoc -> modelMethods ();
*
* var $hasMany = array ( 'ModelName' );
* usage : $this -> ModelName -> modelMethods ();
2006-07-30 12:24:03 +00:00
* @ access private
*/
2007-08-14 23:12:24 +00:00
function __constructLinkedModel ( $assoc , $className = null , $id = false , $table = null , $ds = null ) {
2006-07-30 12:24:03 +00:00
$colKey = Inflector :: underscore ( $className );
2007-08-14 23:12:24 +00:00
if ( empty ( $className )) {
$className = $assoc ;
}
2006-11-22 20:08:53 +00:00
2007-06-20 06:15:35 +00:00
if ( ! class_exists ( $className )) {
2007-02-15 18:45:47 +00:00
if ( ! loadModel ( $className )) {
2007-04-11 18:01:24 +00:00
return $this -> cakeError ( 'missingModel' , array ( array ( 'className' => $className )));
2007-02-15 18:45:47 +00:00
}
2006-11-22 20:08:53 +00:00
}
2006-07-30 12:24:03 +00:00
if ( ClassRegistry :: isKeySet ( $colKey )) {
2006-08-06 23:21:36 +00:00
if ( ! PHP5 ) {
2006-09-14 21:59:51 +00:00
$this -> { $assoc } =& ClassRegistry :: getObject ( $colKey );
2007-02-05 04:53:31 +00:00
ClassRegistry :: map ( $assoc , $colKey );
2006-07-30 16:49:40 +00:00
} else {
2006-09-14 21:59:51 +00:00
$this -> { $assoc } = ClassRegistry :: getObject ( $colKey );
2007-02-05 04:53:31 +00:00
ClassRegistry :: map ( $assoc , $colKey );
2006-07-30 16:49:40 +00:00
}
2006-07-30 12:24:03 +00:00
} else {
2006-08-06 23:21:36 +00:00
if ( ! PHP5 ) {
2006-09-14 21:59:51 +00:00
$this -> { $assoc } =& new $className ( $id , $table , $ds );
2006-07-30 16:49:40 +00:00
} else {
2006-09-14 21:59:51 +00:00
$this -> { $assoc } = new $className ( $id , $table , $ds );
2006-07-30 16:49:40 +00:00
}
2006-07-30 12:24:03 +00:00
}
2006-09-14 21:59:51 +00:00
$this -> alias [ $assoc ] = $this -> { $assoc } -> table ;
2006-11-03 21:01:24 +00:00
$this -> tableToModel [ $this -> { $assoc } -> table ] = $className ;
2006-09-14 21:59:51 +00:00
$this -> modelToTable [ $assoc ] = $this -> { $assoc } -> table ;
2006-07-30 12:24:03 +00:00
}
/**
* Build array - based association from string .
*
2007-01-31 23:25:05 +00:00
* @ param string $type 'belongsTo' , 'hasOne' , 'hasMany' , 'hasAndBelongsToMany'
2006-07-30 12:24:03 +00:00
* @ access private
*/
function __generateAssociation ( $type ) {
2007-06-20 06:15:35 +00:00
foreach ( $this -> { $type } as $assocKey => $assocData ) {
2006-07-30 12:24:03 +00:00
$class = $assocKey ;
2007-06-20 06:15:35 +00:00
foreach ( $this -> __associationKeys [ $type ] as $key ) {
2006-07-30 12:24:03 +00:00
if ( ! isset ( $this -> { $type }[ $assocKey ][ $key ]) || $this -> { $type }[ $assocKey ][ $key ] == null ) {
$data = '' ;
switch ( $key ) {
case 'fields' :
$data = '' ;
break ;
case 'foreignKey' :
2007-01-31 23:25:05 +00:00
$data = ife ( $type == 'belongsTo' , Inflector :: underscore ( $assocKey ) . '_id' , Inflector :: singularize ( $this -> table ) . '_id' );
2006-07-30 12:24:03 +00:00
break ;
case 'associationForeignKey' :
$data = Inflector :: singularize ( $this -> { $class } -> table ) . '_id' ;
break ;
2007-08-29 10:14:14 +00:00
case 'with' :
$data = Inflector :: camelize ( Inflector :: singularize ( $this -> { $type }[ $assocKey ][ 'joinTable' ]));
break ;
2006-07-30 12:24:03 +00:00
case 'joinTable' :
$tables = array ( $this -> table , $this -> { $class } -> table );
sort ( $tables );
$data = $tables [ 0 ] . '_' . $tables [ 1 ];
break ;
case 'className' :
$data = $class ;
break ;
2007-08-29 10:14:14 +00:00
2006-07-30 12:24:03 +00:00
}
$this -> { $type }[ $assocKey ][ $key ] = $data ;
}
if ( $key == 'foreignKey' && ! isset ( $this -> keyToTable [ $this -> { $type }[ $assocKey ][ $key ]])) {
$this -> keyToTable [ $this -> { $type }[ $assocKey ][ $key ]][ 0 ] = $this -> { $class } -> table ;
$this -> keyToTable [ $this -> { $type }[ $assocKey ][ $key ]][ 1 ] = $this -> { $class } -> name ;
2007-08-14 23:12:24 +00:00
2007-06-20 06:15:35 +00:00
if ( $this -> { $class } -> name != $class ) {
2007-06-08 16:30:22 +00:00
$this -> keyToTable [ $this -> { $type }[ $assocKey ][ $key ]][ 2 ] = $class ;
}
2006-07-30 12:24:03 +00:00
}
}
2007-08-14 23:12:24 +00:00
2007-08-29 10:14:14 +00:00
if ( isset ( $this -> { $type }[ $assocKey ][ 'with' ]) && ! empty ( $this -> { $type }[ $assocKey ][ 'with' ])) {
$joinClass = $this -> { $type }[ $assocKey ][ 'with' ];
if ( ! loadModel ( $joinClass )) {
2007-08-29 20:47:03 +00:00
$this -> { $joinClass } = new AppModel ( array (
'name' => $joinClass ,
'table' => $this -> { $type }[ $assocKey ][ 'joinTable' ],
'ds' => $this -> useDbConfig
));
2007-08-29 10:14:14 +00:00
$this -> { $joinClass } -> name = $joinClass ;
$this -> { $joinClass } -> primaryKey = $this -> { $type }[ $assocKey ][ 'foreignKey' ];
} else {
$this -> __constructLinkedModel ( $joinClass );
2007-08-29 20:47:03 +00:00
$this -> { $joinClass } -> name = $joinClass ;
2007-09-03 04:48:58 +00:00
$this -> { $joinClass } -> primaryKey = $this -> { $type }[ $assocKey ][ 'foreignKey' ];
2007-08-29 10:14:14 +00:00
$this -> { $type }[ $assocKey ][ 'joinTable' ] = $this -> { $joinClass } -> table ;
2007-08-21 21:46:59 +00:00
}
2007-09-03 04:48:58 +00:00
if ( count ( $this -> { $joinClass } -> _schema -> value ) > 2 ) {
if ( isset ( $this -> { $joinClass } -> _schema -> value [ 'id' ])) {
$this -> { $joinClass } -> primaryKey = 'id' ;
}
}
2007-01-31 23:25:05 +00:00
}
2006-07-30 12:24:03 +00:00
}
}
/**
* Sets a custom table for your controller class . Used by your controller to select a database table .
*
* @ param string $tableName Name of the custom table
*/
function setSource ( $tableName ) {
2007-01-10 11:15:43 +00:00
$this -> setDataSource ( $this -> useDbConfig );
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2007-04-08 23:30:31 +00:00
$db -> cacheSources = $this -> cacheSources ;
2007-08-29 00:16:13 +00:00
2006-07-30 12:24:03 +00:00
if ( $db -> isInterfaceSupported ( 'listSources' )) {
$sources = $db -> listSources ();
2007-01-10 11:15:43 +00:00
if ( is_array ( $sources ) && ! in_array ( low ( $this -> tablePrefix . $tableName ), array_map ( 'low' , $sources ))) {
2006-07-30 12:24:03 +00:00
return $this -> cakeError ( 'missingTable' , array ( array (
2007-08-29 00:16:13 +00:00
'className' => $this -> name ,
'table' => $this -> tablePrefix . $tableName )));
2006-07-30 12:24:03 +00:00
}
2007-08-29 00:16:13 +00:00
$this -> _tableInfo = null ;
2006-07-30 12:24:03 +00:00
}
2007-08-29 00:16:13 +00:00
$this -> table = $this -> useTable = $tableName ;
$this -> tableToModel [ $this -> table ] = $this -> name ;
$this -> loadInfo ();
2006-07-30 12:24:03 +00:00
}
/**
* This function does two things : 1 ) it scans the array $one for the primary key ,
* and if that ' s found , it sets the current id to the value of $one [ id ] .
* For all other keys than 'id' the keys and values of $one are copied to the 'data' property of this object .
* 2 ) Returns an array with all of $one ' s keys and values .
* ( Alternative indata : two strings , which are mangled to
* a one - item , two - dimensional array using $one for a key and $two as its value . )
*
* @ param mixed $one Array or string of data
* @ param string $two Value string for the alternative indata method
* @ return unknown
*/
function set ( $one , $two = null ) {
2006-10-09 22:00:22 +00:00
if ( is_object ( $one )) {
2007-06-30 06:52:39 +00:00
$one = Set :: reverse ( $one );
2006-10-09 22:00:22 +00:00
}
2006-07-30 12:24:03 +00:00
if ( is_array ( $one )) {
2006-11-08 03:28:24 +00:00
if ( Set :: countDim ( $one ) == 1 ) {
2006-07-30 12:24:03 +00:00
$data = array ( $this -> name => $one );
} else {
$data = $one ;
}
} else {
$data = array ( $this -> name => array ( $one => $two ));
}
2007-06-20 06:15:35 +00:00
foreach ( $data as $n => $v ) {
2006-07-30 12:24:03 +00:00
if ( is_array ( $v )) {
2007-06-20 06:15:35 +00:00
foreach ( $v as $x => $y ) {
2006-07-30 12:24:03 +00:00
if ( $n == $this -> name ) {
if ( isset ( $this -> validationErrors [ $x ])) {
unset ( $this -> validationErrors [ $x ]);
}
2007-05-12 05:20:40 +00:00
if ( $x === $this -> primaryKey ) {
2006-07-30 12:24:03 +00:00
$this -> id = $y ;
}
}
$this -> data [ $n ][ $x ] = $y ;
}
}
}
return $data ;
}
/**
* Returns an array of table metadata ( column names and types ) from the database .
2007-08-21 21:46:59 +00:00
* $field => keys ( type , null , default , key , length , extra )
2006-07-30 12:24:03 +00:00
*
* @ return array Array of table metadata
*/
2007-08-21 21:46:59 +00:00
function schema ( $clear = false ) {
if ( ! is_object ( $this -> _schema ) || $clear ) {
2007-04-18 16:39:11 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
$db -> cacheSources = $this -> cacheSources ;
if ( $db -> isInterfaceSupported ( 'describe' ) && $this -> useTable !== false ) {
2007-08-21 21:46:59 +00:00
$this -> _schema = new Set ( $db -> describe ( $this , $clear ));
2007-04-18 16:39:11 +00:00
} elseif ( $this -> useTable === false ) {
2007-08-21 21:46:59 +00:00
$this -> _schema = new Set ();
2007-04-18 16:39:11 +00:00
}
2006-07-30 12:24:03 +00:00
}
2007-08-21 21:46:59 +00:00
return $this -> _schema ;
}
/**
* See Model :: schema
*
* @ deprecated
*/
function loadInfo ( $clear = false ) {
$info = $this -> schema ( $clear );
2007-09-28 10:04:25 +00:00
$fields = array ();
2007-08-21 21:46:59 +00:00
foreach ( $info -> value as $field => $value ) {
$fields [] = am ( array ( 'name' => $field ), $value );
}
unset ( $info );
$this -> _tableInfo = new Set ( $fields );
2006-07-30 12:24:03 +00:00
return $this -> _tableInfo ;
}
/**
* Returns an associative array of field names and column types .
*
* @ return array
*/
function getColumnTypes () {
$columns = $this -> loadInfo ();
2007-05-05 17:36:30 +00:00
$names = $columns -> extract ( '{n}.name' );
$types = $columns -> extract ( '{n}.type' );
if ( ! count ( $names ) || ! count ( $types )) {
trigger_error ( __ ( '(Model::getColumnTypes) Unable to build model field data. If you are using a model without a database table, try implementing loadInfo()' , true ), E_USER_WARNING );
}
return array_combine ( $names , $types );
2006-07-30 12:24:03 +00:00
}
/**
* Returns the column type of a column in the model
*
* @ param string $column The name of the model column
* @ return string Column type
*/
function getColumnType ( $column ) {
2007-03-03 15:18:45 +00:00
$cols = $this -> getColumnTypes ();
if ( isset ( $cols [ $column ])) {
return $cols [ $column ];
2006-07-30 12:24:03 +00:00
}
return null ;
}
/**
* Returns true if this Model has given field in its database table .
*
* @ param string $name Name of field to look for
* @ return boolean
*/
function hasField ( $name ) {
2006-12-19 19:26:02 +00:00
if ( is_array ( $name )) {
foreach ( $name as $n ) {
if ( $this -> hasField ( $n )) {
return $n ;
}
}
return false ;
}
2006-07-30 12:24:03 +00:00
if ( empty ( $this -> _tableInfo )) {
$this -> loadInfo ();
}
if ( $this -> _tableInfo != null ) {
2006-11-21 22:40:30 +00:00
return in_array ( $name , $this -> _tableInfo -> extract ( '{n}.name' ));
2006-07-30 12:24:03 +00:00
}
2006-11-21 22:40:30 +00:00
return false ;
2006-07-30 12:24:03 +00:00
}
/**
* Initializes the model for writing a new record .
*
* @ param array $data Optional data to assign to the model after it is created
2006-10-27 22:35:40 +00:00
* @ return array The current data of the model
2006-07-30 12:24:03 +00:00
*/
2007-01-16 12:53:39 +00:00
function create ( $data = array ()) {
2006-07-30 12:24:03 +00:00
$this -> id = false ;
$this -> data = array ();
2007-01-16 12:53:39 +00:00
$defaults = array ();
2006-08-03 06:49:51 +00:00
2006-07-30 12:24:03 +00:00
$cols = $this -> loadInfo ();
2007-03-17 00:24:33 +00:00
$names = $cols -> extract ( '{n}.name' );
$values = $cols -> extract ( '{n}.default' );
if ( ! empty ( $names ) && ! empty ( $values )) {
$count = count ( $names );
2006-07-30 12:24:03 +00:00
for ( $i = 0 ; $i < $count ; $i ++ ) {
2007-03-17 00:24:33 +00:00
if ( $names [ $i ] != $this -> primaryKey ) {
$defaults [ $names [ $i ]] = $values [ $i ];
2006-07-30 12:24:03 +00:00
}
}
}
2007-03-17 00:24:33 +00:00
2007-01-22 08:22:10 +00:00
$this -> validationErrors = array ();
2007-06-10 17:41:35 +00:00
$this -> set ( Set :: filter ( $defaults ));
2007-02-15 18:45:47 +00:00
$this -> set ( $data );
2006-10-27 18:14:35 +00:00
return $this -> data ;
2006-07-30 12:24:03 +00:00
}
/**
* Returns a list of fields from the database
*
* @ param mixed $id The ID of the record to read
* @ param mixed $fields String of single fieldname , or an array of fieldnames .
* @ return array Array of database fields
*/
function read ( $fields = null , $id = null ) {
$this -> validationErrors = array ();
if ( $id != null ) {
$this -> id = $id ;
}
$id = $this -> id ;
if ( is_array ( $this -> id )) {
$id = $this -> id [ 0 ];
}
if ( $this -> id !== null && $this -> id !== false ) {
2007-02-08 17:50:47 +00:00
$this -> data = $this -> find ( array ( $this -> name . '.' . $this -> primaryKey => $id ), $fields );
return $this -> data ;
2006-07-30 12:24:03 +00:00
} else {
return false ;
}
}
/**
* Returns contents of a field in a query matching given conditions .
*
* @ param string $name Name of field to get
* @ param array $conditions SQL conditions ( defaults to NULL )
* @ param string $order SQL ORDER BY fragment
* @ return field contents
*/
function field ( $name , $conditions = null , $order = null ) {
if ( $conditions === null ) {
$conditions = array ( $this -> name . '.' . $this -> primaryKey => $this -> id );
}
2007-06-20 06:15:35 +00:00
if ( $this -> recursive >= 1 ) {
2007-01-10 11:15:43 +00:00
$recursive = - 1 ;
} else {
$recursive = $this -> recursive ;
}
if ( $data = $this -> find ( $conditions , $name , $order , $recursive )) {
2006-07-30 12:24:03 +00:00
if ( strpos ( $name , '.' ) === false ) {
if ( isset ( $data [ $this -> name ][ $name ])) {
return $data [ $this -> name ][ $name ];
}
} else {
$name = explode ( '.' , $name );
if ( isset ( $data [ $name [ 0 ]][ $name [ 1 ]])) {
return $data [ $name [ 0 ]][ $name [ 1 ]];
}
}
2007-03-26 18:38:54 +00:00
if ( isset ( $data [ 0 ]) && count ( $data [ 0 ]) > 0 ) {
$name = key ( $data [ 0 ]);
return $data [ 0 ][ $name ];
}
2006-07-30 12:24:03 +00:00
} else {
return false ;
}
}
/**
* Saves a single field to the database .
*
* @ param string $name Name of the table field
* @ param mixed $value Value of the field
* @ param boolean $validate Whether or not this model should validate before saving ( defaults to false )
* @ return boolean True on success save
*/
function saveField ( $name , $value , $validate = false ) {
2007-03-17 00:24:33 +00:00
return $this -> save ( array ( $this -> name => array ( $name => $value )), $validate , array ( $name ));
2006-07-30 12:24:03 +00:00
}
/**
* Saves model data to the database .
* By default , validation occurs before save .
*
* @ param array $data Data to save .
* @ param boolean $validate If set , validation will be done before the save
* @ param array $fieldList List of fields to allow to be written
* @ return boolean success
*/
function save ( $data = null , $validate = true , $fieldList = array ()) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
2006-10-09 22:00:22 +00:00
$this -> set ( $data );
2007-08-14 23:12:24 +00:00
$whitelist = ! empty ( $fieldList );
2006-07-30 12:24:03 +00:00
if ( $validate && ! $this -> validates ()) {
return false ;
}
2006-12-19 19:26:02 +00:00
if ( ! empty ( $this -> behaviors )) {
$behaviors = array_keys ( $this -> behaviors );
$ct = count ( $behaviors );
for ( $i = 0 ; $i < $ct ; $i ++ ) {
if ( $this -> behaviors [ $behaviors [ $i ]] -> beforeSave ( $this ) === false ) {
return false ;
}
}
}
2006-07-30 12:24:03 +00:00
if ( ! $this -> beforeSave ()) {
return false ;
}
$fields = $values = array ();
2007-06-21 13:53:51 +00:00
$habtm = count ( $this -> hasAndBelongsToMany );
2006-07-30 12:24:03 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $this -> data as $n => $v ) {
2007-06-28 02:47:16 +00:00
if ( isset ( $v [ $n ]) && $habtm > 0 ) {
2006-07-30 12:24:03 +00:00
$joined [] = $v ;
} else {
if ( $n === $this -> name ) {
2006-09-11 00:35:06 +00:00
foreach ( array ( 'created' , 'updated' , 'modified' ) as $field ) {
if ( array_key_exists ( $field , $v ) && ( empty ( $v [ $field ]) || $v [ $field ] === null )) {
unset ( $v [ $field ]);
}
}
2006-09-14 18:50:33 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $v as $x => $y ) {
2006-07-30 12:24:03 +00:00
if ( $this -> hasField ( $x ) && ( $whitelist && in_array ( $x , $fieldList ) || ! $whitelist )) {
$fields [] = $x ;
$values [] = $y ;
}
}
}
}
}
2007-10-01 16:49:37 +00:00
2006-12-12 22:06:22 +00:00
$exists = $this -> exists ();
2006-07-30 12:24:03 +00:00
2006-12-12 22:06:22 +00:00
if ( ! $exists && $this -> hasField ( 'created' ) && ! in_array ( 'created' , $fields ) && ( $whitelist && in_array ( 'created' , $fieldList ) || ! $whitelist )) {
2007-01-31 23:25:05 +00:00
$colType = am ( array ( 'formatter' => 'date' ), $db -> columns [ $this -> getColumnType ( 'created' )]);
2006-07-30 12:24:03 +00:00
$fields [] = 'created' ;
2007-01-31 23:25:05 +00:00
$values [] = $colType [ 'formatter' ]( $colType [ 'format' ]);
2006-07-30 12:24:03 +00:00
}
2006-12-12 22:06:22 +00:00
foreach ( array ( 'modified' , 'updated' ) as $updateCol ) {
if ( $this -> hasField ( $updateCol ) && ! in_array ( $updateCol , $fields ) && ( $whitelist && in_array ( $updateCol , $fieldList ) || ! $whitelist )) {
2007-01-31 23:25:05 +00:00
$colType = am ( array ( 'formatter' => 'date' ), $db -> columns [ $this -> getColumnType ( $updateCol )]);
2006-12-12 22:06:22 +00:00
$fields [] = $updateCol ;
2007-01-31 23:25:05 +00:00
$values [] = $colType [ 'formatter' ]( $colType [ 'format' ]);
2006-12-12 22:06:22 +00:00
}
2006-07-30 12:24:03 +00:00
}
2007-06-28 02:47:16 +00:00
$count = count ( $fields );
2006-07-30 12:24:03 +00:00
2007-06-28 02:47:16 +00:00
if ( ! $exists && $count > 0 ) {
2006-07-30 12:24:03 +00:00
$this -> id = false ;
}
2007-06-28 02:47:16 +00:00
$success = true ;
2007-02-07 00:36:19 +00:00
$created = false ;
2006-07-30 12:24:03 +00:00
2007-06-28 02:47:16 +00:00
if ( $count > 0 ) {
2006-07-30 12:24:03 +00:00
if ( ! empty ( $this -> id )) {
2007-06-28 02:47:16 +00:00
if ( ! $db -> update ( $this , $fields , $values )) {
$success = false ;
2006-07-30 12:24:03 +00:00
}
} else {
2007-08-20 01:58:44 +00:00
foreach ( $this -> _tableInfo -> value as $key => $value ) {
if ( in_array ( $this -> primaryKey , $value )) {
2007-09-10 12:06:53 +00:00
if ( empty ( $this -> data [ $this -> name ][ $this -> primaryKey ]) && $this -> _tableInfo -> value [ $key ][ 'type' ] === 'string' && $this -> _tableInfo -> value [ $key ][ 'length' ] === 36 ) {
2007-08-20 01:58:44 +00:00
$fields [] = $this -> primaryKey ;
$values [] = String :: uuid ();
}
break ;
}
}
2007-06-28 02:47:16 +00:00
if ( ! $db -> create ( $this , $fields , $values )) {
$success = $created = false ;
} else {
$created = true ;
2006-09-11 00:35:06 +00:00
if ( ! empty ( $this -> belongsTo )) {
foreach ( $this -> belongsTo as $parent => $assoc ) {
if ( isset ( $assoc [ 'counterCache' ]) && ! empty ( $assoc [ 'counterCache' ])) {
$parentObj =& $this -> { $assoc [ 'className' ]};
}
}
}
2007-02-07 00:36:19 +00:00
}
}
2007-06-28 02:47:16 +00:00
}
2006-07-30 12:24:03 +00:00
2007-06-28 02:47:16 +00:00
if ( ! empty ( $joined ) && $success === true ) {
$this -> __saveMulti ( $joined , $this -> id );
}
if ( $success && $count > 0 ) {
if ( ! empty ( $this -> behaviors )) {
$behaviors = array_keys ( $this -> behaviors );
$ct = count ( $behaviors );
for ( $i = 0 ; $i < $ct ; $i ++ ) {
$this -> behaviors [ $behaviors [ $i ]] -> afterSave ( $this , $created );
2006-07-30 12:24:03 +00:00
}
}
2007-06-28 02:47:16 +00:00
$this -> afterSave ( $created );
$this -> data = false ;
$this -> _clearCache ();
$this -> validationErrors = array ();
return true ;
2006-07-30 12:24:03 +00:00
}
2007-06-28 02:47:16 +00:00
2007-02-07 00:36:19 +00:00
return $success ;
2006-07-30 12:24:03 +00:00
}
/**
* Saves model hasAndBelongsToMany data to the database .
*
* @ param array $joined Data to save .
* @ param string $id
* @ return
* @ access private
*/
function __saveMulti ( $joined , $id ) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2007-06-20 06:15:35 +00:00
foreach ( $joined as $x => $y ) {
foreach ( $y as $assoc => $value ) {
2007-03-31 20:27:47 +00:00
if ( isset ( $this -> hasAndBelongsToMany [ $assoc ])) {
$joinTable [ $assoc ] = $this -> hasAndBelongsToMany [ $assoc ][ 'joinTable' ];
2007-06-28 17:31:26 +00:00
$mainKey [ $assoc ] = $db -> name ( $this -> hasAndBelongsToMany [ $assoc ][ 'foreignKey' ]);
$keys [] = $db -> name ( $this -> hasAndBelongsToMany [ $assoc ][ 'foreignKey' ]);
$keys [] = $db -> name ( $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]);
2007-03-31 20:27:47 +00:00
$fields [ $assoc ] = join ( ',' , $keys );
unset ( $keys );
2007-04-08 23:30:31 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $value as $update ) {
2007-03-31 20:27:47 +00:00
if ( ! empty ( $update )) {
$values [] = $db -> value ( $id , $this -> getColumnType ( $this -> primaryKey ));
$values [] = $db -> value ( $update );
$values = join ( ',' , $values );
$newValues [] = " ( { $values } ) " ;
unset ( $values );
}
}
2007-04-08 23:30:31 +00:00
2007-03-31 20:27:47 +00:00
if ( ! empty ( $newValues )) {
$newValue [ $assoc ] = $newValues ;
unset ( $newValues );
} else {
$newValue [ $assoc ] = array ();
2006-07-30 12:24:03 +00:00
}
}
}
}
2007-04-08 23:30:31 +00:00
2007-06-28 17:31:26 +00:00
if ( isset ( $joinTable ) && is_array ( $newValue )) {
foreach ( $newValue as $loopAssoc => $val ) {
$table = $db -> name ( $db -> fullTableName ( $joinTable [ $loopAssoc ]));
$db -> query ( " DELETE FROM { $table } WHERE { $mainKey [ $loopAssoc ] } = ' { $id } ' " );
2007-04-08 23:30:31 +00:00
2007-06-28 17:31:26 +00:00
if ( ! empty ( $newValue [ $loopAssoc ])) {
2007-07-25 04:38:28 +00:00
$db -> insertMulti ( $table , $fields [ $loopAssoc ], $newValue [ $loopAssoc ]);
2006-07-30 12:24:03 +00:00
}
}
}
}
2006-10-09 22:00:22 +00:00
/**
* Allows model records to be updated based on a set of conditions
*
* @ param mixed $conditions
* @ param mixed $fields
* @ return boolean True on success , false on failure
*/
2007-02-08 18:36:26 +00:00
function updateAll ( $fields , $conditions = true ) {
2006-10-20 17:24:37 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
return $db -> update ( $this , $fields , null , $conditions );
2006-10-09 22:00:22 +00:00
}
2006-07-30 12:24:03 +00:00
/**
* Synonym for del () .
*
* @ param mixed $id
* @ see function del
* @ return boolean True on success
*/
function remove ( $id = null , $cascade = true ) {
return $this -> del ( $id , $cascade );
}
/**
* Removes record for given id . If no id is given , the current id is used . Returns true on success .
*
* @ param mixed $id Id of record to delete
* @ return boolean True on success
*/
function del ( $id = null , $cascade = true ) {
2006-12-13 04:04:15 +00:00
if ( ! empty ( $id )) {
2006-07-30 12:24:03 +00:00
$this -> id = $id ;
}
2007-04-30 02:46:51 +00:00
$id = $this -> id ;
2006-07-30 12:24:03 +00:00
2006-12-13 04:04:15 +00:00
if ( $this -> exists () && $this -> beforeDelete ()) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
2006-12-19 19:26:02 +00:00
if ( ! empty ( $this -> behaviors )) {
$behaviors = array_keys ( $this -> behaviors );
$ct = count ( $behaviors );
for ( $i = 0 ; $i < $ct ; $i ++ ) {
if ( $this -> behaviors [ $behaviors [ $i ]] -> beforeDelete ( $this ) === false ) {
return false ;
}
}
}
2007-04-30 02:46:51 +00:00
$this -> _deleteDependent ( $id , $cascade );
$this -> _deleteLinks ( $id );
2007-05-01 00:19:42 +00:00
$this -> id = $id ;
2006-12-19 19:26:02 +00:00
if ( $db -> delete ( $this )) {
if ( ! empty ( $this -> behaviors )) {
for ( $i = 0 ; $i < $ct ; $i ++ ) {
2007-02-10 20:28:22 +00:00
$this -> behaviors [ $behaviors [ $i ]] -> afterDelete ( $this );
2006-12-19 19:26:02 +00:00
}
}
2006-07-30 12:24:03 +00:00
$this -> afterDelete ();
$this -> _clearCache ();
$this -> id = false ;
2007-10-01 16:49:37 +00:00
$this -> __exists = null ;
2006-07-30 12:24:03 +00:00
return true ;
}
}
return false ;
}
/**
* Alias for del ()
*
* @ param mixed $id Id of record to delete
* @ return boolean True on success
*/
function delete ( $id = null , $cascade = true ) {
return $this -> del ( $id , $cascade );
}
/**
2007-01-31 23:25:05 +00:00
* Cascades model deletes to hasMany and hasOne relationships .
2006-07-30 12:24:03 +00:00
*
* @ param string $id
* @ return null
* @ access protected
*/
2007-01-31 23:25:05 +00:00
function _deleteDependent ( $id , $cascade ) {
2007-03-26 17:16:43 +00:00
if ( ! empty ( $this -> __backAssociation )) {
2006-11-23 11:31:59 +00:00
$savedAssociatons = $this -> __backAssociation ;
2007-03-26 17:16:43 +00:00
$this -> __backAssociation = array ();
2006-11-23 11:31:59 +00:00
}
2007-06-20 06:15:35 +00:00
foreach ( am ( $this -> hasMany , $this -> hasOne ) as $assoc => $data ) {
2006-07-30 12:24:03 +00:00
if ( $data [ 'dependent' ] === true && $cascade === true ) {
2007-01-31 23:25:05 +00:00
$model =& $this -> { $assoc };
2006-07-30 12:24:03 +00:00
$field = $model -> escapeField ( $data [ 'foreignKey' ]);
2007-01-31 23:25:05 +00:00
$model -> recursive = - 1 ;
$records = $model -> findAll ( array ( $field => $id ), $model -> primaryKey );
2006-07-30 12:24:03 +00:00
2007-06-20 06:15:35 +00:00
if ( ! empty ( $records )) {
foreach ( $records as $record ) {
2007-01-31 23:25:05 +00:00
$model -> delete ( $record [ $model -> name ][ $model -> primaryKey ]);
2006-11-23 11:05:47 +00:00
}
2006-07-30 12:24:03 +00:00
}
}
}
2006-11-23 11:31:59 +00:00
if ( isset ( $savedAssociatons )) {
$this -> __backAssociation = $savedAssociatons ;
}
2006-07-30 12:24:03 +00:00
}
/**
2007-01-31 23:25:05 +00:00
* Cascades model deletes to HABTM join keys .
2006-07-30 12:24:03 +00:00
*
* @ param string $id
* @ return null
* @ access protected
*/
2007-01-31 23:25:05 +00:00
function _deleteLinks ( $id ) {
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2007-06-20 06:15:35 +00:00
foreach ( $this -> hasAndBelongsToMany as $assoc => $data ) {
2007-01-31 23:25:05 +00:00
if ( isset ( $data [ 'with' ])) {
$model =& $this -> { $data [ 'with' ]};
$records = $model -> findAll ( array ( $data [ 'foreignKey' ] => $id ), $model -> primaryKey , null , null , null , - 1 );
2006-07-30 12:24:03 +00:00
2007-01-31 23:25:05 +00:00
if ( ! empty ( $records )) {
2007-06-20 06:15:35 +00:00
foreach ( $records as $record ) {
2007-01-31 23:25:05 +00:00
$model -> delete ( $record [ $model -> name ][ $model -> primaryKey ]);
2006-11-23 11:05:47 +00:00
}
2006-07-30 12:24:03 +00:00
}
2007-01-31 23:25:05 +00:00
} else {
$table = $db -> name ( $db -> fullTableName ( $data [ 'joinTable' ]));
$conditions = $db -> name ( $data [ 'foreignKey' ]) . ' = ' . $db -> value ( $id );
$db -> query ( " DELETE FROM { $table } WHERE { $conditions } " );
2006-07-30 12:24:03 +00:00
}
}
}
2006-11-21 22:40:30 +00:00
/**
* Allows model records to be deleted based on a set of conditions
*
* @ param mixed $conditions
* @ param mixed $fields
* @ return boolean True on success , false on failure
*/
function deleteAll ( $conditions , $cascade = true ) {
2007-02-08 17:50:47 +00:00
if ( empty ( $conditions )) {
return false ;
}
$records = $this -> findAll ( $conditions , array ( $this -> escapeField ()), null , null , null , 0 );
if ( empty ( $records )) {
return false ;
}
$ids = Set :: extract ( $records , " { n}. { $this -> name } . { $this -> primaryKey } " );
foreach ( $ids as $id ) {
$this -> _deleteLinks ( $id );
$this -> _deleteDependent ( $id , $cascade );
}
2006-11-21 22:40:30 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2007-06-27 19:13:44 +00:00
return $db -> delete ( $this , array ( $this -> primaryKey => $ids ));
2006-11-21 22:40:30 +00:00
}
2006-07-30 12:24:03 +00:00
/**
* Returns true if a record with set id exists .
*
2007-10-01 16:49:37 +00:00
* @ param boolean $reset if true will force database query
2006-07-30 12:24:03 +00:00
* @ return boolean True if such a record exists
*/
2007-10-01 16:49:37 +00:00
function exists ( $reset = false ) {
2006-10-27 18:14:35 +00:00
if ( $this -> getID () === false ) {
return false ;
2006-07-30 12:24:03 +00:00
}
2007-10-01 16:49:37 +00:00
if ( $this -> __exists !== null && $reset !== true ) {
return $this -> __exists ;
}
return $this -> __exists = ( $this -> findCount ( array ( $this -> name . '.' . $this -> primaryKey => $this -> getID ()), - 1 ) > 0 );
2006-07-30 12:24:03 +00:00
}
/**
* Returns true if a record that meets given conditions exists
*
* @ param array $conditions SQL conditions array
* @ return boolean True if such a record exists
*/
function hasAny ( $conditions = null ) {
return ( $this -> findCount ( $conditions ) != false );
}
/**
* Return a single row as a resultset array .
* By using the $recursive parameter , the call can access further " levels of association " than
* the ones this model is directly associated to .
*
* @ param array $conditions SQL conditions array
* @ param mixed $fields Either a single string of a field name , or an array of field names
* @ param string $order SQL ORDER BY conditions ( e . g . " price DESC " or " name ASC " )
* @ param int $recursive The number of levels deep to fetch associated records
* @ return array Array of records
*/
function find ( $conditions = null , $fields = null , $order = null , $recursive = null ) {
$data = $this -> findAll ( $conditions , $fields , $order , 1 , null , $recursive );
if ( empty ( $data [ 0 ])) {
return false ;
}
return $data [ 0 ];
}
/**
* Returns a resultset array with specified fields from database matching given conditions .
* By using the $recursive parameter , the call can access further " levels of association " than
* the ones this model is directly associated to .
*
* @ param mixed $conditions SQL conditions as a string or as an array ( 'field' => 'value' , ... )
* @ param mixed $fields Either a single string of a field name , or an array of field names
* @ param string $order SQL ORDER BY conditions ( e . g . " price DESC " or " name ASC " )
* @ param int $limit SQL LIMIT clause , for calculating items per page .
* @ param int $page Page number , for accessing paged data
* @ param int $recursive The number of levels deep to fetch associated records
* @ return array Array of records
*/
function findAll ( $conditions = null , $fields = null , $order = null , $limit = null , $page = 1 , $recursive = null ) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
$this -> id = $this -> getID ();
$offset = null ;
2006-11-08 03:28:24 +00:00
if ( empty ( $page ) || ! is_numeric ( $page ) || intval ( $page ) < 1 ) {
$page = 1 ;
}
2006-07-30 12:24:03 +00:00
if ( $page > 1 && $limit != null ) {
$offset = ( $page - 1 ) * $limit ;
}
2007-03-25 18:17:15 +00:00
if ( $order == null && $order !== false ) {
2006-07-30 12:24:03 +00:00
if ( $this -> order == null ) {
$order = array ();
} else {
$order = array ( $this -> order );
}
} else {
$order = array ( $order );
}
$queryData = array (
'conditions' => $conditions ,
'fields' => $fields ,
'joins' => array (),
'limit' => $limit ,
'offset' => $offset ,
'order' => $order
);
if ( ! empty ( $this -> behaviors )) {
2006-12-19 19:26:02 +00:00
$behaviors = array_keys ( $this -> behaviors );
$ct = count ( $behaviors );
for ( $i = 0 ; $i < $ct ; $i ++ ) {
$ret = $this -> behaviors [ $behaviors [ $i ]] -> beforeFind ( $this , $queryData );
if ( is_array ( $ret )) {
$queryData = $ret ;
} elseif ( $ret === false ) {
return null ;
}
2006-07-30 12:24:03 +00:00
}
}
2006-12-19 19:26:02 +00:00
$ret = $this -> beforeFind ( $queryData );
if ( is_array ( $ret )) {
$queryData = $ret ;
} elseif ( $ret === false ) {
2006-07-30 12:24:03 +00:00
return null ;
}
$results = $db -> read ( $this , $queryData , $recursive );
if ( ! empty ( $this -> behaviors )) {
$b = array_keys ( $this -> behaviors );
$c = count ( $b );
for ( $i = 0 ; $i < $c ; $i ++ ) {
2006-12-19 19:26:02 +00:00
$ret = $this -> behaviors [ $b [ $i ]] -> afterFind ( $this , $results , true );
if ( is_array ( $ret )) {
$results = $ret ;
}
2006-07-30 12:24:03 +00:00
}
}
2006-08-18 08:00:54 +00:00
$return = $this -> afterFind ( $results , true );
2006-07-30 12:24:03 +00:00
2007-03-26 17:16:43 +00:00
if ( ! empty ( $this -> __backAssociation )) {
2006-07-30 12:24:03 +00:00
$this -> __resetAssociations ();
}
return $return ;
}
/**
* Method is called only when bindTo < ModelName > () is used .
* This resets the association arrays for the model back
* to the original as set in the model .
*
* @ return unknown
* @ access private
*/
function __resetAssociations () {
2007-06-20 06:15:35 +00:00
foreach ( $this -> __associations as $type ) {
2006-07-30 12:24:03 +00:00
if ( isset ( $this -> __backAssociation [ $type ])) {
$this -> { $type } = $this -> __backAssociation [ $type ];
}
}
2007-03-26 17:16:43 +00:00
$this -> __backAssociation = array ();
2006-07-30 12:24:03 +00:00
return true ;
}
/**
* Runs a direct query against the bound DataSource , and returns the result .
*
* @ param string $data Query data
* @ return array
*/
function execute ( $data ) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
$data = $db -> fetchAll ( $data , $this -> cacheQueries );
2007-06-20 06:15:35 +00:00
foreach ( $data as $key => $value ) {
foreach ( $this -> tableToModel as $key1 => $value1 ) {
2006-07-30 12:24:03 +00:00
if ( isset ( $data [ $key ][ $key1 ])) {
$newData [ $key ][ $value1 ] = $data [ $key ][ $key1 ];
}
}
}
if ( ! empty ( $newData )) {
return $newData ;
}
return $data ;
}
/**
* Returns number of rows matching given SQL condition .
*
* @ param array $conditions SQL conditions array for findAll
* @ param int $recursize The number of levels deep to fetch associated records
* @ return int Number of matching rows
* @ see Model :: findAll
*/
function findCount ( $conditions = null , $recursive = 0 ) {
2007-06-26 19:02:10 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2007-07-06 17:19:59 +00:00
list ( $data ) = $this -> findAll ( $conditions , 'COUNT(*) AS ' . $db -> name ( 'count' ), false , null , 1 , $recursive );
2006-07-30 12:24:03 +00:00
if ( isset ( $data [ 0 ][ 'count' ])) {
2007-08-04 16:13:48 +00:00
return intval ( $data [ 0 ][ 'count' ]);
2006-11-02 14:44:44 +00:00
} elseif ( isset ( $data [ $this -> name ][ 'count' ])) {
2007-08-04 16:13:48 +00:00
return intval ( $data [ $this -> name ][ 'count' ]);
2006-07-30 12:24:03 +00:00
}
return false ;
}
2007-01-22 08:09:17 +00:00
/**
* False if any fields passed match any ( by default , all if $or = false ) of their matching values .
*
* @ param array $fields Field / value pairs to search ( if no values specified , they are pulled from $this -> data )
* @ param boolean $or If false , all fields specified must match in order for a false return value
* @ return boolean False if any records matching any fields are found
*/
function isUnique ( $fields , $or = true ) {
if ( ! is_array ( $fields )) {
$fields = func_get_args ();
if ( is_bool ( $fields [ count ( $fields ) - 1 ])) {
$or = $fields [ count ( $fields ) - 1 ];
unset ( $fields [ count ( $fields ) - 1 ]);
}
}
foreach ( $fields as $field => $value ) {
if ( is_numeric ( $field )) {
unset ( $fields [ $field ]);
$field = $value ;
if ( isset ( $this -> data [ $this -> name ][ $field ])) {
$value = $this -> data [ $this -> name ][ $field ];
} else {
$value = null ;
}
}
2007-01-24 10:47:12 +00:00
2007-01-22 08:09:17 +00:00
if ( strpos ( $field , '.' ) === false ) {
unset ( $fields [ $field ]);
$fields [ $this -> name . '.' . $field ] = $value ;
}
}
if ( $or ) {
$fields = array ( 'or' => $fields );
}
return ( $this -> findCount ( $fields ) == 0 );
}
2006-07-30 12:24:03 +00:00
/**
* Special findAll variation for tables joined to themselves .
* The table needs the fields id and parent_id to work .
*
* @ param array $conditions Conditions for the findAll () call
* @ param array $fields Fields for the findAll () call
* @ param string $sort SQL ORDER BY statement
* @ return array
* @ todo Perhaps create a Component with this logic
*/
function findAllThreaded ( $conditions = null , $fields = null , $sort = null ) {
return $this -> __doThread ( Model :: findAll ( $conditions , $fields , $sort ), null );
}
/**
* Private , recursive helper method for findAllThreaded .
*
* @ param array $data
* @ param string $root NULL or id for root node of operation
* @ return array
* @ access private
* @ see findAllThreaded
*/
function __doThread ( $data , $root ) {
$out = array ();
$sizeOf = sizeof ( $data );
2007-06-20 06:15:35 +00:00
for ( $ii = 0 ; $ii < $sizeOf ; $ii ++ ) {
2006-07-30 12:24:03 +00:00
if (( $data [ $ii ][ $this -> name ][ 'parent_id' ] == $root ) || (( $root === null ) && ( $data [ $ii ][ $this -> name ][ 'parent_id' ] == '0' ))) {
$tmp = $data [ $ii ];
if ( isset ( $data [ $ii ][ $this -> name ][ $this -> primaryKey ])) {
$tmp [ 'children' ] = $this -> __doThread ( $data , $data [ $ii ][ $this -> name ][ $this -> primaryKey ]);
} else {
$tmp [ 'children' ] = null ;
}
$out [] = $tmp ;
}
}
return $out ;
}
/**
* Returns an array with keys " prev " and " next " that holds the id ' s of neighbouring data ,
* which is useful when creating paged lists .
*
* @ param string $conditions SQL conditions for matching rows
* @ param string $field Field name ( parameter for findAll )
* @ param unknown_type $value
* @ return array Array with keys " prev " and " next " that holds the id ' s
*/
function findNeighbours ( $conditions = null , $field , $value ) {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
if ( ! is_null ( $conditions )) {
2006-10-27 21:42:29 +00:00
$conditions = $conditions . ' AND ' ;
2006-07-30 12:24:03 +00:00
}
@ list ( $prev ) = Model :: findAll ( $conditions . $field . ' < ' . $db -> value ( $value ), $field , $field . ' DESC' , 1 , null , 0 );
@ list ( $next ) = Model :: findAll ( $conditions . $field . ' > ' . $db -> value ( $value ), $field , $field . ' ASC' , 1 , null , 0 );
if ( ! isset ( $prev )) {
$prev = null ;
}
if ( ! isset ( $next )) {
$next = null ;
}
return array ( 'prev' => $prev , 'next' => $next );
}
/**
* Returns a resultset for given SQL statement . Generic SQL queries should be made with this method .
*
* @ param string $sql SQL statement
* @ return array Resultset
*/
function query () {
$params = func_get_args ();
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
return call_user_func_array ( array ( & $db , 'query' ), $params );
}
/**
* Returns true if all fields pass validation , otherwise false .
*
* @ return boolean True if there are no errors
*/
function validates ( $data = array ()) {
2007-01-06 04:58:24 +00:00
if ( ! empty ( $data )) {
2007-04-18 16:39:11 +00:00
trigger_error ( __ ( '(Model::validates) Parameter usage is deprecated, set the $data property instead' , true ), E_USER_WARNING );
2007-01-06 04:58:24 +00:00
}
2006-07-30 12:24:03 +00:00
$errors = $this -> invalidFields ( $data );
2006-10-10 22:29:13 +00:00
if ( is_array ( $errors )) {
return count ( $errors ) === 0 ;
}
return $errors ;
2006-07-30 12:24:03 +00:00
}
/**
* Returns an array of invalid fields .
*
* @ param array $data
2007-09-20 15:16:25 +00:00
* @ return array Array of invalid fields
2006-07-30 12:24:03 +00:00
*/
function invalidFields ( $data = array ()) {
2007-09-20 15:16:25 +00:00
if ( ! empty ( $this -> behaviors )) {
$behaviors = array_keys ( $this -> behaviors );
$ct = count ( $behaviors );
for ( $i = 0 ; $i < $ct ; $i ++ ) {
if ( $this -> behaviors [ $behaviors [ $i ]] -> beforeValidate ( $this ) === false ) {
return $this -> validationErrors ;
}
}
}
2007-03-17 02:59:48 +00:00
if ( ! $this -> beforeValidate ()) {
return $this -> validationErrors ;
}
2006-07-30 12:24:03 +00:00
if ( empty ( $data )) {
$data = $this -> data ;
2007-01-06 04:58:24 +00:00
} else {
2007-04-18 16:39:11 +00:00
trigger_error ( __ ( '(Model::invalidFields) Parameter usage is deprecated, set the $data property instead' , true ), E_USER_WARNING );
2006-07-30 12:24:03 +00:00
}
2006-12-25 06:53:19 +00:00
if ( ! isset ( $this -> validate ) || empty ( $this -> validate )) {
2007-02-02 18:05:48 +00:00
return $this -> validationErrors ;
2006-07-30 12:24:03 +00:00
}
if ( isset ( $data [ $this -> name ])) {
$data = $data [ $this -> name ];
}
2006-12-25 06:53:19 +00:00
$Validation = new Validation ();
2007-10-01 16:49:37 +00:00
$exists = $this -> exists ();
2006-12-25 06:53:19 +00:00
2007-06-20 06:15:35 +00:00
foreach ( $this -> validate as $fieldName => $ruleSet ) {
2007-04-30 06:24:33 +00:00
if ( ! is_array ( $ruleSet ) || ( is_array ( $ruleSet ) && isset ( $ruleSet [ 'rule' ]))) {
$ruleSet = array ( $ruleSet );
2007-01-06 04:58:24 +00:00
}
2006-12-25 06:53:19 +00:00
2007-04-30 12:10:57 +00:00
foreach ( $ruleSet as $index => $validator ) {
2007-04-30 06:24:33 +00:00
if ( ! is_array ( $validator )) {
$validator = array ( 'rule' => $validator );
}
2006-12-25 06:53:19 +00:00
2007-05-02 07:48:22 +00:00
$default = array (
2007-05-01 03:52:28 +00:00
'allowEmpty' => null ,
'required' => null ,
2007-04-30 06:24:33 +00:00
'rule' => 'blank' ,
'last' => false ,
'on' => null
2007-05-02 07:48:22 +00:00
);
$validator = am ( $default , $validator );
2007-04-30 06:24:33 +00:00
2007-04-30 12:10:57 +00:00
if ( isset ( $validator [ 'message' ])) {
$message = $validator [ 'message' ];
} else {
2007-10-01 16:49:37 +00:00
$message = __ ( 'This field cannot be left blank' , true );
2007-04-30 12:10:57 +00:00
}
2007-08-29 20:47:03 +00:00
if ( empty ( $validator [ 'on' ]) || ( $validator [ 'on' ] == 'create' && ! $exists ) || ( $validator [ 'on' ] == 'update' && $exists )) {
2007-05-04 07:13:15 +00:00
if (( ! isset ( $data [ $fieldName ]) && $validator [ 'required' ] === true ) || ( isset ( $data [ $fieldName ]) && ( empty ( $data [ $fieldName ]) && ! is_numeric ( $data [ $fieldName ])) && $validator [ 'allowEmpty' ] === false )) {
2007-04-30 12:10:57 +00:00
$this -> invalidate ( $fieldName , $message );
2007-09-20 22:45:00 +00:00
} elseif ( array_key_exists ( $fieldName , $data )) {
2007-06-20 06:15:35 +00:00
if ( empty ( $data [ $fieldName ]) && $data [ $fieldName ] != '0' && $validator [ 'allowEmpty' ] === true ) {
2007-05-01 03:52:28 +00:00
break ;
}
2007-04-30 06:24:33 +00:00
if ( is_array ( $validator [ 'rule' ])) {
$rule = $validator [ 'rule' ][ 0 ];
unset ( $validator [ 'rule' ][ 0 ]);
$ruleParams = am ( array ( $data [ $fieldName ]), array_values ( $validator [ 'rule' ]));
} else {
$rule = $validator [ 'rule' ];
$ruleParams = array ( $data [ $fieldName ]);
}
$valid = true ;
2007-05-05 17:36:30 +00:00
$msg = null ;
2007-09-16 18:18:23 +00:00
if ( method_exists ( $this , $rule ) || isset ( $this -> __behaviorMethods [ $rule ]) || isset ( $this -> __behaviorMethods [ low ( $rule )])) {
2007-05-02 07:48:22 +00:00
$ruleParams [] = array_diff_key ( $validator , $default );
2007-04-30 06:24:33 +00:00
$valid = call_user_func_array ( array ( & $this , $rule ), $ruleParams );
} elseif ( method_exists ( $Validation , $rule )) {
$valid = call_user_func_array ( array ( & $Validation , $rule ), $ruleParams );
} elseif ( ! is_array ( $validator [ 'rule' ])) {
$valid = preg_match ( $rule , $data [ $fieldName ]);
}
if ( ! $valid ) {
2007-04-30 12:10:57 +00:00
if ( ! isset ( $validator [ 'message' ])) {
2007-05-14 10:37:23 +00:00
if ( is_string ( $index )) {
$validator [ 'message' ] = $index ;
} else {
$validator [ 'message' ] = ife ( is_numeric ( $index ) && count ( $ruleSet ) > 1 , ( $index + 1 ), $message );
}
2007-04-30 12:10:57 +00:00
}
2007-04-30 06:24:33 +00:00
$this -> invalidate ( $fieldName , $validator [ 'message' ]);
}
2006-12-25 06:53:19 +00:00
}
}
2006-07-30 12:24:03 +00:00
}
}
return $this -> validationErrors ;
}
/**
* Sets a field as invalid
*
* @ param string $field The name of the field to invalidate
2006-12-25 06:53:19 +00:00
* @ param mixed $value
2006-07-30 12:24:03 +00:00
* @ return void
*/
2007-04-30 06:24:33 +00:00
function invalidate ( $field , $value = null ) {
2006-07-30 12:24:03 +00:00
if ( ! is_array ( $this -> validationErrors )) {
$this -> validationErrors = array ();
}
2007-04-30 06:24:33 +00:00
if ( empty ( $value )) {
$value = true ;
}
2006-12-25 06:53:19 +00:00
$this -> validationErrors [ $field ] = $value ;
2006-07-30 12:24:03 +00:00
}
/**
* Returns true if given field name is a foreign key in this Model .
*
* @ param string $field Returns true if the input string ends in " _id "
* @ return True if the field is a foreign key listed in the belongsTo array .
*/
function isForeignKey ( $field ) {
$foreignKeys = array ();
if ( count ( $this -> belongsTo )) {
2007-06-20 06:15:35 +00:00
foreach ( $this -> belongsTo as $assoc => $data ) {
2006-07-30 12:24:03 +00:00
$foreignKeys [] = $data [ 'foreignKey' ];
}
}
return ( bool )( in_array ( $field , $foreignKeys ));
}
/**
* Gets the display field for this model
*
* @ return string The name of the display field for this Model ( i . e . 'name' , 'title' ) .
*/
function getDisplayField () {
return $this -> displayField ;
}
/**
* Returns a resultset array with specified fields from database matching given conditions .
* Method can be used to generate option lists for SELECT elements .
*
* @ param mixed $conditions SQL conditions as a string or as an array ( 'field' => 'value' , ... )
* @ param string $order SQL ORDER BY conditions ( e . g . " price DESC " or " name ASC " )
* @ param int $limit SQL LIMIT clause , for calculating items per page
* @ param string $keyPath A string path to the key , i . e . " { n}.Post.id "
* @ param string $valuePath A string path to the value , i . e . " { n}.Post.title "
2006-07-30 23:31:04 +00:00
* @ param string $groupPath A string path to a value to group the elements by , i . e . " { n}.Post.category_id "
2006-07-30 12:24:03 +00:00
* @ return array An associative array of records , where the id is the key , and the display field is the value
*/
2006-07-30 23:31:04 +00:00
function generateList ( $conditions = null , $order = null , $limit = null , $keyPath = null , $valuePath = null , $groupPath = null ) {
if ( $keyPath == null && $valuePath == null && $groupPath == null && $this -> hasField ( $this -> displayField )) {
2006-07-30 12:24:03 +00:00
$fields = array ( $this -> primaryKey , $this -> displayField );
} else {
$fields = null ;
}
2006-11-22 19:36:59 +00:00
$recursive = $this -> recursive ;
2007-06-20 06:15:35 +00:00
if ( $groupPath == null && $recursive >= 1 ) {
2006-10-18 01:07:09 +00:00
$this -> recursive = - 1 ;
2007-06-20 07:51:52 +00:00
} elseif ( $groupPath && $recursive >= 1 ) {
2006-11-03 19:49:32 +00:00
$this -> recursive = 0 ;
2006-10-18 01:07:09 +00:00
}
$result = $this -> findAll ( $conditions , $fields , $order , $limit );
2006-11-22 19:36:59 +00:00
$this -> recursive = $recursive ;
2006-12-26 16:17:37 +00:00
2007-06-20 06:15:35 +00:00
if ( ! $result ) {
2006-12-04 06:59:56 +00:00
return false ;
}
2006-07-30 12:24:03 +00:00
if ( $keyPath == null ) {
$keyPath = '{n}.' . $this -> name . '.' . $this -> primaryKey ;
}
if ( $valuePath == null ) {
$valuePath = '{n}.' . $this -> name . '.' . $this -> displayField ;
}
2007-07-01 03:43:05 +00:00
return Set :: combine ( $result , $keyPath , $valuePath , $groupPath );
2006-07-30 12:24:03 +00:00
}
/**
* Escapes the field name and prepends the model name . Escaping will be done according to the current database driver ' s rules .
*
* @ param unknown_type $field
* @ return string The name of the escaped field for this Model ( i . e . id becomes `Post` . `id` ) .
*/
2007-02-08 17:50:47 +00:00
function escapeField ( $field = null , $alias = null ) {
if ( empty ( $alias )) {
2006-07-30 12:24:03 +00:00
$alias = $this -> name ;
}
2007-02-08 17:50:47 +00:00
if ( empty ( $field )) {
$field = $this -> primaryKey ;
}
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
return $db -> name ( $alias ) . '.' . $db -> name ( $field );
}
/**
* Returns the current record ' s ID
*
* @ param unknown_type $list
* @ return mixed The ID of the current record
*/
function getID ( $list = 0 ) {
2006-12-12 22:06:22 +00:00
if ( empty ( $this -> id ) || ( is_array ( $this -> id ) && isset ( $this -> id [ 0 ]) && empty ( $this -> id [ 0 ]))) {
2006-10-27 18:14:35 +00:00
return false ;
}
2006-07-30 12:24:03 +00:00
if ( ! is_array ( $this -> id )) {
return $this -> id ;
}
if ( count ( $this -> id ) == 0 ) {
return false ;
}
2006-12-12 22:06:22 +00:00
if ( isset ( $this -> id [ $list ]) && ! empty ( $this -> id [ $list ])) {
2006-07-30 12:24:03 +00:00
return $this -> id [ $list ];
2006-12-12 22:06:22 +00:00
} elseif ( isset ( $this -> id [ $list ])) {
return false ;
2006-07-30 12:24:03 +00:00
}
2007-06-20 06:15:35 +00:00
foreach ( $this -> id as $id ) {
2006-07-30 12:24:03 +00:00
return $id ;
}
return false ;
}
/**
* Returns the ID of the last record this Model inserted
*
* @ return mixed
*/
function getLastInsertID () {
return $this -> getInsertID ();
}
/**
* Returns the ID of the last record this Model inserted
*
* @ return mixed
*/
function getInsertID () {
return $this -> __insertID ;
}
2006-10-20 17:24:37 +00:00
/**
* Sets the ID of the last record this Model inserted
*
* @ param mixed $id
* @ return void
*/
function setInsertID ( $id ) {
$this -> __insertID = $id ;
}
2006-07-30 12:24:03 +00:00
/**
* Returns the number of rows returned from the last query
*
* @ return int
*/
function getNumRows () {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
return $db -> lastNumRows ();
}
/**
* Returns the number of rows affected by the last query
*
* @ return int
*/
function getAffectedRows () {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
return $db -> lastAffected ();
}
/**
* Sets the DataSource to which this model is bound
*
* @ param string $dataSource The name of the DataSource , as defined in Connections . php
* @ return boolean True on success
*/
function setDataSource ( $dataSource = null ) {
2007-01-10 11:15:43 +00:00
if ( $dataSource != null ) {
$this -> useDbConfig = $dataSource ;
2006-07-30 12:24:03 +00:00
}
2007-01-10 11:15:43 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
2006-07-30 12:24:03 +00:00
2007-08-28 21:44:47 +00:00
if ( ! empty ( $db -> config [ 'prefix' ]) && $this -> tablePrefix === null ) {
2006-07-30 12:24:03 +00:00
$this -> tablePrefix = $db -> config [ 'prefix' ];
}
if ( empty ( $db ) || $db == null || ! is_object ( $db )) {
return $this -> cakeError ( 'missingConnection' , array ( array ( 'className' => $this -> name )));
}
}
/**
2006-08-25 00:43:48 +00:00
* Gets the DataSource to which this model is bound .
* Not safe for use with some versions of PHP4 , because this class is overloaded .
2006-07-30 12:24:03 +00:00
*
* @ return DataSource A DataSource object
*/
function & getDataSource () {
2006-08-25 00:43:48 +00:00
$db =& ConnectionManager :: getDataSource ( $this -> useDbConfig );
return $db ;
2006-07-30 12:24:03 +00:00
}
/**
* Gets all the models with which this model is associated
*
2007-01-16 12:53:39 +00:00
* @ param string $type
2006-07-30 12:24:03 +00:00
* @ return array
*/
function getAssociated ( $type = null ) {
if ( $type == null ) {
$associated = array ();
foreach ( $this -> __associations as $assoc ) {
if ( ! empty ( $this -> { $assoc })) {
$models = array_keys ( $this -> { $assoc });
foreach ( $models as $m ) {
$associated [ $m ] = $assoc ;
}
}
}
return $associated ;
} elseif ( in_array ( $type , $this -> __associations )) {
if ( empty ( $this -> { $type })) {
return array ();
}
return array_keys ( $this -> { $type });
} else {
$assoc = am ( $this -> hasOne , $this -> hasMany , $this -> belongsTo , $this -> hasAndBelongsToMany );
if ( array_key_exists ( $type , $assoc )) {
2007-01-16 12:53:39 +00:00
foreach ( $this -> __associations as $a ) {
if ( isset ( $this -> { $a }[ $type ])) {
$assoc [ $type ][ 'association' ] = $a ;
break ;
}
}
2006-07-30 12:24:03 +00:00
return $assoc [ $type ];
}
return null ;
}
}
/**
* Before find callback
*
* @ param array $queryData Data used to execute this query , i . e . conditions , order , etc .
* @ return boolean True if the operation should continue , false if it should abort
*/
2006-12-23 20:36:00 +00:00
function beforeFind ( $queryData ) {
2006-07-30 12:24:03 +00:00
return true ;
}
/**
* After find callback . Can be used to modify any results returned by find and findAll .
*
* @ param mixed $results The results of the find operation
2006-08-18 08:00:54 +00:00
* @ param boolean $primary Whether this model is being queried directly ( vs . being queried as an association )
2006-07-30 12:24:03 +00:00
* @ return mixed Result of the find operation
*/
2006-08-18 08:00:54 +00:00
function afterFind ( $results , $primary = false ) {
2006-07-30 12:24:03 +00:00
return $results ;
}
/**
* Before save callback
*
* @ return boolean True if the operation should continue , false if it should abort
*/
function beforeSave () {
return true ;
}
/**
* After save callback
*
2007-02-07 00:36:19 +00:00
* @ param boolean $created True if this save created a new record
2006-07-30 12:24:03 +00:00
* @ return void
*/
2007-02-07 00:36:19 +00:00
function afterSave ( $created ) {
2006-07-30 12:24:03 +00:00
}
/**
* Before delete callback
*
* @ return boolean True if the operation should continue , false if it should abort
*/
function beforeDelete () {
return true ;
}
/**
* After delete callback
*
* @ return void
*/
function afterDelete () {
}
/**
* Before validate callback
*
* @ return True if validate operation should continue , false to abort
*/
function beforeValidate () {
return true ;
}
/**
* DataSource error callback
*
* @ return void
*/
function onError () {
}
/**
* Private method . Clears cache for this model
2006-01-17 17:52:23 +00:00
*
2007-10-01 16:49:37 +00:00
* @ param string $type If null this deletes cached views if Cache . check is true
2006-07-30 12:24:03 +00:00
* Will be used to allow deleting query cache also
* @ return boolean true on delete
2006-01-17 17:52:23 +00:00
*/
2006-07-30 12:24:03 +00:00
function _clearCache ( $type = null ) {
if ( $type === null ) {
2007-10-01 16:49:37 +00:00
if ( Configure :: read ( 'Cache.check' ) === true ) {
2006-07-30 12:24:03 +00:00
$assoc [] = strtolower ( Inflector :: pluralize ( $this -> name ));
2007-06-20 06:15:35 +00:00
foreach ( $this -> __associations as $key => $association ) {
foreach ( $this -> $association as $key => $className ) {
2006-07-30 12:24:03 +00:00
$check = strtolower ( Inflector :: pluralize ( $className [ 'className' ]));
if ( ! in_array ( $check , $assoc )) {
$assoc [] = strtolower ( Inflector :: pluralize ( $className [ 'className' ]));
}
}
}
clearCache ( $assoc );
return true ;
}
} else {
//Will use for query cache deleting
}
}
/**
* Called when serializing a model
*
* @ return array
*/
function __sleep () {
$return = array_keys ( get_object_vars ( $this ));
return $return ;
2006-07-22 14:13:07 +00:00
}
2006-10-28 00:42:51 +00:00
/**
* Called when unserializing a model
*
* @ return void
*/
function __wakeup () {
}
2006-01-12 02:10:47 +00:00
}
2007-01-27 17:45:26 +00:00
if ( ! defined ( 'CAKEPHP_UNIT_TEST_EXECUTION' )) {
Overloadable :: overload ( 'Model' );
}
2007-06-04 06:11:48 +00:00
?>