2008-05-30 11:40:08 +00:00
< ? php
/**
* Object - relational mapper .
*
* DBO - backed object data model , for mapping database tables to Cake objects .
*
* PHP versions 5
*
2009-05-01 21:05:46 +00:00
* CakePHP ( tm ) : Rapid Development Framework ( http :// cakephp . org )
2012-03-13 02:46:07 +00:00
* Copyright 2005 - 2012 , Cake Software Foundation , Inc . ( http :// cakefoundation . org )
2008-05-30 11:40:08 +00:00
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice .
*
2012-03-13 02:46:07 +00:00
* @ copyright Copyright 2005 - 2012 , Cake Software Foundation , Inc . ( http :// cakefoundation . org )
2010-01-26 19:18:20 +00:00
* @ link http :// cakephp . org CakePHP ( tm ) Project
2011-07-26 06:16:14 +00:00
* @ package Cake . Model
2008-10-30 17:30:26 +00:00
* @ since CakePHP ( tm ) v 0.10 . 0.0
2009-05-01 21:05:46 +00:00
* @ license MIT License ( http :// www . opensource . org / licenses / mit - license . php )
2008-05-30 11:40:08 +00:00
*/
2009-07-24 19:18:37 +00:00
2010-12-07 06:14:17 +00:00
App :: uses ( 'ClassRegistry' , 'Utility' );
App :: uses ( 'Validation' , 'Utility' );
App :: uses ( 'String' , 'Utility' );
2011-12-01 02:14:39 +00:00
App :: uses ( 'Set' , 'Utility' );
2010-12-03 23:07:21 +00:00
App :: uses ( 'BehaviorCollection' , 'Model' );
App :: uses ( 'ModelBehavior' , 'Model' );
App :: uses ( 'ConnectionManager' , 'Model' );
2010-12-07 06:14:17 +00:00
App :: uses ( 'Xml' , 'Utility' );
2011-12-26 17:36:48 +00:00
App :: uses ( 'CakeEvent' , 'Event' );
App :: uses ( 'CakeEventListener' , 'Event' );
App :: uses ( 'CakeEventManager' , 'Event' );
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +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 ' )
2008-10-31 19:05:30 +00:00
* The table is required to have at least 'id auto_increment' primary key .
2008-05-30 11:40:08 +00:00
*
2011-07-26 06:16:14 +00:00
* @ package Cake . Model
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models . html
2008-05-30 11:40:08 +00:00
*/
2011-12-26 17:36:48 +00:00
class Model extends Object implements CakeEventListener {
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* The name of the DataSource connection that this Model uses
*
2011-08-15 04:17:40 +00:00
* The value must be an attribute name that you defined in `app/Config/database.php`
* or created using `ConnectionManager::create()` .
*
2008-05-30 11:40:08 +00:00
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #usedbconfig
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $useDbConfig = 'default' ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Custom database table name , or null / false if no table association is desired .
2008-05-30 11:40:08 +00:00
*
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #useTable
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $useTable = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Custom display field name . Display fields are used by Scaffold , in SELECT boxes ' OPTION elements .
*
2011-08-15 04:35:20 +00:00
* This field is also used in `find('list')` when called with no extra parameters in the fields list
2011-08-15 04:17:40 +00:00
*
2008-05-30 11:40:08 +00:00
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #displayField
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $displayField = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-11-08 02:54:07 +00:00
* Value of the primary key ID of the record that this model is currently pointing to .
2008-10-31 19:05:30 +00:00
* Automatically set after database insertions .
2008-05-30 11:40:08 +00:00
*
* @ var mixed
*/
2010-04-04 07:14:00 +00:00
public $id = false ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Container for the data that this model gets from persistent storage ( usually , a database ) .
2008-05-30 11:40:08 +00:00
*
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #data
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $data = array ();
2009-07-24 19:18:37 +00:00
2011-11-05 10:57:08 +00:00
/**
* Holds physical schema / database name for this model . Automatically set during Model creation .
*
* @ var string
* @ access public
*/
public $schemaName = null ;
2008-05-30 11:40:08 +00:00
/**
* Table name for this Model .
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $table = false ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* The name of the primary key field for this model .
2008-05-30 11:40:08 +00:00
*
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #primaryKey
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $primaryKey = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Field - by - field table metadata .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-04-04 06:36:12 +00:00
protected $_schema = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2011-08-15 04:35:20 +00:00
* List of validation rules . It must be an array with the field name as key and using
* as value one of the following possibilities
2011-08-15 04:17:40 +00:00
*
* ### Validating using regular expressions
*
* {{{
* public $validate = array (
* 'name' => '/^[a-z].+$/i'
* );
* }}}
*
* ### Validating using methods (no parameters)
*
* {{{
* public $validate = array (
* 'name' => 'notEmpty'
* );
* }}}
*
* ### Validating using methods (with parameters)
*
* {{{
* public $validate = array (
* 'age' => array (
* 'rule' => array ( 'between' , 5 , 25 )
* )
* );
* }}}
*
* ### Validating using custom method
*
* {{{
* public $validate = array (
* 'password' => array (
* 'rule' => array ( 'customValidation' )
* )
* );
* public function customValidation ( $data ) {
* // $data will contain array('password' => 'value')
* if ( isset ( $this -> data [ $this -> alias ][ 'password2' ])) {
* return $this -> data [ $this -> alias ][ 'password2' ] === current ( $data );
* }
* return true ;
* }
* }}}
*
* ### Validations with messages
*
* The messages will be used in Model :: $validationErrors and can be used in the FormHelper
*
* {{{
* public $validate = array (
* 'age' => array (
* 'rule' => array ( 'between' , 5 , 25 ),
* 'message' => array ( 'The age must be between %d and %d.' )
* )
* );
* }}}
*
* ### Multiple validations to the same field
*
* {{{
* public $validate = array (
* 'login' => array (
* array (
2011-10-06 02:02:15 +00:00
* 'rule' => 'alphaNumeric' ,
2011-08-15 04:17:40 +00:00
* 'message' => 'Only alphabets and numbers allowed' ,
* 'last' => true
* ),
* array (
2011-10-06 02:02:15 +00:00
* 'rule' => array ( 'minLength' , 8 ),
2011-08-15 04:17:40 +00:00
* 'message' => array ( 'Minimum length of %d characters' )
* )
* )
* );
* }}}
*
* ### Valid keys in validations
*
2011-10-06 02:03:18 +00:00
* - `rule` : String with method name , regular expression ( started by slash ) or array with method and parameters
2011-08-15 04:17:40 +00:00
* - `message` : String with the message or array if have multiple parameters . See http :// php . net / sprintf
* - `last` : Boolean value to indicate if continue validating the others rules if the current fail [ Default : true ]
* - `required` : Boolean value to indicate if the field must be present on save
* - `allowEmpty` : Boolean value to indicate if the field can be empty
* - `on` : Possible values : `update` , `create` . Indicate to apply this rule only on update or create
2008-05-30 11:40:08 +00:00
*
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #validate
* @ link http :// book . cakephp . org / 2.0 / en / models / data - validation . html
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $validate = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* List of validation errors .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-04-04 07:14:00 +00:00
public $validationErrors = array ();
2009-07-24 19:18:37 +00:00
2011-06-20 05:06:31 +00:00
/**
2011-07-07 12:14:06 +00:00
* Name of the validation string domain to use when translating validation errors .
2011-06-20 05:06:31 +00:00
*
* @ var string
*/
public $validationDomain = null ;
2008-05-30 11:40:08 +00:00
/**
* Database table prefix for tables in model .
*
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #tableprefix
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $tablePrefix = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Name of the model .
*
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #name
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $name = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Alias name for model .
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $alias = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* List of table names included in the model description . Used for associations .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-04-04 07:14:00 +00:00
public $tableToModel = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Whether or not to cache queries for this model . This enables in - memory
2008-10-31 19:05:30 +00:00
* caching only , the results are not stored beyond the current request .
2008-05-30 11:40:08 +00:00
*
* @ var boolean
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #cacheQueries
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $cacheQueries = false ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Detailed list of belongsTo associations .
2008-05-30 11:40:08 +00:00
*
2011-08-15 05:10:32 +00:00
* ### Basic usage
*
* `public $belongsTo = array('Group', 'Department');`
*
* ### Detailed configuration
*
* {{{
* public $belongsTo = array (
* 'Group' ,
* 'Department' => array (
* 'className' => 'Department' ,
* 'foreignKey' => 'department_id'
* )
* );
* }}}
*
* ### Possible keys in association
*
* - `className` : the classname of the model being associated to the current model .
2012-01-11 18:37:52 +00:00
* If you 're defining a ' Profile belongsTo User ' relationship, the className key should equal ' User . '
2011-08-15 05:10:32 +00:00
* - `foreignKey` : the name of the foreign key found in the current model . This is
* especially handy if you need to define multiple belongsTo relationships . The default
2012-01-11 18:37:52 +00:00
* value for this key is the underscored , singular name of the other model , suffixed with '_id' .
* - `conditions` : An SQL fragment used to filter related model records . It ' s good
* practice to use model names in SQL fragments : 'User.active = 1' is always
* better than just 'active = 1.'
2011-08-15 05:10:32 +00:00
* - `type` : the type of the join to use in the SQL query , default is LEFT which
* may not fit your needs in all situations , INNER may be helpful when you want
* everything from your main and associated models or nothing at all ! ( effective
* when used with some conditions of course ) . ( NB : type value is in lower case - i . e . left , inner )
* - `fields` : A list of fields to be retrieved when the associated model data is
* fetched . Returns all fields by default .
* - `order` : An SQL fragment that defines the sorting order for the returned associated rows .
* - `counterCache` : If set to true the associated Model will automatically increase or
2012-01-11 18:37:52 +00:00
* decrease the " [singular_model_name]_count " field in the foreign table whenever you do
2011-08-15 05:10:32 +00:00
* a save () or delete () . If its a string then its the field name to use . The value in the
* counter field represents the number of related rows .
* - `counterScope` : Optional conditions array to use for updating counter cache field .
*
2008-05-30 11:40:08 +00:00
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / associations - linking - models - together . html #belongsto
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $belongsTo = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Detailed list of hasOne associations .
2008-05-30 11:40:08 +00:00
*
2011-08-15 05:10:32 +00:00
* ### Basic usage
*
* `public $hasOne = array('Profile', 'Address');`
*
* ### Detailed configuration
*
* {{{
* public $hasOne = array (
* 'Profile' ,
* 'Address' => array (
* 'className' => 'Address' ,
* 'foreignKey' => 'user_id'
* )
* );
* }}}
*
* ### Possible keys in association
*
* - `className` : the classname of the model being associated to the current model .
2012-01-11 18:37:52 +00:00
* If you 're defining a ' User hasOne Profile ' relationship, the className key should equal ' Profile . '
2011-08-15 05:10:32 +00:00
* - `foreignKey` : the name of the foreign key found in the other model . This is
* especially handy if you need to define multiple hasOne relationships .
* The default value for this key is the underscored , singular name of the
2012-01-11 18:37:52 +00:00
* current model , suffixed with '_id' . In the example above it would default to 'user_id' .
* - `conditions` : An SQL fragment used to filter related model records . It ' s good
* practice to use model names in SQL fragments : " Profile.approved = 1 " is
* always better than just " approved = 1. "
2011-08-15 05:10:32 +00:00
* - `fields` : A list of fields to be retrieved when the associated model data is
* fetched . Returns all fields by default .
* - `order` : An SQL fragment that defines the sorting order for the returned associated rows .
2012-01-11 18:37:52 +00:00
* - `dependent` : When the dependent key is set to true , and the model ' s delete ()
2011-08-15 05:10:32 +00:00
* method is called with the cascade parameter set to true , associated model
* records are also deleted . In this case we set it true so that deleting a
* User will also delete her associated Profile .
*
2008-05-30 11:40:08 +00:00
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / associations - linking - models - together . html #hasone
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $hasOne = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Detailed list of hasMany associations .
2008-05-30 11:40:08 +00:00
*
2011-08-15 05:10:32 +00:00
* ### Basic usage
*
* `public $hasMany = array('Comment', 'Task');`
*
* ### Detailed configuration
*
* {{{
* public $hasMany = array (
* 'Comment' ,
* 'Task' => array (
* 'className' => 'Task' ,
* 'foreignKey' => 'user_id'
* )
* );
* }}}
*
* ### Possible keys in association
*
* - `className` : the classname of the model being associated to the current model .
2012-01-11 18:37:52 +00:00
* If you 're defining a ' User hasMany Comment ' relationship, the className key should equal ' Comment . '
2011-08-15 05:10:32 +00:00
* - `foreignKey` : the name of the foreign key found in the other model . This is
* especially handy if you need to define multiple hasMany relationships . The default
2012-01-11 18:37:52 +00:00
* value for this key is the underscored , singular name of the actual model , suffixed with '_id' .
* - `conditions` : An SQL fragment used to filter related model records . It ' s good
* practice to use model names in SQL fragments : " Comment.status = 1 " is always
* better than just " status = 1. "
2011-08-15 05:10:32 +00:00
* - `fields` : A list of fields to be retrieved when the associated model data is
* fetched . Returns all fields by default .
* - `order` : An SQL fragment that defines the sorting order for the returned associated rows .
* - `limit` : The maximum number of associated rows you want returned .
* - `offset` : The number of associated rows to skip over ( given the current
* conditions and order ) before fetching and associating .
* - `dependent` : When dependent is set to true , recursive model deletion is
* possible . In this example , Comment records will be deleted when their
* associated User record has been deleted .
* - `exclusive` : When exclusive is set to true , recursive model deletion does
* the delete with a deleteAll () call , instead of deleting each entity separately .
* This greatly improves performance , but may not be ideal for all circumstances .
* - `finderQuery` : A complete SQL query CakePHP can use to fetch associated model
* records . This should be used in situations that require very custom results .
*
2008-05-30 11:40:08 +00:00
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / associations - linking - models - together . html #hasmany
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $hasMany = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Detailed list of hasAndBelongsToMany associations .
2008-05-30 11:40:08 +00:00
*
2011-08-15 05:10:32 +00:00
* ### Basic usage
*
* `public $hasAndBelongsToMany = array('Role', 'Address');`
*
* ### Detailed configuration
*
* {{{
* public $hasAndBelongsToMany = array (
* 'Role' ,
* 'Address' => array (
* 'className' => 'Address' ,
* 'foreignKey' => 'user_id' ,
* 'associationForeignKey' => 'address_id' ,
* 'joinTable' => 'addresses_users'
* )
* );
* }}}
*
* ### Possible keys in association
*
* - `className` : the classname of the model being associated to the current model .
2012-01-11 18:37:52 +00:00
* If you 're defining a ' Recipe HABTM Tag ' relationship, the className key should equal ' Tag . '
2011-08-15 05:10:32 +00:00
* - `joinTable` : The name of the join table used in this association ( if the
* current table doesn ' t adhere to the naming convention for HABTM join tables ) .
* - `with` : Defines the name of the model for the join table . By default CakePHP
* will auto - create a model for you . Using the example above it would be called
* RecipesTag . By using this key you can override this default name . The join
* table model can be used just like any " regular " model to access the join table directly .
* - `foreignKey` : the name of the foreign key found in the current model .
* This is especially handy if you need to define multiple HABTM relationships .
* The default value for this key is the underscored , singular name of the
2012-01-11 18:37:52 +00:00
* current model , suffixed with '_id' .
2011-08-15 05:10:32 +00:00
* - `associationForeignKey` : the name of the foreign key found in the other model .
* This is especially handy if you need to define multiple HABTM relationships .
* The default value for this key is the underscored , singular name of the other
2012-01-11 18:37:52 +00:00
* model , suffixed with '_id' .
2011-08-15 05:10:32 +00:00
* - `unique` : If true ( default value ) cake will first delete existing relationship
* records in the foreign keys table before inserting new ones , when updating a
* record . So existing associations need to be passed again when updating .
2012-01-17 21:02:30 +00:00
* To prevent deletion of existing relationship records , set this key to a string 'keepExisting' .
2011-08-15 05:10:32 +00:00
* - `conditions` : An SQL fragment used to filter related model records . It ' s good
* practice to use model names in SQL fragments : " Comment.status = 1 " is always
* better than just " status = 1. "
* - `fields` : A list of fields to be retrieved when the associated model data is
* fetched . Returns all fields by default .
* - `order` : An SQL fragment that defines the sorting order for the returned associated rows .
* - `limit` : The maximum number of associated rows you want returned .
* - `offset` : The number of associated rows to skip over ( given the current
* conditions and order ) before fetching and associating .
* - `finderQuery` , `deleteQuery` , `insertQuery` : A complete SQL query CakePHP
* can use to fetch , delete , or create new associated model records . This should
* be used in situations that require very custom results .
*
2008-05-30 11:40:08 +00:00
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / associations - linking - models - together . html #hasandbelongstomany-habtm
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $hasAndBelongsToMany = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* List of behaviors to load when the model object is initialized . Settings can be
* passed to behaviors by using the behavior name as index . Eg :
*
2010-04-04 07:14:00 +00:00
* public $actsAs = array ( 'Translate' , 'MyBehavior' => array ( 'setting1' => 'value1' ))
2008-05-30 11:40:08 +00:00
*
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / behaviors . html #using-behaviors
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $actsAs = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Holds the Behavior objects currently bound to this model .
2008-05-30 11:40:08 +00:00
*
2009-03-17 21:10:28 +00:00
* @ var BehaviorCollection
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $Behaviors = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Whitelist of fields allowed to be saved .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-04-04 07:14:00 +00:00
public $whitelist = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Whether or not to cache sources for this model .
2008-05-30 11:40:08 +00:00
*
* @ var boolean
*/
2010-04-04 07:14:00 +00:00
public $cacheSources = true ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Type of find query currently executing .
2008-05-30 11:40:08 +00:00
*
* @ var string
*/
2010-04-04 07:14:00 +00:00
public $findQueryType = null ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-11-08 02:54:07 +00:00
* Number of associations to recurse through during find calls . Fetches only
2008-10-31 19:05:30 +00:00
* the first level by default .
2008-05-30 11:40:08 +00:00
*
* @ var integer
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #recursive
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $recursive = 1 ;
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-11-08 02:54:07 +00:00
* The column name ( s ) and direction ( s ) to order find results by default .
*
2010-04-04 07:14:00 +00:00
* public $order = " Post.created DESC " ;
* public $order = array ( " Post.view_count DESC " , " Post.rating DESC " );
2008-05-30 11:40:08 +00:00
*
* @ var string
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #order
2008-05-30 11:40:08 +00:00
*/
2010-04-04 07:14:00 +00:00
public $order = null ;
2009-07-24 19:18:37 +00:00
2009-12-20 21:26:12 +00:00
/**
* Array of virtual fields this model has . Virtual fields are aliased
* SQL expressions . Fields added to this property will be read as other fields in a model
* but will not be saveable .
*
2010-04-04 07:14:00 +00:00
* `public $virtualFields = array('two' => '1 + 1');`
2009-12-20 21:26:12 +00:00
*
* Is a simplistic example of how to set virtualFields
*
* @ var array
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / model - attributes . html #virtualfields
2009-12-20 21:26:12 +00:00
*/
2010-04-04 07:14:00 +00:00
public $virtualFields = array ();
2009-12-20 21:26:12 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Default list of association keys .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2011-08-20 04:43:34 +00:00
protected $_associationKeys = array (
2009-03-08 18:05:18 +00:00
'belongsTo' => array ( 'className' , 'foreignKey' , 'conditions' , 'fields' , 'order' , 'counterCache' ),
2011-12-01 07:21:31 +00:00
'hasOne' => array ( 'className' , 'foreignKey' , 'conditions' , 'fields' , 'order' , 'dependent' ),
2009-03-08 18:05:18 +00:00
'hasMany' => array ( 'className' , 'foreignKey' , 'conditions' , 'fields' , 'order' , 'limit' , 'offset' , 'dependent' , 'exclusive' , 'finderQuery' , 'counterQuery' ),
'hasAndBelongsToMany' => array ( 'className' , 'joinTable' , 'with' , 'foreignKey' , 'associationForeignKey' , 'conditions' , 'fields' , 'order' , 'limit' , 'offset' , 'unique' , 'finderQuery' , 'deleteQuery' , 'insertQuery' )
);
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Holds provided / generated association key names and other data for all associations .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2011-08-20 04:43:34 +00:00
protected $_associations = array ( 'belongsTo' , 'hasOne' , 'hasMany' , 'hasAndBelongsToMany' );
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Holds model associations temporarily to allow for dynamic ( un ) binding .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2010-12-12 20:48:36 +00:00
public $__backAssociation = array ();
2011-07-31 21:05:20 +00:00
/**
* Back inner association
*
* @ var array
*/
2010-12-12 20:48:36 +00:00
public $__backInnerAssociation = array ();
2011-01-29 22:43:01 +00:00
2011-07-31 21:05:20 +00:00
/**
* Back original association
*
* @ var array
*/
2010-12-12 20:48:36 +00:00
public $__backOriginalAssociation = array ();
2011-01-29 22:43:01 +00:00
2011-07-31 21:05:20 +00:00
/**
* Back containable association
*
* @ var array
*/
2010-12-12 20:48:36 +00:00
public $__backContainableAssociation = array ();
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* The ID of the model record that was last inserted .
2008-05-30 11:40:08 +00:00
*
* @ var integer
*/
2011-08-20 04:43:34 +00:00
protected $_insertID = null ;
2009-07-24 19:18:37 +00:00
2011-02-12 03:39:09 +00:00
/**
* Has the datasource been configured .
*
* @ var boolean
* @ see Model :: getDataSource
*/
2011-08-20 04:43:34 +00:00
protected $_sourceConfigured = false ;
2011-02-12 03:39:09 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* List of valid finder method options , supplied as the first parameter to find () .
2008-05-30 11:40:08 +00:00
*
* @ var array
*/
2011-04-17 00:39:00 +00:00
public $findMethods = array (
2008-09-21 04:09:16 +00:00
'all' => true , 'first' => true , 'count' => true ,
'neighbors' => true , 'list' => true , 'threaded' => true
);
2009-07-24 19:18:37 +00:00
2011-12-26 17:36:48 +00:00
/**
* Instance of the CakeEventManager this model is using
* to dispatch inner events .
*
* @ var CakeEventManager
*/
protected $_eventManager = null ;
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Constructor . Binds the model ' s database table to the object .
2008-05-30 11:40:08 +00:00
*
2010-01-02 04:58:07 +00:00
* If `$id` is an array it can be used to pass several options into the model .
*
* - id - The id to start the model on .
* - table - The table to use for this model .
* - ds - The connection name this model is connected to .
* - name - The name of the model eg . Post .
* - alias - The alias of the model , this is used for registering the instance in the `ClassRegistry` .
* eg . `ParentThread`
*
* ### Overriding Model's __construct method.
2010-01-14 17:57:43 +00:00
*
* When overriding Model :: __construct () be careful to include and pass in all 3 of the
2010-01-02 04:58:07 +00:00
* arguments to `parent::__construct($id, $table, $ds);`
*
* ### Dynamically creating models
*
2010-07-19 22:29:18 +00:00
* You can dynamically create model instances using the $id array syntax .
2010-01-14 17:57:43 +00:00
*
2010-01-02 04:58:07 +00:00
* {{{
* $Post = new Model ( array ( 'table' => 'posts' , 'name' => 'Post' , 'ds' => 'connection2' ));
* }}}
*
* Would create a model attached to the posts table on connection2 . Dynamic model creation is useful
* when you want a model object that contains no associations or attached behaviors .
*
* @ param mixed $id Set this ID for this model on startup , can also be an array of options , see above .
2008-05-30 11:40:08 +00:00
* @ param string $table Name of database table to use .
2010-01-02 04:58:07 +00:00
* @ param string $ds DataSource connection name .
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function __construct ( $id = false , $table = null , $ds = null ) {
2008-05-30 11:40:08 +00:00
parent :: __construct ();
if ( is_array ( $id )) {
2008-08-25 22:33:36 +00:00
extract ( array_merge (
2008-09-21 04:09:16 +00:00
array (
'id' => $this -> id , 'table' => $this -> useTable , 'ds' => $this -> useDbConfig ,
'name' => $this -> name , 'alias' => $this -> alias
),
$id
));
2008-05-30 11:40:08 +00:00
}
if ( $this -> name === null ) {
2008-09-21 04:09:16 +00:00
$this -> name = ( isset ( $name ) ? $name : get_class ( $this ));
2008-05-30 11:40:08 +00:00
}
if ( $this -> alias === null ) {
2008-09-21 04:09:16 +00:00
$this -> alias = ( isset ( $alias ) ? $alias : $this -> name );
2008-05-30 11:40:08 +00:00
}
if ( $this -> primaryKey === null ) {
$this -> primaryKey = 'id' ;
}
2008-09-26 15:27:36 +00:00
2008-05-30 11:40:08 +00:00
ClassRegistry :: addObject ( $this -> alias , $this );
$this -> id = $id ;
unset ( $id );
if ( $table === false ) {
$this -> useTable = false ;
} elseif ( $table ) {
$this -> useTable = $table ;
}
2009-07-24 19:18:37 +00:00
2009-06-16 21:35:21 +00:00
if ( $ds !== null ) {
$this -> useDbConfig = $ds ;
}
2008-05-30 11:40:08 +00:00
2008-09-21 04:09:16 +00:00
if ( is_subclass_of ( $this , 'AppModel' )) {
2011-12-18 15:37:16 +00:00
$merge = array ( 'actsAs' , 'findMethods' );
2008-11-14 20:24:27 +00:00
$parentClass = get_parent_class ( $this );
2010-11-20 05:20:54 +00:00
if ( $parentClass !== 'AppModel' ) {
$this -> _mergeVars ( $merge , $parentClass );
2008-09-21 04:09:16 +00:00
}
2010-11-20 05:20:54 +00:00
$this -> _mergeVars ( $merge , 'AppModel' );
2008-09-21 04:09:16 +00:00
}
2012-03-03 22:45:45 +00:00
$this -> _mergeVars ( array ( 'findMethods' ), 'Model' );
2008-09-21 04:09:16 +00:00
$this -> Behaviors = new BehaviorCollection ();
2008-05-30 11:40:08 +00:00
if ( $this -> useTable !== false ) {
2011-02-23 04:19:02 +00:00
2008-05-30 11:40:08 +00:00
if ( $this -> useTable === null ) {
$this -> useTable = Inflector :: tableize ( $this -> name );
}
if ( $this -> displayField == null ) {
2010-07-16 01:48:16 +00:00
unset ( $this -> displayField );
2008-05-30 11:40:08 +00:00
}
2011-02-23 04:19:02 +00:00
$this -> table = $this -> useTable ;
$this -> tableToModel [ $this -> table ] = $this -> alias ;
2008-10-15 17:30:08 +00:00
} elseif ( $this -> table === false ) {
$this -> table = Inflector :: tableize ( $this -> name );
2008-05-30 11:40:08 +00:00
}
2011-12-08 04:40:22 +00:00
if ( $this -> tablePrefix === null ) {
unset ( $this -> tablePrefix );
}
2011-08-20 04:43:34 +00:00
$this -> _createLinks ();
2008-09-22 16:32:41 +00:00
$this -> Behaviors -> init ( $this -> alias , $this -> actsAs );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2011-12-26 17:36:48 +00:00
/**
* Returns a list of all events that will fire in the model during it ' s lifecycle .
* You can override this function to add you own listener callbacks
*
* @ return array
*/
public function implementedEvents () {
return array (
'Model.beforeFind' => array ( 'callable' => 'beforeFind' , 'passParams' => true ),
'Model.afterFind' => array ( 'callable' => 'afterFind' , 'passParams' => true ),
'Model.beforeValidate' => array ( 'callable' => 'beforeValidate' , 'passParams' => true ),
'Model.beforeSave' => array ( 'callable' => 'beforeSave' , 'passParams' => true ),
'Model.afterSave' => array ( 'callable' => 'afterSave' , 'passParams' => true ),
2011-12-28 03:19:50 +00:00
'Model.beforeDelete' => array ( 'callable' => 'beforeDelete' , 'passParams' => true ),
2011-12-26 17:36:48 +00:00
'Model.afterDelete' => array ( 'callable' => 'afterDelete' ),
);
}
/**
* Returns the CakeEventManager manager instance that is handling any callbacks .
* You can use this instance to register any new listeners or callbacks to the
2012-02-17 12:51:20 +00:00
* model events , or create your own events and trigger them at will .
2011-12-26 17:36:48 +00:00
*
* @ return CakeEventManager
*/
public function getEventManager () {
if ( empty ( $this -> _eventManager )) {
$this -> _eventManager = new CakeEventManager ();
$this -> _eventManager -> attach ( $this -> Behaviors );
$this -> _eventManager -> attach ( $this );
}
return $this -> _eventManager ;
}
2008-05-30 11:40:08 +00:00
/**
* Handles custom method calls , like findBy < field > for DB models ,
* and custom RPC calls for remote data sources .
*
* @ param string $method Name of method to call .
* @ param array $params Parameters for the method .
* @ return mixed Whatever is returned by called method
*/
2010-04-05 06:43:20 +00:00
public function __call ( $method , $params ) {
2008-05-30 11:40:08 +00:00
$result = $this -> Behaviors -> dispatchMethod ( $this , $method , $params );
if ( $result !== array ( 'unhandled' )) {
return $result ;
}
2010-07-15 03:49:38 +00:00
$return = $this -> getDataSource () -> query ( $method , $params , $this );
2008-05-30 11:40:08 +00:00
return $return ;
}
2009-07-24 19:18:37 +00:00
2010-07-14 21:28:12 +00:00
/**
2011-10-18 17:06:29 +00:00
* Handles the lazy loading of model associations by looking in the association arrays for the requested variable
2010-07-14 21:28:12 +00:00
*
2011-12-02 05:58:09 +00:00
* @ param string $name variable tested for existence in class
2010-07-14 21:28:12 +00:00
* @ return boolean true if the variable exists ( if is a not loaded model association it will be created ), false otherwise
*/
public function __isset ( $name ) {
$className = false ;
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associations as $type ) {
2010-07-14 21:28:12 +00:00
if ( isset ( $name , $this -> { $type }[ $name ])) {
$className = empty ( $this -> { $type }[ $name ][ 'className' ]) ? $name : $this -> { $type }[ $name ][ 'className' ];
break ;
2012-03-04 19:18:04 +00:00
} elseif ( isset ( $name , $this -> __backAssociation [ $type ][ $name ])) {
2011-09-29 14:44:05 +00:00
$className = empty ( $this -> __backAssociation [ $type ][ $name ][ 'className' ]) ?
$name : $this -> __backAssociation [ $type ][ $name ][ 'className' ];
break ;
2012-02-23 13:38:02 +00:00
} elseif ( $type == 'hasAndBelongsToMany' ) {
2010-07-14 21:28:12 +00:00
foreach ( $this -> { $type } as $k => $relation ) {
2010-07-14 22:24:19 +00:00
if ( empty ( $relation [ 'with' ])) {
continue ;
}
2010-07-15 03:49:38 +00:00
if ( is_array ( $relation [ 'with' ])) {
if ( key ( $relation [ 'with' ]) === $name ) {
$className = $name ;
}
2010-07-14 22:24:19 +00:00
} else {
list ( $plugin , $class ) = pluginSplit ( $relation [ 'with' ]);
if ( $class === $name ) {
$className = $relation [ 'with' ];
}
}
if ( $className ) {
$assocKey = $k ;
2010-07-15 03:49:38 +00:00
$dynamic = ! empty ( $relation [ 'dynamicWith' ]);
2010-07-14 21:28:12 +00:00
break ( 2 );
}
}
}
2011-12-19 13:18:28 +00:00
}
2010-07-14 21:28:12 +00:00
if ( ! $className ) {
return false ;
}
list ( $plugin , $className ) = pluginSplit ( $className );
2010-07-15 03:49:38 +00:00
if ( ! ClassRegistry :: isKeySet ( $className ) && ! empty ( $dynamic )) {
$this -> { $className } = new AppModel ( array (
'name' => $className ,
'table' => $this -> hasAndBelongsToMany [ $assocKey ][ 'joinTable' ],
'ds' => $this -> useDbConfig
));
} else {
2011-08-20 04:43:34 +00:00
$this -> _constructLinkedModel ( $name , $className , $plugin );
2010-07-15 03:49:38 +00:00
}
2010-07-14 22:24:19 +00:00
if ( ! empty ( $assocKey )) {
$this -> hasAndBelongsToMany [ $assocKey ][ 'joinTable' ] = $this -> { $name } -> table ;
if ( count ( $this -> { $name } -> schema ()) <= 2 && $this -> { $name } -> primaryKey !== false ) {
$this -> { $name } -> primaryKey = $this -> hasAndBelongsToMany [ $assocKey ][ 'foreignKey' ];
}
}
2010-07-16 03:47:13 +00:00
return true ;
2010-07-14 21:28:12 +00:00
}
/**
* Returns the value of the requested variable if it can be set by __isset ()
*
* @ param string $name variable requested for it ' s value or reference
* @ return mixed value of requested variable if it is set
*/
2011-05-28 20:38:46 +00:00
public function __get ( $name ) {
2010-07-16 01:48:16 +00:00
if ( $name === 'displayField' ) {
return $this -> displayField = $this -> hasField ( array ( 'title' , 'name' , $this -> primaryKey ));
}
2011-12-08 04:40:22 +00:00
if ( $name === 'tablePrefix' ) {
$this -> setDataSource ();
2012-01-11 02:01:03 +00:00
if ( property_exists ( $this , 'tablePrefix' ) && ! empty ( $this -> tablePrefix )) {
2011-12-08 04:40:22 +00:00
return $this -> tablePrefix ;
}
return $this -> tablePrefix = null ;
}
2010-07-14 21:28:12 +00:00
if ( isset ( $this -> { $name })) {
return $this -> { $name };
}
}
2008-05-30 11:40:08 +00:00
/**
* Bind model associations on the fly .
*
2010-05-01 21:37:23 +00:00
* If `$reset` is false , association will not be reset
2008-05-30 11:40:08 +00:00
* to the originals defined in the model
*
* Example : Add a new hasOne binding to the Profile model not
* defined in the model source code :
2010-05-01 21:37:23 +00:00
*
* `$this->User->bindModel( array('hasOne' => array('Profile')) );`
*
* Bindings that are not made permanent will be reset by the next Model :: find () call on this
* model .
2008-05-30 11:40:08 +00:00
*
* @ param array $params Set of bindings ( indexed by binding type )
* @ param boolean $reset Set to false to make the binding permanent
* @ return boolean Success
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / associations - linking - models - together . html #creating-and-destroying-associations-on-the-fly
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function bindModel ( $params , $reset = true ) {
2008-05-30 11:40:08 +00:00
foreach ( $params as $assoc => $model ) {
2010-07-03 22:05:14 +00:00
if ( $reset === true && ! isset ( $this -> __backAssociation [ $assoc ])) {
2008-05-30 11:40:08 +00:00
$this -> __backAssociation [ $assoc ] = $this -> { $assoc };
}
foreach ( $model as $key => $value ) {
$assocName = $key ;
if ( is_numeric ( $key )) {
$assocName = $value ;
$value = array ();
}
$this -> { $assoc }[ $assocName ] = $value ;
2010-07-14 21:28:12 +00:00
if ( property_exists ( $this , $assocName )) {
unset ( $this -> { $assocName });
}
2010-07-01 16:39:50 +00:00
if ( $reset === false && isset ( $this -> __backAssociation [ $assoc ])) {
$this -> __backAssociation [ $assoc ][ $assocName ] = $value ;
}
2008-05-30 11:40:08 +00:00
}
}
2011-08-20 04:43:34 +00:00
$this -> _createLinks ();
2008-05-30 11:40:08 +00:00
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Turn off associations on the fly .
*
* If $reset is false , association will not be reset
* to the originals defined in the model
*
* Example : Turn off the associated Model Support request ,
* to temporarily lighten the User model :
2010-11-03 13:25:42 +00:00
*
2010-05-01 21:37:23 +00:00
* `$this->User->unbindModel( array('hasMany' => array('Supportrequest')) );`
2010-11-03 13:25:42 +00:00
*
2010-05-01 21:37:23 +00:00
* unbound models that are not made permanent will reset with the next call to Model :: find ()
2008-05-30 11:40:08 +00:00
*
* @ param array $params Set of bindings to unbind ( indexed by binding type )
* @ param boolean $reset Set to false to make the unbinding permanent
* @ return boolean Success
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / associations - linking - models - together . html #creating-and-destroying-associations-on-the-fly
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function unbindModel ( $params , $reset = true ) {
2008-05-30 11:40:08 +00:00
foreach ( $params as $assoc => $models ) {
2010-07-03 22:05:14 +00:00
if ( $reset === true && ! isset ( $this -> __backAssociation [ $assoc ])) {
2008-05-30 11:40:08 +00:00
$this -> __backAssociation [ $assoc ] = $this -> { $assoc };
}
foreach ( $models as $model ) {
2010-07-03 22:05:14 +00:00
if ( $reset === false && isset ( $this -> __backAssociation [ $assoc ][ $model ])) {
unset ( $this -> __backAssociation [ $assoc ][ $model ]);
}
2010-07-01 16:39:50 +00:00
unset ( $this -> { $assoc }[ $model ]);
2008-05-30 11:40:08 +00:00
}
}
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Create a set of associations .
2008-05-30 11:40:08 +00:00
*
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2011-08-20 04:43:34 +00:00
protected function _createLinks () {
foreach ( $this -> _associations as $type ) {
2008-05-30 11:40:08 +00:00
if ( ! is_array ( $this -> { $type })) {
$this -> { $type } = explode ( ',' , $this -> { $type });
foreach ( $this -> { $type } as $i => $className ) {
$className = trim ( $className );
unset ( $this -> { $type }[ $i ]);
$this -> { $type }[ $className ] = array ();
}
}
2008-06-11 08:54:27 +00:00
if ( ! empty ( $this -> { $type })) {
foreach ( $this -> { $type } as $assoc => $value ) {
$plugin = null ;
2008-05-30 11:40:08 +00:00
2008-06-11 08:54:27 +00:00
if ( is_numeric ( $assoc )) {
unset ( $this -> { $type }[ $assoc ]);
$assoc = $value ;
$value = array ();
if ( strpos ( $assoc , '.' ) !== false ) {
2010-07-14 03:58:48 +00:00
list ( $plugin , $assoc ) = pluginSplit ( $assoc );
2012-03-04 19:18:04 +00:00
$this -> { $type }[ $assoc ] = array ( 'className' => $plugin . '.' . $assoc );
2011-09-18 16:26:59 +00:00
} else {
$this -> { $type }[ $assoc ] = $value ;
2008-06-11 08:54:27 +00:00
}
2008-05-30 11:40:08 +00:00
}
2011-08-20 04:43:34 +00:00
$this -> _generateAssociation ( $type , $assoc );
2008-05-30 11:40:08 +00:00
}
}
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2011-08-20 04:43:34 +00:00
* Protected helper method to create associated models of a given class .
2008-05-30 11:40:08 +00:00
*
* @ param string $assoc Association name
* @ param string $className Class name
2010-07-14 03:58:48 +00:00
* @ param string $plugin name of the plugin where $className is located
2010-04-04 07:14:00 +00:00
* examples : public $hasMany = array ( 'Assoc' => array ( 'className' => 'ModelName' ));
2008-05-30 11:40:08 +00:00
* usage : $this -> Assoc -> modelMethods ();
*
2010-04-04 07:14:00 +00:00
* public $hasMany = array ( 'ModelName' );
2008-05-30 11:40:08 +00:00
* usage : $this -> ModelName -> modelMethods ();
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2011-08-20 04:43:34 +00:00
protected function _constructLinkedModel ( $assoc , $className = null , $plugin = null ) {
2008-10-23 00:10:44 +00:00
if ( empty ( $className )) {
2008-05-30 11:40:08 +00:00
$className = $assoc ;
}
2008-09-19 15:27:43 +00:00
if ( ! isset ( $this -> { $assoc }) || $this -> { $assoc } -> name !== $className ) {
2011-07-14 06:00:52 +00:00
if ( $plugin ) {
$plugin .= '.' ;
}
$model = array ( 'class' => $plugin . $className , 'alias' => $assoc );
2010-07-06 02:19:22 +00:00
$this -> { $assoc } = ClassRegistry :: init ( $model );
2010-07-14 23:53:41 +00:00
if ( $plugin ) {
2011-07-14 06:00:52 +00:00
ClassRegistry :: addObject ( $plugin . $className , $this -> { $assoc });
2010-01-18 17:35:30 +00:00
}
2008-06-11 08:54:27 +00:00
if ( $assoc ) {
$this -> tableToModel [ $this -> { $assoc } -> table ] = $assoc ;
}
2008-05-30 11:40:08 +00:00
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Build an array - based association from string .
2008-05-30 11:40:08 +00:00
*
* @ param string $type 'belongsTo' , 'hasOne' , 'hasMany' , 'hasAndBelongsToMany'
2010-07-14 21:28:12 +00:00
* @ param string $assocKey
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2011-08-20 04:43:34 +00:00
protected function _generateAssociation ( $type , $assocKey ) {
2010-07-14 21:28:12 +00:00
$class = $assocKey ;
$dynamicWith = false ;
2008-05-30 11:40:08 +00:00
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associationKeys [ $type ] as $key ) {
2008-10-12 22:21:55 +00:00
2010-07-14 21:28:12 +00:00
if ( ! isset ( $this -> { $type }[ $assocKey ][ $key ]) || $this -> { $type }[ $assocKey ][ $key ] === null ) {
$data = '' ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
switch ( $key ) {
case 'fields' :
$data = '' ;
break ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
case 'foreignKey' :
$data = (( $type == 'belongsTo' ) ? Inflector :: underscore ( $assocKey ) : Inflector :: singularize ( $this -> table )) . '_id' ;
break ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
case 'associationForeignKey' :
$data = Inflector :: singularize ( $this -> { $class } -> table ) . '_id' ;
break ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
case 'with' :
$data = Inflector :: camelize ( Inflector :: singularize ( $this -> { $type }[ $assocKey ][ 'joinTable' ]));
$dynamicWith = true ;
break ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
case 'joinTable' :
$tables = array ( $this -> table , $this -> { $class } -> table );
sort ( $tables );
$data = $tables [ 0 ] . '_' . $tables [ 1 ];
break ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
case 'className' :
$data = $class ;
break ;
2008-05-30 11:40:08 +00:00
2010-07-14 21:28:12 +00:00
case 'unique' :
$data = true ;
break ;
2008-05-30 11:40:08 +00:00
}
2010-07-14 21:28:12 +00:00
$this -> { $type }[ $assocKey ][ $key ] = $data ;
2008-05-30 11:40:08 +00:00
}
2010-07-15 03:49:38 +00:00
if ( $dynamicWith ) {
$this -> { $type }[ $assocKey ][ 'dynamicWith' ] = true ;
2010-07-14 21:28:12 +00:00
}
2008-05-30 11:40:08 +00:00
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +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
2010-07-16 03:41:30 +00:00
* @ throws MissingTableException when database table $tableName is not found on data source
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function setSource ( $tableName ) {
2008-05-30 11:40:08 +00:00
$this -> setDataSource ( $this -> useDbConfig );
2010-07-16 01:46:52 +00:00
$db = ConnectionManager :: getDataSource ( $this -> useDbConfig );
2008-08-27 04:55:15 +00:00
$db -> cacheSources = ( $this -> cacheSources && $db -> cacheSources );
2008-05-30 11:40:08 +00:00
2011-02-25 01:51:43 +00:00
if ( method_exists ( $db , 'listSources' )) {
2008-05-30 11:40:08 +00:00
$sources = $db -> listSources ();
if ( is_array ( $sources ) && ! in_array ( strtolower ( $this -> tablePrefix . $tableName ), array_map ( 'strtolower' , $sources ))) {
2010-08-30 01:37:25 +00:00
throw new MissingTableException ( array (
'table' => $this -> tablePrefix . $tableName ,
2011-11-05 06:50:11 +00:00
'class' => $this -> alias ,
'ds' => $this -> useDbConfig ,
2010-08-30 01:37:25 +00:00
));
2008-05-30 11:40:08 +00:00
}
$this -> _schema = null ;
}
$this -> table = $this -> useTable = $tableName ;
$this -> tableToModel [ $this -> table ] = $this -> alias ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2009-11-12 04:17:23 +00:00
* This function does two things :
2009-10-06 01:27:34 +00:00
*
* 1. it scans the array $one for the primary key ,
2008-05-30 11:40:08 +00:00
* 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 .
2009-10-06 01:27:34 +00:00
* 2. Returns an array with all of $one ' s keys and values .
2008-05-30 11:40:08 +00:00
* ( 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 array Data with all of $one ' s keys and values
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function set ( $one , $two = null ) {
2008-05-30 11:40:08 +00:00
if ( ! $one ) {
return ;
}
if ( is_object ( $one )) {
2010-10-18 00:47:43 +00:00
if ( $one instanceof SimpleXMLElement || $one instanceof DOMNode ) {
$one = $this -> _normalizeXmlData ( Xml :: toArray ( $one ));
} else {
$one = Set :: reverse ( $one );
}
2008-05-30 11:40:08 +00:00
}
if ( is_array ( $one )) {
2008-06-14 20:39:27 +00:00
$data = $one ;
if ( empty ( $one [ $this -> alias ])) {
2008-08-01 06:28:59 +00:00
if ( $this -> getAssociated ( key ( $one )) === null ) {
2008-06-14 20:39:27 +00:00
$data = array ( $this -> alias => $one );
}
2008-05-30 11:40:08 +00:00
}
} else {
$data = array ( $this -> alias => array ( $one => $two ));
}
2008-10-06 02:44:05 +00:00
foreach ( $data as $modelName => $fieldSet ) {
if ( is_array ( $fieldSet )) {
2008-05-30 11:40:08 +00:00
2008-10-06 02:44:05 +00:00
foreach ( $fieldSet as $fieldName => $fieldValue ) {
if ( isset ( $this -> validationErrors [ $fieldName ])) {
unset ( $this -> validationErrors [ $fieldName ]);
2008-05-30 11:40:08 +00:00
}
2008-10-06 02:44:05 +00:00
if ( $modelName === $this -> alias ) {
if ( $fieldName === $this -> primaryKey ) {
$this -> id = $fieldValue ;
2008-05-30 11:40:08 +00:00
}
}
2008-10-06 02:44:05 +00:00
if ( is_array ( $fieldValue ) || is_object ( $fieldValue )) {
$fieldValue = $this -> deconstruct ( $fieldName , $fieldValue );
2008-05-30 11:40:08 +00:00
}
2008-10-06 02:44:05 +00:00
$this -> data [ $modelName ][ $fieldName ] = $fieldValue ;
2008-05-30 11:40:08 +00:00
}
}
}
return $data ;
}
2009-07-24 19:18:37 +00:00
2010-10-18 00:47:43 +00:00
/**
* Normalize Xml :: toArray () to use in Model :: save ()
*
* @ param array $xml XML as array
* @ return array
*/
protected function _normalizeXmlData ( array $xml ) {
$return = array ();
foreach ( $xml as $key => $value ) {
if ( is_array ( $value )) {
$return [ Inflector :: camelize ( $key )] = $this -> _normalizeXmlData ( $value );
} elseif ( $key [ 0 ] === '@' ) {
$return [ substr ( $key , 1 )] = $value ;
} else {
$return [ $key ] = $value ;
}
}
return $return ;
}
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Deconstructs a complex data type ( array or object ) into a single field value .
2008-05-30 11:40:08 +00:00
*
* @ param string $field The name of the field to be deconstructed
* @ param mixed $data An array or object to be deconstructed into a field
* @ return mixed The resulting data that should be assigned to a field
*/
2010-04-05 03:19:38 +00:00
public function deconstruct ( $field , $data ) {
2009-06-02 03:23:15 +00:00
if ( ! is_array ( $data )) {
return $data ;
}
2008-05-30 11:40:08 +00:00
$type = $this -> getColumnType ( $field );
if ( in_array ( $type , array ( 'datetime' , 'timestamp' , 'date' , 'time' ))) {
2009-07-24 19:18:37 +00:00
$useNewDate = ( isset ( $data [ 'year' ]) || isset ( $data [ 'month' ]) ||
2009-07-08 03:25:30 +00:00
isset ( $data [ 'day' ]) || isset ( $data [ 'hour' ]) || isset ( $data [ 'minute' ]));
2008-05-30 11:40:08 +00:00
$dateFields = array ( 'Y' => 'year' , 'm' => 'month' , 'd' => 'day' , 'H' => 'hour' , 'i' => 'min' , 's' => 'sec' );
2009-07-08 03:25:30 +00:00
$timeFields = array ( 'H' => 'hour' , 'i' => 'min' , 's' => 'sec' );
2008-05-30 11:40:08 +00:00
$date = array ();
2011-12-26 15:03:14 +00:00
if ( isset ( $data [ 'meridian' ]) && empty ( $data [ 'meridian' ])) {
return null ;
}
if (
isset ( $data [ 'hour' ]) &&
isset ( $data [ 'meridian' ]) &&
! empty ( $data [ 'hour' ]) &&
$data [ 'hour' ] != 12 &&
'pm' == $data [ 'meridian' ]
) {
2008-05-30 11:40:08 +00:00
$data [ 'hour' ] = $data [ 'hour' ] + 12 ;
}
if ( isset ( $data [ 'hour' ]) && isset ( $data [ 'meridian' ]) && $data [ 'hour' ] == 12 && 'am' == $data [ 'meridian' ]) {
$data [ 'hour' ] = '00' ;
}
2009-07-08 03:25:30 +00:00
if ( $type == 'time' ) {
foreach ( $timeFields as $key => $val ) {
if ( ! isset ( $data [ $val ]) || $data [ $val ] === '0' || $data [ $val ] === '00' ) {
2008-05-30 11:40:08 +00:00
$data [ $val ] = '00' ;
2011-12-26 16:56:44 +00:00
} elseif ( $data [ $val ] !== '' ) {
2008-05-30 11:40:08 +00:00
$data [ $val ] = sprintf ( '%02d' , $data [ $val ]);
}
2009-07-08 03:25:30 +00:00
if ( ! empty ( $data [ $val ])) {
$date [ $key ] = $data [ $val ];
} else {
return null ;
}
2008-05-30 11:40:08 +00:00
}
2009-07-08 03:25:30 +00:00
}
if ( $type == 'datetime' || $type == 'timestamp' || $type == 'date' ) {
foreach ( $dateFields as $key => $val ) {
if ( $val == 'hour' || $val == 'min' || $val == 'sec' ) {
if ( ! isset ( $data [ $val ]) || $data [ $val ] === '0' || $data [ $val ] === '00' ) {
$data [ $val ] = '00' ;
} else {
$data [ $val ] = sprintf ( '%02d' , $data [ $val ]);
}
}
if ( ! isset ( $data [ $val ]) || isset ( $data [ $val ]) && ( empty ( $data [ $val ]) || $data [ $val ][ 0 ] === '-' )) {
return null ;
}
if ( isset ( $data [ $val ]) && ! empty ( $data [ $val ])) {
$date [ $key ] = $data [ $val ];
}
2008-05-30 11:40:08 +00:00
}
}
2010-11-27 04:43:04 +00:00
2009-07-08 03:25:30 +00:00
if ( $useNewDate && ! empty ( $date )) {
2011-12-03 19:38:55 +00:00
$format = $this -> getDataSource () -> columns [ $type ][ 'format' ];
foreach ( array ( 'm' , 'd' , 'H' , 'i' , 's' ) as $index ) {
if ( isset ( $date [ $index ])) {
$date [ $index ] = sprintf ( '%02d' , $date [ $index ]);
}
}
return str_replace ( array_keys ( $date ), array_values ( $date ), $format );
2008-05-30 11:40:08 +00:00
}
}
return $data ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns an array of table metadata ( column names and types ) from the database .
* $field => keys ( type , null , default , key , length , extra )
*
* @ param mixed $field Set to true to reload schema , or a string to return a specific field
* @ return array Array of table metadata
*/
2010-04-05 03:19:38 +00:00
public function schema ( $field = false ) {
2012-01-21 18:33:11 +00:00
if ( $this -> useTable !== false && ( ! is_array ( $this -> _schema ) || $field === true )) {
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2008-08-27 04:55:15 +00:00
$db -> cacheSources = ( $this -> cacheSources && $db -> cacheSources );
2011-02-25 01:51:43 +00:00
if ( method_exists ( $db , 'describe' ) && $this -> useTable !== false ) {
2011-07-11 19:07:44 +00:00
$this -> _schema = $db -> describe ( $this );
2008-05-30 11:40:08 +00:00
} elseif ( $this -> useTable === false ) {
$this -> _schema = array ();
}
}
if ( is_string ( $field )) {
if ( isset ( $this -> _schema [ $field ])) {
return $this -> _schema [ $field ];
} else {
return null ;
}
}
return $this -> _schema ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns an associative array of field names and column types .
*
* @ return array Field types indexed by field name
*/
2010-04-05 03:19:38 +00:00
public function getColumnTypes () {
2008-05-30 11:40:08 +00:00
$columns = $this -> schema ();
if ( empty ( $columns )) {
2011-03-20 15:35:43 +00:00
trigger_error ( __d ( 'cake_dev' , '(Model::getColumnTypes) Unable to build model field data. If you are using a model without a database table, try implementing schema()' ), E_USER_WARNING );
2008-05-30 11:40:08 +00:00
}
$cols = array ();
foreach ( $columns as $field => $values ) {
$cols [ $field ] = $values [ 'type' ];
}
return $cols ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns the column type of a column in the model .
2008-05-30 11:40:08 +00:00
*
* @ param string $column The name of the model column
* @ return string Column type
*/
2010-04-05 03:19:38 +00:00
public function getColumnType ( $column ) {
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2008-05-30 11:40:08 +00:00
$cols = $this -> schema ();
$model = null ;
2012-04-11 17:08:45 +00:00
$startQuote = isset ( $db -> startQuote ) ? $db -> startQuote : null ;
$endQuote = isset ( $db -> endQuote ) ? $db -> endQuote : null ;
$column = str_replace ( array ( $startQuote , $endQuote ), '' , $column );
2008-11-10 19:53:04 +00:00
2008-05-30 11:40:08 +00:00
if ( strpos ( $column , '.' )) {
list ( $model , $column ) = explode ( '.' , $column );
}
if ( $model != $this -> alias && isset ( $this -> { $model })) {
return $this -> { $model } -> getColumnType ( $column );
}
if ( isset ( $cols [ $column ]) && isset ( $cols [ $column ][ 'type' ])) {
return $cols [ $column ][ 'type' ];
}
return null ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns true if the supplied field exists in the model ' s database table .
2008-05-30 11:40:08 +00:00
*
* @ param mixed $name Name of field to look for , or an array of names
2009-11-12 05:09:11 +00:00
* @ param boolean $checkVirtual checks if the field is declared as virtual
2008-05-30 11:40:08 +00:00
* @ return mixed If $name is a string , returns a boolean indicating whether the field exists .
* If $name is an array of field names , returns the first field that exists ,
* or false if none exist .
*/
2010-04-05 03:19:38 +00:00
public function hasField ( $name , $checkVirtual = false ) {
2008-05-30 11:40:08 +00:00
if ( is_array ( $name )) {
foreach ( $name as $n ) {
2009-12-17 05:15:42 +00:00
if ( $this -> hasField ( $n , $checkVirtual )) {
2008-05-30 11:40:08 +00:00
return $n ;
}
}
return false ;
}
2009-11-12 05:09:11 +00:00
if ( $checkVirtual && ! empty ( $this -> virtualFields )) {
2009-12-07 02:46:00 +00:00
if ( $this -> isVirtualField ( $name )) {
2009-11-12 05:09:11 +00:00
return true ;
}
}
2008-05-30 11:40:08 +00:00
if ( empty ( $this -> _schema )) {
$this -> schema ();
}
if ( $this -> _schema != null ) {
return isset ( $this -> _schema [ $name ]);
}
return false ;
}
2009-07-24 19:18:37 +00:00
2010-12-26 22:35:22 +00:00
/**
2011-01-29 22:43:01 +00:00
* Check that a method is callable on a model . This will check both the model ' s own methods , its
2010-12-26 22:35:22 +00:00
* inherited methods and methods that could be callable through behaviors .
*
* @ param string $method The method to be called .
* @ return boolean True on method being callable .
*/
public function hasMethod ( $method ) {
if ( method_exists ( $this , $method )) {
return true ;
}
if ( $this -> Behaviors -> hasMethod ( $method )) {
return true ;
}
return false ;
}
2009-12-07 02:46:00 +00:00
/**
* Returns true if the supplied field is a model Virtual Field
*
2011-07-30 22:38:57 +00:00
* @ param string $field Name of field to look for
2009-12-07 02:46:00 +00:00
* @ return boolean indicating whether the field exists as a model virtual field .
*/
2010-04-05 03:19:38 +00:00
public function isVirtualField ( $field ) {
2010-01-19 14:22:13 +00:00
if ( empty ( $this -> virtualFields ) || ! is_string ( $field )) {
return false ;
}
if ( isset ( $this -> virtualFields [ $field ])) {
return true ;
}
if ( strpos ( $field , '.' ) !== false ) {
list ( $model , $field ) = explode ( '.' , $field );
2011-10-04 02:41:31 +00:00
if ( $model == $this -> alias && isset ( $this -> virtualFields [ $field ])) {
2010-01-19 14:22:13 +00:00
return true ;
}
}
return false ;
2009-12-07 02:46:00 +00:00
}
/**
2010-01-14 17:57:43 +00:00
* Returns the expression for a model virtual field
2009-12-07 02:46:00 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param string $field Name of field to look for
2009-12-07 02:46:00 +00:00
* @ return mixed If $field is string expression bound to virtual field $field
2009-12-20 21:26:12 +00:00
* If $field is null , returns an array of all model virtual fields
* or false if none $field exist .
2009-12-07 02:46:00 +00:00
*/
2010-04-05 03:19:38 +00:00
public function getVirtualField ( $field = null ) {
2009-12-07 02:46:00 +00:00
if ( $field == null ) {
return empty ( $this -> virtualFields ) ? false : $this -> virtualFields ;
}
if ( $this -> isVirtualField ( $field )) {
2010-01-19 14:22:13 +00:00
if ( strpos ( $field , '.' ) !== false ) {
list ( $model , $field ) = explode ( '.' , $field );
}
2009-12-07 02:46:00 +00:00
return $this -> virtualFields [ $field ];
}
return false ;
}
2008-05-30 11:40:08 +00:00
/**
* Initializes the model for writing a new record , loading the default values
2009-11-12 04:17:23 +00:00
* for those fields that are not defined in $data , and clearing previous validation errors .
2009-10-13 03:38:55 +00:00
* Especially helpful for saving data in loops .
2008-05-30 11:40:08 +00:00
*
* @ param mixed $data Optional data array to assign to the model after it is created . If null or false ,
2009-10-13 03:38:55 +00:00
* schema data defaults are not merged .
2008-05-30 11:40:08 +00:00
* @ param boolean $filterKey If true , overwrites any primary key input with an empty value
* @ return array The current Model :: data ; after merging $data and / or defaults from database
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-create-array-data-array
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function create ( $data = array (), $filterKey = false ) {
2008-05-30 11:40:08 +00:00
$defaults = array ();
$this -> id = false ;
$this -> data = array ();
$this -> validationErrors = array ();
if ( $data !== null && $data !== false ) {
foreach ( $this -> schema () as $field => $properties ) {
2011-01-21 18:31:33 +00:00
if ( $this -> primaryKey !== $field && isset ( $properties [ 'default' ]) && $properties [ 'default' ] !== '' ) {
2008-05-30 11:40:08 +00:00
$defaults [ $field ] = $properties [ 'default' ];
}
}
2011-01-21 18:31:33 +00:00
$this -> set ( $defaults );
2008-05-30 11:40:08 +00:00
$this -> set ( $data );
}
if ( $filterKey ) {
$this -> set ( $this -> primaryKey , false );
}
return $this -> data ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns a list of fields from the database , and sets the current model
* data ( Model :: $data ) with the record found .
*
2011-12-02 05:58:09 +00:00
* @ param mixed $fields String of single field name , or an array of field names .
2008-05-30 11:40:08 +00:00
* @ param mixed $id The ID of the record to read
* @ return array Array of database fields , or false if not found
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / retrieving - your - data . html #model-read
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function read ( $fields = null , $id = null ) {
2008-05-30 11:40:08 +00:00
$this -> validationErrors = array ();
if ( $id != null ) {
$this -> id = $id ;
}
$id = $this -> id ;
if ( is_array ( $this -> id )) {
$id = $this -> id [ 0 ];
}
if ( $id !== null && $id !== false ) {
2009-05-04 22:57:10 +00:00
$this -> data = $this -> find ( 'first' , array (
'conditions' => array ( $this -> alias . '.' . $this -> primaryKey => $id ),
'fields' => $fields
));
2008-05-30 11:40:08 +00:00
return $this -> data ;
} else {
return false ;
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns the contents of a single field given the supplied conditions , in the
* supplied order .
2008-05-30 11:40:08 +00:00
*
* @ param string $name Name of field to get
* @ param array $conditions SQL conditions ( defaults to NULL )
* @ param string $order SQL ORDER BY fragment
* @ return string field contents , or false if not found
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / retrieving - your - data . html #model-field
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function field ( $name , $conditions = null , $order = null ) {
2008-05-30 11:40:08 +00:00
if ( $conditions === null && $this -> id !== false ) {
$conditions = array ( $this -> alias . '.' . $this -> primaryKey => $this -> id );
}
if ( $this -> recursive >= 1 ) {
$recursive = - 1 ;
} else {
$recursive = $this -> recursive ;
}
2009-11-12 04:13:37 +00:00
$fields = $name ;
2009-12-17 05:15:42 +00:00
if ( $data = $this -> find ( 'first' , compact ( 'conditions' , 'fields' , 'order' , 'recursive' ))) {
2008-05-30 11:40:08 +00:00
if ( strpos ( $name , '.' ) === false ) {
if ( isset ( $data [ $this -> alias ][ $name ])) {
return $data [ $this -> alias ][ $name ];
}
} else {
$name = explode ( '.' , $name );
if ( isset ( $data [ $name [ 0 ]][ $name [ 1 ]])) {
return $data [ $name [ 0 ]][ $name [ 1 ]];
}
}
2009-12-11 00:43:09 +00:00
if ( isset ( $data [ 0 ]) && count ( $data [ 0 ]) > 0 ) {
return array_shift ( $data [ 0 ]);
2008-05-30 11:40:08 +00:00
}
} else {
return false ;
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Saves the value of a single field to the database , based on the current
* model ID .
2008-05-30 11:40:08 +00:00
*
* @ param string $name Name of the table field
* @ param mixed $value Value of the field
2008-07-05 11:02:09 +00:00
* @ param array $validate See $options param in Model :: save () . Does not respect 'fieldList' key if passed
2008-06-20 20:17:23 +00:00
* @ return boolean See Model :: save ()
2008-05-30 11:40:08 +00:00
* @ see Model :: save ()
2012-01-25 09:12:59 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-savefield-string-fieldname-string-fieldvalue-validate-false
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function saveField ( $name , $value , $validate = false ) {
2008-05-30 11:40:08 +00:00
$id = $this -> id ;
$this -> create ( false );
2008-06-20 20:17:23 +00:00
if ( is_array ( $validate )) {
2008-07-05 11:02:09 +00:00
$options = array_merge ( array ( 'validate' => false , 'fieldList' => array ( $name )), $validate );
2008-06-20 20:17:23 +00:00
} else {
$options = array ( 'validate' => $validate , 'fieldList' => array ( $name ));
}
2008-07-05 11:02:09 +00:00
return $this -> save ( array ( $this -> alias => array ( $this -> primaryKey => $id , $name => $value )), $options );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-11-08 02:54:07 +00:00
* Saves model data ( based on white - list , if supplied ) to the database . By
2008-10-31 19:05:30 +00:00
* default , validation occurs before save .
2008-05-30 11:40:08 +00:00
*
* @ param array $data Data to save .
2008-08-23 21:31:38 +00:00
* @ param mixed $validate Either a boolean , or an array .
2009-09-03 15:59:57 +00:00
* If a boolean , indicates whether or not to validate before saving .
* If an array , allows control of validate , callbacks , and fieldList
2008-05-30 11:40:08 +00:00
* @ param array $fieldList List of fields to allow to be written
* @ return mixed On success Model :: $data if its not empty or true , false on failure
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function save ( $data = null , $validate = true , $fieldList = array ()) {
2008-05-30 11:40:08 +00:00
$defaults = array ( 'validate' => true , 'fieldList' => array (), 'callbacks' => true );
2008-09-04 01:00:08 +00:00
$_whitelist = $this -> whitelist ;
2008-05-30 11:40:08 +00:00
$fields = array ();
if ( ! is_array ( $validate )) {
$options = array_merge ( $defaults , compact ( 'validate' , 'fieldList' , 'callbacks' ));
} else {
$options = array_merge ( $defaults , $validate );
}
if ( ! empty ( $options [ 'fieldList' ])) {
2011-12-22 20:37:48 +00:00
if ( ! empty ( $options [ 'fieldList' ][ $this -> alias ]) && is_array ( $options [ 'fieldList' ][ $this -> alias ])) {
$this -> whitelist = $options [ 'fieldList' ][ $this -> alias ];
} else {
$this -> whitelist = $options [ 'fieldList' ];
}
2008-05-30 11:40:08 +00:00
} elseif ( $options [ 'fieldList' ] === null ) {
$this -> whitelist = array ();
}
$this -> set ( $data );
if ( empty ( $this -> data ) && ! $this -> hasField ( array ( 'created' , 'updated' , 'modified' ))) {
return false ;
}
foreach ( array ( 'created' , 'updated' , 'modified' ) as $field ) {
2008-09-04 01:00:08 +00:00
$keyPresentAndEmpty = (
isset ( $this -> data [ $this -> alias ]) &&
array_key_exists ( $field , $this -> data [ $this -> alias ]) &&
$this -> data [ $this -> alias ][ $field ] === null
);
if ( $keyPresentAndEmpty ) {
2008-05-30 11:40:08 +00:00
unset ( $this -> data [ $this -> alias ][ $field ]);
}
}
2008-06-15 02:58:23 +00:00
2010-01-14 18:47:38 +00:00
$exists = $this -> exists ();
2008-05-30 11:40:08 +00:00
$dateFields = array ( 'modified' , 'updated' );
2010-01-14 18:47:38 +00:00
if ( ! $exists ) {
2008-05-30 11:40:08 +00:00
$dateFields [] = 'created' ;
}
if ( isset ( $this -> data [ $this -> alias ])) {
$fields = array_keys ( $this -> data [ $this -> alias ]);
}
if ( $options [ 'validate' ] && ! $this -> validates ( $options )) {
$this -> whitelist = $_whitelist ;
return false ;
}
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2008-09-04 01:00:08 +00:00
2008-05-30 11:40:08 +00:00
foreach ( $dateFields as $updateCol ) {
if ( $this -> hasField ( $updateCol ) && ! in_array ( $updateCol , $fields )) {
2008-12-17 04:13:45 +00:00
$default = array ( 'formatter' => 'date' );
$colType = array_merge ( $default , $db -> columns [ $this -> getColumnType ( $updateCol )]);
if ( ! array_key_exists ( 'format' , $colType )) {
2008-05-30 11:40:08 +00:00
$time = strtotime ( 'now' );
} else {
2012-03-28 15:49:41 +00:00
$time = call_user_func ( $colType [ 'formatter' ], $colType [ 'format' ]);
2008-05-30 11:40:08 +00:00
}
if ( ! empty ( $this -> whitelist )) {
$this -> whitelist [] = $updateCol ;
}
$this -> set ( $updateCol , $time );
}
}
2008-06-20 20:17:23 +00:00
if ( $options [ 'callbacks' ] === true || $options [ 'callbacks' ] === 'before' ) {
2011-12-26 17:36:48 +00:00
$event = new CakeEvent ( 'Model.beforeSave' , $this , array ( $options ));
list ( $event -> break , $event -> breakOn ) = array ( true , array ( false , null ));
$this -> getEventManager () -> dispatch ( $event );
if ( ! $event -> result ) {
2008-05-30 11:40:08 +00:00
$this -> whitelist = $_whitelist ;
return false ;
}
}
2010-05-12 02:40:56 +00:00
if ( empty ( $this -> data [ $this -> alias ][ $this -> primaryKey ])) {
2008-05-30 11:40:08 +00:00
unset ( $this -> data [ $this -> alias ][ $this -> primaryKey ]);
}
2010-01-14 18:47:38 +00:00
$fields = $values = array ();
2008-05-30 11:40:08 +00:00
foreach ( $this -> data as $n => $v ) {
if ( isset ( $this -> hasAndBelongsToMany [ $n ])) {
if ( isset ( $v [ $n ])) {
$v = $v [ $n ];
}
$joined [ $n ] = $v ;
} else {
if ( $n === $this -> alias ) {
foreach ( array ( 'created' , 'updated' , 'modified' ) as $field ) {
if ( array_key_exists ( $field , $v ) && empty ( $v [ $field ])) {
unset ( $v [ $field ]);
}
}
foreach ( $v as $x => $y ) {
if ( $this -> hasField ( $x ) && ( empty ( $this -> whitelist ) || in_array ( $x , $this -> whitelist ))) {
list ( $fields [], $values []) = array ( $x , $y );
}
}
}
}
}
$count = count ( $fields );
2010-01-14 18:47:38 +00:00
if ( ! $exists && $count > 0 ) {
2008-05-30 11:40:08 +00:00
$this -> id = false ;
}
$success = true ;
$created = false ;
if ( $count > 0 ) {
2008-12-17 04:13:45 +00:00
$cache = $this -> _prepareUpdateFields ( array_combine ( $fields , $values ));
2008-05-30 11:40:08 +00:00
if ( ! empty ( $this -> id )) {
2008-12-17 04:13:45 +00:00
$success = ( bool ) $db -> update ( $this , $fields , $values );
2008-05-30 11:40:08 +00:00
} else {
2010-07-16 01:49:23 +00:00
$fInfo = $this -> schema ( $this -> primaryKey );
2010-03-16 03:36:20 +00:00
$isUUID = ( $fInfo [ 'length' ] == 36 &&
( $fInfo [ 'type' ] === 'string' || $fInfo [ 'type' ] === 'binary' )
);
if ( empty ( $this -> data [ $this -> alias ][ $this -> primaryKey ]) && $isUUID ) {
if ( array_key_exists ( $this -> primaryKey , $this -> data [ $this -> alias ])) {
$j = array_search ( $this -> primaryKey , $fields );
$values [ $j ] = String :: uuid ();
} else {
list ( $fields [], $values []) = array ( $this -> primaryKey , String :: uuid ());
2008-05-30 11:40:08 +00:00
}
}
if ( ! $db -> create ( $this , $fields , $values )) {
$success = $created = false ;
} else {
$created = true ;
}
}
2008-12-17 04:13:45 +00:00
if ( $success && ! empty ( $this -> belongsTo )) {
$this -> updateCounterCache ( $cache , $created );
}
2008-05-30 11:40:08 +00:00
}
if ( ! empty ( $joined ) && $success === true ) {
2011-08-20 04:43:34 +00:00
$this -> _saveMulti ( $joined , $this -> id , $db );
2008-05-30 11:40:08 +00:00
}
if ( $success && $count > 0 ) {
if ( ! empty ( $this -> data )) {
$success = $this -> data ;
2011-08-13 21:26:08 +00:00
if ( $created ) {
$this -> data [ $this -> alias ][ $this -> primaryKey ] = $this -> id ;
}
2008-05-30 11:40:08 +00:00
}
2008-06-20 20:17:23 +00:00
if ( $options [ 'callbacks' ] === true || $options [ 'callbacks' ] === 'after' ) {
2011-12-26 17:36:48 +00:00
$event = new CakeEvent ( 'Model.afterSave' , $this , array ( $created , $options ));
$this -> getEventManager () -> dispatch ( $event );
2008-05-30 11:40:08 +00:00
}
if ( ! empty ( $this -> data )) {
$success = Set :: merge ( $success , $this -> data );
}
$this -> data = false ;
$this -> _clearCache ();
$this -> validationErrors = array ();
}
$this -> whitelist = $_whitelist ;
return $success ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Saves model hasAndBelongsToMany data to the database .
*
* @ param array $joined Data to save
* @ param mixed $id ID of record in this model
2011-07-30 22:38:57 +00:00
* @ param DataSource $db
* @ return void
2008-05-30 11:40:08 +00:00
*/
2011-08-20 04:43:34 +00:00
protected function _saveMulti ( $joined , $id , $db ) {
2008-10-29 07:19:26 +00:00
foreach ( $joined as $assoc => $data ) {
2008-05-30 11:40:08 +00:00
if ( isset ( $this -> hasAndBelongsToMany [ $assoc ])) {
list ( $join ) = $this -> joinModel ( $this -> hasAndBelongsToMany [ $assoc ][ 'with' ]);
2008-10-29 07:19:26 +00:00
2010-07-16 01:49:23 +00:00
$keyInfo = $this -> { $join } -> schema ( $this -> { $join } -> primaryKey );
2011-11-05 11:15:51 +00:00
if ( $with = $this -> hasAndBelongsToMany [ $assoc ][ 'with' ]) {
$withModel = is_array ( $with ) ? key ( $with ) : $with ;
list ( $pluginName , $withModel ) = pluginSplit ( $withModel );
$dbMulti = $this -> { $withModel } -> getDataSource ();
} else {
$dbMulti = $db ;
}
2009-03-04 01:36:53 +00:00
$isUUID = ! empty ( $this -> { $join } -> primaryKey ) && (
2010-07-16 01:49:23 +00:00
$keyInfo [ 'length' ] == 36 && (
$keyInfo [ 'type' ] === 'string' ||
$keyInfo [ 'type' ] === 'binary'
2009-03-04 01:36:53 +00:00
)
);
2008-10-23 13:29:32 +00:00
2011-05-23 06:50:59 +00:00
$newData = $newValues = $newJoins = array ();
2008-12-30 16:09:25 +00:00
$primaryAdded = false ;
2012-03-04 19:18:04 +00:00
$fields = array (
2011-11-05 11:15:51 +00:00
$dbMulti -> name ( $this -> hasAndBelongsToMany [ $assoc ][ 'foreignKey' ]),
$dbMulti -> name ( $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ])
2008-12-30 16:09:25 +00:00
);
$idField = $db -> name ( $this -> { $join } -> primaryKey );
if ( $isUUID && ! in_array ( $idField , $fields )) {
$fields [] = $idField ;
$primaryAdded = true ;
}
2008-10-29 07:19:26 +00:00
2008-10-30 00:11:32 +00:00
foreach (( array ) $data as $row ) {
2008-11-09 20:55:51 +00:00
if (( is_string ( $row ) && ( strlen ( $row ) == 36 || strlen ( $row ) == 16 )) || is_numeric ( $row )) {
2011-05-23 06:50:59 +00:00
$newJoins [] = $row ;
2010-10-25 00:29:54 +00:00
$values = array ( $id , $row );
2008-12-30 16:09:25 +00:00
if ( $isUUID && $primaryAdded ) {
2010-10-25 00:29:54 +00:00
$values [] = String :: uuid ();
2008-05-30 11:40:08 +00:00
}
2011-05-23 06:50:59 +00:00
$newValues [ $row ] = $values ;
2008-10-29 07:19:26 +00:00
unset ( $values );
2008-11-09 20:55:51 +00:00
} elseif ( isset ( $row [ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]])) {
2012-03-18 08:05:49 +00:00
if ( ! empty ( $row [ $this -> { $join } -> primaryKey ])) {
$newJoins [] = $row [ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]];
}
2008-10-29 07:19:26 +00:00
$newData [] = $row ;
2009-07-23 19:28:46 +00:00
} elseif ( isset ( $row [ $join ]) && isset ( $row [ $join ][ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]])) {
2012-03-18 08:05:49 +00:00
if ( ! empty ( $row [ $join ][ $this -> { $join } -> primaryKey ])) {
$newJoins [] = $row [ $join ][ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]];
}
2009-02-11 03:53:04 +00:00
$newData [] = $row [ $join ];
2008-10-29 07:19:26 +00:00
}
}
2011-05-23 06:50:59 +00:00
$keepExisting = $this -> hasAndBelongsToMany [ $assoc ][ 'unique' ] === 'keepExisting' ;
2009-01-16 04:09:44 +00:00
if ( $this -> hasAndBelongsToMany [ $assoc ][ 'unique' ]) {
2010-03-16 03:14:23 +00:00
$conditions = array (
$join . '.' . $this -> hasAndBelongsToMany [ $assoc ][ 'foreignKey' ] => $id
2009-11-22 22:56:46 +00:00
);
2010-03-16 03:14:23 +00:00
if ( ! empty ( $this -> hasAndBelongsToMany [ $assoc ][ 'conditions' ])) {
$conditions = array_merge ( $conditions , ( array ) $this -> hasAndBelongsToMany [ $assoc ][ 'conditions' ]);
}
2012-03-04 19:18:04 +00:00
$associationForeignKey = $this -> { $join } -> alias . '.' . $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ];
2009-11-22 22:56:46 +00:00
$links = $this -> { $join } -> find ( 'all' , array (
'conditions' => $conditions ,
'recursive' => empty ( $this -> hasAndBelongsToMany [ $assoc ][ 'conditions' ]) ? - 1 : 0 ,
2011-05-23 06:50:59 +00:00
'fields' => $associationForeignKey ,
2009-11-22 22:56:46 +00:00
));
2008-10-29 07:19:26 +00:00
$oldLinks = Set :: extract ( $links , " { n}. { $associationForeignKey } " );
if ( ! empty ( $oldLinks )) {
2011-05-23 06:50:59 +00:00
if ( $keepExisting && ! empty ( $newJoins )) {
$conditions [ $associationForeignKey ] = array_diff ( $oldLinks , $newJoins );
} else {
$conditions [ $associationForeignKey ] = $oldLinks ;
}
2011-11-05 11:15:51 +00:00
$dbMulti -> delete ( $this -> { $join }, $conditions );
2008-05-30 11:40:08 +00:00
}
}
2009-01-16 04:09:44 +00:00
if ( ! empty ( $newData )) {
foreach ( $newData as $data ) {
$data [ $this -> hasAndBelongsToMany [ $assoc ][ 'foreignKey' ]] = $id ;
2012-03-18 08:05:49 +00:00
if ( empty ( $data [ $this -> { $join } -> primaryKey ])) {
$this -> { $join } -> create ();
}
$this -> { $join } -> save ( $data );
2009-01-16 04:09:44 +00:00
}
}
2008-05-30 11:40:08 +00:00
if ( ! empty ( $newValues )) {
2011-05-23 06:50:59 +00:00
if ( $keepExisting && ! empty ( $links )) {
foreach ( $links as $link ) {
$oldJoin = $link [ $join ][ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]];
if ( ! in_array ( $oldJoin , $newJoins ) ) {
$conditions [ $associationForeignKey ] = $oldJoin ;
$db -> delete ( $this -> { $join }, $conditions );
} else {
unset ( $newValues [ $oldJoin ]);
}
}
$newValues = array_values ( $newValues );
}
if ( ! empty ( $newValues )) {
$dbMulti -> insertMulti ( $this -> { $join }, $fields , $newValues );
}
2008-05-30 11:40:08 +00:00
}
}
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Updates the counter cache of belongsTo associations after a save or delete operation
*
* @ param array $keys Optional foreign key data , defaults to the information $this -> data
* @ param boolean $created True if a new record was created , otherwise only associations with
2009-10-06 01:27:34 +00:00
* 'counterScope' defined get updated
2008-05-30 11:40:08 +00:00
* @ return void
*/
2010-04-05 03:19:38 +00:00
public function updateCounterCache ( $keys = array (), $created = false ) {
2008-12-17 04:13:45 +00:00
$keys = empty ( $keys ) ? $this -> data [ $this -> alias ] : $keys ;
$keys [ 'old' ] = isset ( $keys [ 'old' ]) ? $keys [ 'old' ] : array ();
2008-05-30 11:40:08 +00:00
foreach ( $this -> belongsTo as $parent => $assoc ) {
if ( ! empty ( $assoc [ 'counterCache' ])) {
2011-08-17 12:40:32 +00:00
if ( ! is_array ( $assoc [ 'counterCache' ])) {
if ( isset ( $assoc [ 'counterScope' ])) {
$assoc [ 'counterCache' ] = array ( $assoc [ 'counterCache' ] => $assoc [ 'counterScope' ]);
} else {
$assoc [ 'counterCache' ] = array ( $assoc [ 'counterCache' ] => array ());
}
2008-05-30 11:40:08 +00:00
}
2008-12-17 04:13:45 +00:00
2011-08-17 12:40:32 +00:00
$foreignKey = $assoc [ 'foreignKey' ];
$fkQuoted = $this -> escapeField ( $assoc [ 'foreignKey' ]);
foreach ( $assoc [ 'counterCache' ] as $field => $conditions ) {
if ( ! is_string ( $field )) {
$field = Inflector :: underscore ( $this -> alias ) . '_count' ;
}
if ( ! $this -> { $parent } -> hasField ( $field )) {
continue ;
}
if ( $conditions === true ) {
$conditions = array ();
} else {
$conditions = ( array ) $conditions ;
2008-05-30 11:40:08 +00:00
}
2008-12-17 04:13:45 +00:00
2011-08-17 12:40:32 +00:00
if ( ! array_key_exists ( $foreignKey , $keys )) {
$keys [ $foreignKey ] = $this -> field ( $foreignKey );
}
$recursive = ( empty ( $conditions ) ? - 1 : 0 );
2008-12-17 04:13:45 +00:00
2011-08-17 12:40:32 +00:00
if ( isset ( $keys [ 'old' ][ $foreignKey ])) {
if ( $keys [ 'old' ][ $foreignKey ] != $keys [ $foreignKey ]) {
$conditions [ $fkQuoted ] = $keys [ 'old' ][ $foreignKey ];
$count = intval ( $this -> find ( 'count' , compact ( 'conditions' , 'recursive' )));
$this -> { $parent } -> updateAll (
array ( $field => $count ),
array ( $this -> { $parent } -> escapeField () => $keys [ 'old' ][ $foreignKey ])
);
}
}
$conditions [ $fkQuoted ] = $keys [ $foreignKey ];
if ( $recursive === 0 ) {
$conditions = array_merge ( $conditions , ( array ) $conditions );
}
$count = intval ( $this -> find ( 'count' , compact ( 'conditions' , 'recursive' )));
$this -> { $parent } -> updateAll (
array ( $field => $count ),
array ( $this -> { $parent } -> escapeField () => $keys [ $foreignKey ])
);
}
2008-12-17 04:13:45 +00:00
}
}
}
2009-07-24 19:18:37 +00:00
2008-12-17 04:13:45 +00:00
/**
* Helper method for Model :: updateCounterCache () . Checks the fields to be updated for
*
* @ param array $data The fields of the record that will be updated
* @ return array Returns updated foreign key values , along with an 'old' key containing the old
2010-03-06 03:07:39 +00:00
* values , or empty if no foreign keys are updated .
2008-12-17 04:13:45 +00:00
*/
2010-04-05 03:21:28 +00:00
protected function _prepareUpdateFields ( $data ) {
2008-12-17 04:13:45 +00:00
$foreignKeys = array ();
foreach ( $this -> belongsTo as $assoc => $info ) {
if ( $info [ 'counterCache' ]) {
$foreignKeys [ $assoc ] = $info [ 'foreignKey' ];
2008-05-30 11:40:08 +00:00
}
}
2008-12-17 04:13:45 +00:00
$included = array_intersect ( $foreignKeys , array_keys ( $data ));
if ( empty ( $included ) || empty ( $this -> id )) {
return array ();
}
$old = $this -> find ( 'first' , array (
2012-02-16 16:22:45 +00:00
'conditions' => array ( $this -> alias . '.' . $this -> primaryKey => $this -> id ),
2008-12-17 04:13:45 +00:00
'fields' => array_values ( $included ),
'recursive' => - 1
));
return array_merge ( $data , array ( 'old' => $old [ $this -> alias ]));
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2011-12-02 05:58:09 +00:00
* Backwards compatible passthrough method for :
2011-07-25 07:39:03 +00:00
* saveMany (), validateMany (), saveAssociated () and validateAssociated ()
*
2008-10-31 19:05:30 +00:00
* Saves multiple individual records for a single model ; Also works with a single record , as well as
* all its associated records .
2008-05-30 11:40:08 +00:00
*
2009-09-03 15:59:57 +00:00
* #### Options
*
2010-03-27 23:59:42 +00:00
* - validate : Set to false to disable validation , true to validate each record before saving ,
* 'first' to validate * all * records before any are saved ( default ),
* or 'only' to only validate the records , but not save them .
2009-09-03 15:59:57 +00:00
* - atomic : If true ( default ), will attempt to save all records in a single transaction .
* Should be set to false if database / table does not support transactions .
2012-02-12 16:38:03 +00:00
* - fieldList : Equivalent to the $fieldList parameter in Model :: save () .
* It should be an associate array with model name as key and array of fields as value . Eg .
* {{{
* array (
* 'SomeModel' => array ( 'field' ),
* 'AssociatedModel' => array ( 'field' , 'otherfield' )
* )
* }}}
2012-02-13 00:00:28 +00:00
* - deep : see saveMany / saveAssociated
2009-09-03 15:59:57 +00:00
*
2011-07-25 07:39:03 +00:00
* @ param array $data Record data to save . This can be either a numerically - indexed array ( for saving multiple
2009-09-03 15:59:57 +00:00
* records of the same type ), or an array indexed by association name .
* @ param array $options Options to use when saving record data , See $options above .
2010-02-23 15:05:30 +00:00
* @ return mixed If atomic : True on success , or false on failure .
2010-03-06 03:07:39 +00:00
* Otherwise : array similar to the $data array passed , but values are set to true / false
* depending on whether each record saved successfully .
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-saveassociated-array-data-null-array-options-array
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-saveall-array-data-null-array-options-array
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function saveAll ( $data = null , $options = array ()) {
2011-07-25 07:39:03 +00:00
$options = array_merge ( array ( 'validate' => 'first' ), $options );
if ( Set :: numeric ( array_keys ( $data ))) {
if ( $options [ 'validate' ] === 'only' ) {
return $this -> validateMany ( $data , $options );
}
return $this -> saveMany ( $data , $options );
}
if ( $options [ 'validate' ] === 'only' ) {
2012-02-13 00:00:28 +00:00
return $this -> validateAssociated ( $data , $options );
2011-07-25 07:39:03 +00:00
}
return $this -> saveAssociated ( $data , $options );
}
/**
* Saves multiple individual records for a single model
*
* #### Options
*
* - validate : Set to false to disable validation , true to validate each record before saving ,
* 'first' to validate * all * records before any are saved ( default ),
* - atomic : If true ( default ), will attempt to save all records in a single transaction .
* Should be set to false if database / table does not support transactions .
* - fieldList : Equivalent to the $fieldList parameter in Model :: save ()
2012-02-13 00:00:28 +00:00
* - deep : If set to true , all associated data will be saved as well .
2011-07-25 07:39:03 +00:00
*
* @ param array $data Record data to save . This should be a numerically - indexed array
* @ param array $options Options to use when saving record data , See $options above .
* @ return mixed If atomic : True on success , or false on failure .
* Otherwise : array similar to the $data array passed , but values are set to true / false
* depending on whether each record saved successfully .
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-savemany-array-data-null-array-options-array
2011-07-25 07:39:03 +00:00
*/
public function saveMany ( $data = null , $options = array ()) {
2008-05-30 11:40:08 +00:00
if ( empty ( $data )) {
$data = $this -> data ;
}
2012-02-13 00:00:28 +00:00
$options = array_merge ( array ( 'validate' => 'first' , 'atomic' => true , 'deep' => false ), $options );
2008-05-30 11:40:08 +00:00
$this -> validationErrors = $validationErrors = array ();
2010-03-17 19:49:30 +00:00
if ( empty ( $data ) && $options [ 'validate' ] !== false ) {
$result = $this -> save ( $data , $options );
2012-04-16 20:46:58 +00:00
if ( ! $options [ 'atomic' ]) {
return array ( ! empty ( $result ));
}
2010-03-17 19:49:30 +00:00
return ! empty ( $result );
}
2011-07-25 07:39:03 +00:00
if ( $options [ 'validate' ] === 'first' ) {
$validates = $this -> validateMany ( $data , $options );
if (( ! $validates && $options [ 'atomic' ]) || ( ! $options [ 'atomic' ] && in_array ( false , $validates , true ))) {
return $validates ;
}
2012-04-16 07:45:44 +00:00
$options [ 'validate' ] = false ;
2011-07-25 07:39:03 +00:00
}
if ( $options [ 'atomic' ]) {
$db = $this -> getDataSource ();
2012-01-17 20:52:22 +00:00
$transactionBegun = $db -> begin ();
2008-05-30 11:40:08 +00:00
}
2011-07-25 07:39:03 +00:00
$return = array ();
foreach ( $data as $key => $record ) {
2012-02-13 00:00:28 +00:00
$validates = $this -> create ( null ) !== null ;
$saved = false ;
if ( $validates ) {
if ( $options [ 'deep' ]) {
$saved = $this -> saveAssociated ( $record , array_merge ( $options , array ( 'atomic' => false )));
} else {
$saved = $this -> save ( $record , $options );
}
}
$validates = ( $validates && ( $saved === true || ( is_array ( $saved ) && ! in_array ( false , $saved , true ))));
2011-07-25 07:39:03 +00:00
if ( ! $validates ) {
$validationErrors [ $key ] = $this -> validationErrors ;
}
if ( ! $options [ 'atomic' ]) {
2012-02-13 00:00:28 +00:00
$return [ $key ] = $validates ;
2011-07-25 07:39:03 +00:00
} elseif ( ! $validates ) {
break ;
}
}
$this -> validationErrors = $validationErrors ;
2008-05-30 11:40:08 +00:00
2011-07-25 07:39:03 +00:00
if ( ! $options [ 'atomic' ]) {
return $return ;
}
if ( $validates ) {
if ( $transactionBegun ) {
2012-01-17 20:52:22 +00:00
return $db -> commit () !== false ;
2011-07-25 07:39:03 +00:00
} else {
return true ;
}
}
2012-01-17 20:52:22 +00:00
$db -> rollback ();
2011-07-25 07:39:03 +00:00
return false ;
}
2008-09-19 15:27:43 +00:00
2011-07-25 07:39:03 +00:00
/**
* Validates multiple individual records for a single model
*
* #### Options
*
* - atomic : If true ( default ), returns boolean . If false returns array .
* - fieldList : Equivalent to the $fieldList parameter in Model :: save ()
2012-02-13 00:00:28 +00:00
* - deep : If set to true , all associated data will be validated as well .
2011-07-25 07:39:03 +00:00
*
* @ param array $data Record data to validate . This should be a numerically - indexed array
* @ param array $options Options to use when validating record data ( see above ), See also $options of validates () .
* @ return boolean True on success , or false on failure .
* @ return mixed If atomic : True on success , or false on failure .
* Otherwise : array similar to the $data array passed , but values are set to true / false
* depending on whether each record validated successfully .
*/
public function validateMany ( $data , $options = array ()) {
2012-02-13 00:00:28 +00:00
$options = array_merge ( array ( 'atomic' => true , 'deep' => false ), $options );
2011-07-25 07:39:03 +00:00
$this -> validationErrors = $validationErrors = $return = array ();
foreach ( $data as $key => $record ) {
2012-02-13 00:00:28 +00:00
if ( $options [ 'deep' ]) {
$validates = $this -> validateAssociated ( $record , $options );
} else {
$validates = $this -> create ( $record ) && $this -> validates ( $options );
}
if ( $validates === false || ( is_array ( $validates ) && in_array ( false , $validates , true ))) {
2011-07-25 07:39:03 +00:00
$validationErrors [ $key ] = $this -> validationErrors ;
2012-02-13 00:00:28 +00:00
$validates = false ;
} else {
$validates = true ;
2011-07-25 07:39:03 +00:00
}
2012-02-13 00:00:28 +00:00
$return [ $key ] = $validates ;
2011-07-25 07:39:03 +00:00
}
$this -> validationErrors = $validationErrors ;
if ( ! $options [ 'atomic' ]) {
return $return ;
}
if ( empty ( $this -> validationErrors )) {
return true ;
}
return false ;
}
2008-09-19 15:27:43 +00:00
2011-07-25 07:39:03 +00:00
/**
* Saves a single record , as well as all its directly associated records .
*
* #### Options
*
2012-01-20 10:02:13 +00:00
* - `validate` Set to `false` to disable validation , `true` to validate each record before saving ,
* 'first' to validate * all * records before any are saved ( default ),
2012-01-20 02:10:46 +00:00
* - `atomic` If true ( default ), will attempt to save all records in a single transaction .
2011-07-25 07:39:03 +00:00
* Should be set to false if database / table does not support transactions .
2012-02-12 16:38:03 +00:00
* - fieldList : Equivalent to the $fieldList parameter in Model :: save () .
* It should be an associate array with model name as key and array of fields as value . Eg .
* {{{
* array (
* 'SomeModel' => array ( 'field' ),
* 'AssociatedModel' => array ( 'field' , 'otherfield' )
* )
* }}}
2012-02-13 00:00:28 +00:00
* - deep : If set to true , not only directly associated data is saved , but deeper nested associated data as well .
2011-07-25 07:39:03 +00:00
*
* @ param array $data Record data to save . This should be an array indexed by association name .
* @ param array $options Options to use when saving record data , See $options above .
* @ return mixed If atomic : True on success , or false on failure .
* Otherwise : array similar to the $data array passed , but values are set to true / false
* depending on whether each record saved successfully .
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-saveassociated-array-data-null-array-options-array
2011-07-25 07:39:03 +00:00
*/
public function saveAssociated ( $data = null , $options = array ()) {
if ( empty ( $data )) {
$data = $this -> data ;
}
2008-05-30 11:40:08 +00:00
2012-02-13 00:00:28 +00:00
$options = array_merge ( array ( 'validate' => 'first' , 'atomic' => true , 'deep' => false ), $options );
2011-07-25 07:39:03 +00:00
$this -> validationErrors = $validationErrors = array ();
if ( empty ( $data ) && $options [ 'validate' ] !== false ) {
$result = $this -> save ( $data , $options );
2012-04-16 20:46:58 +00:00
if ( ! $options [ 'atomic' ]) {
return array ( ! empty ( $result ));
}
2011-07-25 07:39:03 +00:00
return ! empty ( $result );
}
if ( $options [ 'validate' ] === 'first' ) {
$validates = $this -> validateAssociated ( $data , $options );
if (( ! $validates && $options [ 'atomic' ]) || ( ! $options [ 'atomic' ] && in_array ( false , $validates , true ))) {
return $validates ;
2010-06-09 17:48:54 +00:00
}
2012-04-16 07:45:44 +00:00
$options [ 'validate' ] = false ;
2011-07-25 07:39:03 +00:00
}
if ( $options [ 'atomic' ]) {
$db = $this -> getDataSource ();
2012-01-17 20:52:22 +00:00
$transactionBegun = $db -> begin ();
2008-05-30 11:40:08 +00:00
}
$associations = $this -> getAssociated ();
2011-07-25 07:39:03 +00:00
$return = array ();
$validates = true ;
foreach ( $data as $association => $values ) {
2012-04-16 22:22:13 +00:00
$notEmpty = ! empty ( $values [ $association ]) || ( ! isset ( $values [ $association ]) && ! empty ( $values ));
if ( isset ( $associations [ $association ]) && $associations [ $association ] === 'belongsTo' && $notEmpty ) {
2012-02-13 00:00:28 +00:00
$validates = $this -> { $association } -> create ( null ) !== null ;
$saved = false ;
if ( $validates ) {
if ( $options [ 'deep' ]) {
$saved = $this -> { $association } -> saveAssociated ( $values , array_merge ( $options , array ( 'atomic' => false )));
} else {
$saved = $this -> { $association } -> save ( $values , array_merge ( $options , array ( 'atomic' => false )));
}
$validates = ( $saved === true || ( is_array ( $saved ) && ! in_array ( false , $saved , true )));
}
if ( $validates ) {
2012-03-21 09:38:04 +00:00
$key = $this -> belongsTo [ $association ][ 'foreignKey' ];
if ( isset ( $data [ $this -> alias ])) {
$data [ $this -> alias ][ $key ] = $this -> { $association } -> id ;
2012-02-13 00:00:28 +00:00
} else {
2012-03-21 09:38:04 +00:00
$data = array_merge ( array ( $key => $this -> { $association } -> id ), $data , array ( $key => $this -> { $association } -> id ));
2012-02-13 00:00:28 +00:00
}
2011-07-25 07:39:03 +00:00
} else {
$validationErrors [ $association ] = $this -> { $association } -> validationErrors ;
2008-05-30 11:40:08 +00:00
}
2012-02-13 00:00:28 +00:00
$return [ $association ] = $validates ;
2008-05-30 11:40:08 +00:00
}
2011-07-25 07:39:03 +00:00
}
if ( $validates && ! ( $this -> create ( null ) !== null && $this -> save ( $data , $options ))) {
$validationErrors [ $this -> alias ] = $this -> validationErrors ;
$validates = false ;
}
$return [ $this -> alias ] = $validates ;
2010-09-29 03:37:28 +00:00
2011-07-25 07:39:03 +00:00
foreach ( $data as $association => $values ) {
if ( ! $validates ) {
break ;
2008-05-30 11:40:08 +00:00
}
2012-04-16 22:22:13 +00:00
$notEmpty = ! empty ( $values [ $association ]) || ( ! isset ( $values [ $association ]) && ! empty ( $values ));
if ( isset ( $associations [ $association ]) && $notEmpty ) {
2011-07-25 07:39:03 +00:00
$type = $associations [ $association ];
2012-03-21 09:38:04 +00:00
$key = $this -> { $type }[ $association ][ 'foreignKey' ];
2011-07-25 07:39:03 +00:00
switch ( $type ) {
case 'hasOne' :
2012-03-21 09:38:04 +00:00
if ( isset ( $values [ $association ])) {
$values [ $association ][ $key ] = $this -> id ;
} else {
$values = array_merge ( array ( $key => $this -> id ), $values , array ( $key => $this -> id ));
}
2012-02-13 00:00:28 +00:00
$validates = $this -> { $association } -> create ( null ) !== null ;
$saved = false ;
if ( $validates ) {
if ( $options [ 'deep' ]) {
$saved = $this -> { $association } -> saveAssociated ( $values , array_merge ( $options , array ( 'atomic' => false )));
} else {
$saved = $this -> { $association } -> save ( $values , $options );
}
}
$validates = ( $validates && ( $saved === true || ( is_array ( $saved ) && ! in_array ( false , $saved , true ))));
if ( ! $validates ) {
2011-07-25 07:39:03 +00:00
$validationErrors [ $association ] = $this -> { $association } -> validationErrors ;
}
2012-02-13 00:00:28 +00:00
$return [ $association ] = $validates ;
2011-07-25 07:39:03 +00:00
break ;
case 'hasMany' :
foreach ( $values as $i => $value ) {
2012-03-21 09:38:04 +00:00
if ( isset ( $values [ $i ][ $association ])) {
$values [ $i ][ $association ][ $key ] = $this -> id ;
} else {
$values [ $i ] = array_merge ( array ( $key => $this -> id ), $value , array ( $key => $this -> id ));
}
2011-07-25 07:39:03 +00:00
}
$_return = $this -> { $association } -> saveMany ( $values , array_merge ( $options , array ( 'atomic' => false )));
if ( in_array ( false , $_return , true )) {
$validationErrors [ $association ] = $this -> { $association } -> validationErrors ;
$validates = false ;
}
$return [ $association ] = $_return ;
2008-05-30 11:40:08 +00:00
break ;
}
}
2011-07-25 07:39:03 +00:00
}
$this -> validationErrors = $validationErrors ;
2008-06-27 06:07:00 +00:00
2011-07-25 07:39:03 +00:00
if ( isset ( $validationErrors [ $this -> alias ])) {
$this -> validationErrors = $validationErrors [ $this -> alias ];
}
2008-05-30 11:40:08 +00:00
2011-07-25 07:39:03 +00:00
if ( ! $options [ 'atomic' ]) {
return $return ;
}
if ( $validates ) {
if ( $transactionBegun ) {
2012-01-17 20:52:22 +00:00
return $db -> commit () !== false ;
2011-07-25 07:39:03 +00:00
} else {
return true ;
2010-09-29 03:37:28 +00:00
}
2008-05-30 11:40:08 +00:00
}
2012-01-17 20:52:22 +00:00
$db -> rollback ();
2011-07-25 07:39:03 +00:00
return false ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2011-07-25 07:39:03 +00:00
* Validates a single record , as well as all its directly associated records .
2008-05-30 11:40:08 +00:00
*
2011-07-25 07:39:03 +00:00
* #### Options
*
* - atomic : If true ( default ), returns boolean . If false returns array .
* - fieldList : Equivalent to the $fieldList parameter in Model :: save ()
2012-02-13 00:00:28 +00:00
* - deep : If set to true , not only directly associated data , but deeper nested associated data is validated as well .
2011-07-25 07:39:03 +00:00
*
* @ param array $data Record data to validate . This should be an array indexed by association name .
2011-07-30 22:38:57 +00:00
* @ param array $options Options to use when validating record data ( see above ), See also $options of validates () .
* @ return array | boolean If atomic : True on success , or false on failure .
2011-07-25 07:39:03 +00:00
* Otherwise : array similar to the $data array passed , but values are set to true / false
* depending on whether each record validated successfully .
2008-05-30 11:40:08 +00:00
*/
2011-07-25 07:39:03 +00:00
public function validateAssociated ( $data , $options = array ()) {
2012-02-13 00:00:28 +00:00
$options = array_merge ( array ( 'atomic' => true , 'deep' => false ), $options );
2011-07-25 07:39:03 +00:00
$this -> validationErrors = $validationErrors = $return = array ();
if ( ! ( $this -> create ( $data ) && $this -> validates ( $options ))) {
$validationErrors [ $this -> alias ] = $this -> validationErrors ;
$return [ $this -> alias ] = false ;
} else {
$return [ $this -> alias ] = true ;
}
$associations = $this -> getAssociated ();
foreach ( $data as $association => $values ) {
2012-02-13 00:00:28 +00:00
$validates = true ;
2011-07-25 07:39:03 +00:00
if ( isset ( $associations [ $association ])) {
if ( in_array ( $associations [ $association ], array ( 'belongsTo' , 'hasOne' ))) {
2012-02-13 00:00:28 +00:00
if ( $options [ 'deep' ]) {
$validates = $this -> { $association } -> validateAssociated ( $values , $options );
} else {
$validates = $this -> { $association } -> create ( $values ) !== null && $this -> { $association } -> validates ( $options );
}
if ( is_array ( $validates )) {
if ( in_array ( false , $validates , true )) {
$validates = false ;
} else {
$validates = true ;
}
}
$return [ $association ] = $validates ;
2011-11-30 15:44:11 +00:00
} elseif ( $associations [ $association ] === 'hasMany' ) {
2011-07-25 07:39:03 +00:00
$validates = $this -> { $association } -> validateMany ( $values , $options );
$return [ $association ] = $validates ;
}
if ( ! $validates || ( is_array ( $validates ) && in_array ( false , $validates , true ))) {
$validationErrors [ $association ] = $this -> { $association } -> validationErrors ;
}
2008-05-30 11:40:08 +00:00
}
2011-07-25 07:39:03 +00:00
}
$this -> validationErrors = $validationErrors ;
if ( isset ( $validationErrors [ $this -> alias ])) {
$this -> validationErrors = $validationErrors [ $this -> alias ];
}
if ( ! $options [ 'atomic' ]) {
return $return ;
}
2011-07-26 14:35:16 +00:00
if ( $return [ $this -> alias ] === false || ! empty ( $this -> validationErrors )) {
2008-05-30 11:40:08 +00:00
return false ;
}
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Updates multiple model records based on a set of conditions .
2008-05-30 11:40:08 +00:00
*
2008-07-31 15:38:23 +00:00
* @ param array $fields Set of fields and values , indexed by fields .
2009-09-03 15:59:57 +00:00
* Fields are treated as SQL snippets , to insert literal values manually escape your data .
2008-05-30 11:40:08 +00:00
* @ param mixed $conditions Conditions to match , true for all records
* @ return boolean True on success , false on failure
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / saving - your - data . html #model-updateall-array-fields-array-conditions
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function updateAll ( $fields , $conditions = true ) {
2010-07-15 03:49:38 +00:00
return $this -> getDataSource () -> update ( $this , $fields , null , $conditions );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Removes record for given ID . If no ID is given , the current ID is used . Returns true on success .
2008-05-30 11:40:08 +00:00
*
* @ param mixed $id ID of record to delete
* @ param boolean $cascade Set to true to delete records that depend on this record
* @ return boolean True on success
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / deleting - data . html
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function delete ( $id = null , $cascade = true ) {
2008-05-30 11:40:08 +00:00
if ( ! empty ( $id )) {
$this -> id = $id ;
}
$id = $this -> id ;
2011-12-26 17:36:48 +00:00
$event = new CakeEvent ( 'Model.beforeDelete' , $this , array ( $cascade ));
list ( $event -> break , $event -> breakOn ) = array ( true , array ( false , null ));
$this -> getEventManager () -> dispatch ( $event );
if ( ! $event -> isStopped ()) {
if ( ! $this -> exists ()) {
2008-05-30 11:40:08 +00:00
return false ;
}
2011-02-23 05:19:37 +00:00
$db = $this -> getDataSource ();
2010-09-30 03:31:41 +00:00
2008-05-30 11:40:08 +00:00
$this -> _deleteDependent ( $id , $cascade );
$this -> _deleteLinks ( $id );
$this -> id = $id ;
2011-08-03 22:10:43 +00:00
$updateCounterCache = false ;
2008-05-30 11:40:08 +00:00
if ( ! empty ( $this -> belongsTo )) {
2011-08-03 22:10:43 +00:00
foreach ( $this -> belongsTo as $parent => $assoc ) {
if ( ! empty ( $assoc [ 'counterCache' ])) {
$updateCounterCache = true ;
break ;
}
}
2010-03-13 05:18:51 +00:00
$keys = $this -> find ( 'first' , array (
2011-08-20 04:43:34 +00:00
'fields' => $this -> _collectForeignKeys (),
2011-08-03 22:10:43 +00:00
'conditions' => array ( $this -> alias . '.' . $this -> primaryKey => $id ),
'recursive' => - 1 ,
'callbacks' => false
2010-03-13 05:18:51 +00:00
));
2008-05-30 11:40:08 +00:00
}
2010-11-09 02:50:45 +00:00
if ( $db -> delete ( $this , array ( $this -> alias . '.' . $this -> primaryKey => $id ))) {
2011-08-03 22:10:43 +00:00
if ( $updateCounterCache ) {
2008-05-30 11:40:08 +00:00
$this -> updateCounterCache ( $keys [ $this -> alias ]);
}
2011-12-26 17:36:48 +00:00
$this -> getEventManager () -> dispatch ( new CakeEvent ( 'Model.afterDelete' , $this ));
2008-05-30 11:40:08 +00:00
$this -> _clearCache ();
$this -> id = false ;
return true ;
}
}
return false ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Cascades model deletes through associated hasMany and hasOne child records .
2008-05-30 11:40:08 +00:00
*
* @ param string $id ID of record that was deleted
* @ param boolean $cascade Set to true to delete records that depend on this record
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:21:28 +00:00
protected function _deleteDependent ( $id , $cascade ) {
2008-05-30 11:40:08 +00:00
if ( ! empty ( $this -> __backAssociation )) {
$savedAssociatons = $this -> __backAssociation ;
$this -> __backAssociation = array ();
}
2011-11-05 20:15:57 +00:00
if ( $cascade === true ) {
foreach ( array_merge ( $this -> hasMany , $this -> hasOne ) as $assoc => $data ) {
if ( $data [ 'dependent' ] === true ) {
$model = $this -> { $assoc };
2011-11-30 19:02:36 +00:00
if ( $data [ 'foreignKey' ] === false && $data [ 'conditions' ] && in_array ( $this -> name , $model -> getAssociated ( 'belongsTo' ))) {
$model -> recursive = 0 ;
$conditions = array ( $this -> escapeField ( null , $this -> name ) => $id );
} else {
$model -> recursive = - 1 ;
$conditions = array ( $model -> escapeField ( $data [ 'foreignKey' ]) => $id );
if ( $data [ 'conditions' ]) {
$conditions = array_merge (( array ) $data [ 'conditions' ], $conditions );
}
2011-11-05 20:15:57 +00:00
}
2008-05-30 11:40:08 +00:00
2011-11-05 20:15:57 +00:00
if ( isset ( $data [ 'exclusive' ]) && $data [ 'exclusive' ]) {
$model -> deleteAll ( $conditions );
} else {
$records = $model -> find ( 'all' , array (
'conditions' => $conditions , 'fields' => $model -> primaryKey
));
if ( ! empty ( $records )) {
foreach ( $records as $record ) {
$model -> delete ( $record [ $model -> alias ][ $model -> primaryKey ]);
}
2008-05-30 11:40:08 +00:00
}
}
}
}
}
if ( isset ( $savedAssociatons )) {
$this -> __backAssociation = $savedAssociatons ;
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Cascades model deletes through HABTM join keys .
2008-05-30 11:40:08 +00:00
*
* @ param string $id ID of record that was deleted
2008-09-25 16:49:56 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:21:28 +00:00
protected function _deleteLinks ( $id ) {
2008-05-30 11:40:08 +00:00
foreach ( $this -> hasAndBelongsToMany as $assoc => $data ) {
2011-03-19 12:45:10 +00:00
list ( $plugin , $joinModel ) = pluginSplit ( $data [ 'with' ]);
2010-01-29 16:55:18 +00:00
$records = $this -> { $joinModel } -> find ( 'all' , array (
2011-10-07 13:03:05 +00:00
'conditions' => array ( $this -> { $joinModel } -> escapeField ( $data [ 'foreignKey' ]) => $id ),
2010-01-29 16:55:18 +00:00
'fields' => $this -> { $joinModel } -> primaryKey ,
2011-08-03 22:10:43 +00:00
'recursive' => - 1 ,
'callbacks' => false
2008-05-30 11:40:08 +00:00
));
if ( ! empty ( $records )) {
foreach ( $records as $record ) {
2010-01-29 16:55:18 +00:00
$this -> { $joinModel } -> delete ( $record [ $this -> { $joinModel } -> alias ][ $this -> { $joinModel } -> primaryKey ]);
2008-05-30 11:40:08 +00:00
}
}
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Deletes multiple model records based on a set of conditions .
2008-05-30 11:40:08 +00:00
*
* @ param mixed $conditions Conditions to match
* @ param boolean $cascade Set to true to delete records that depend on this record
2010-04-16 11:45:44 +00:00
* @ param boolean $callbacks Run callbacks
2008-05-30 11:40:08 +00:00
* @ return boolean True on success , false on failure
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / deleting - data . html #deleteall
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function deleteAll ( $conditions , $cascade = true , $callbacks = false ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $conditions )) {
return false ;
}
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2008-05-30 11:40:08 +00:00
if ( ! $cascade && ! $callbacks ) {
return $db -> delete ( $this , $conditions );
} else {
2010-04-24 21:04:18 +00:00
$ids = $this -> find ( 'all' , array_merge ( array (
'fields' => " { $this -> alias } . { $this -> primaryKey } " ,
'recursive' => 0 ), compact ( 'conditions' ))
2008-05-30 11:40:08 +00:00
);
2010-04-24 21:04:18 +00:00
if ( $ids === false ) {
return false ;
}
2008-05-30 11:40:08 +00:00
2010-04-24 21:04:18 +00:00
$ids = Set :: extract ( $ids , " { n}. { $this -> alias } . { $this -> primaryKey } " );
2008-05-30 11:40:08 +00:00
if ( empty ( $ids )) {
2009-07-03 00:26:58 +00:00
return true ;
2008-05-30 11:40:08 +00:00
}
if ( $callbacks ) {
$_id = $this -> id ;
2008-10-22 02:37:05 +00:00
$result = true ;
2008-05-30 11:40:08 +00:00
foreach ( $ids as $id ) {
2008-10-22 02:37:05 +00:00
$result = ( $result && $this -> delete ( $id , $cascade ));
2008-05-30 11:40:08 +00:00
}
$this -> id = $_id ;
2008-10-22 02:37:05 +00:00
return $result ;
2008-05-30 11:40:08 +00:00
} else {
foreach ( $ids as $id ) {
$this -> _deleteLinks ( $id );
if ( $cascade ) {
$this -> _deleteDependent ( $id , $cascade );
}
}
return $db -> delete ( $this , array ( $this -> alias . '.' . $this -> primaryKey => $ids ));
}
}
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Collects foreign keys from associations .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param string $type
2008-09-25 16:49:56 +00:00
* @ return array
2008-05-30 11:40:08 +00:00
*/
2011-08-20 04:43:34 +00:00
protected function _collectForeignKeys ( $type = 'belongsTo' ) {
2008-05-30 11:40:08 +00:00
$result = array ();
foreach ( $this -> { $type } as $assoc => $data ) {
if ( isset ( $data [ 'foreignKey' ]) && is_string ( $data [ 'foreignKey' ])) {
$result [ $assoc ] = $data [ 'foreignKey' ];
}
}
return $result ;
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2012-02-23 06:12:08 +00:00
* Returns true if a record with particular ID exists .
2008-05-30 11:40:08 +00:00
*
2012-02-23 06:12:08 +00:00
* If $id is not passed it calls Model :: getID () to obtain the current record ID ,
2010-01-14 21:42:16 +00:00
* and then performs a Model :: find ( 'count' ) on the currently configured datasource
* to ascertain the existence of the record in persistent storage .
*
2012-02-23 06:12:08 +00:00
* @ param mixed $id ID of record to check for existence
2008-05-30 11:40:08 +00:00
* @ return boolean True if such a record exists
*/
2012-02-23 06:12:08 +00:00
public function exists ( $id = null ) {
if ( $id === null ) {
$id = $this -> getID ();
}
if ( $id === false ) {
2008-05-30 11:40:08 +00:00
return false ;
}
2012-02-23 06:12:08 +00:00
$conditions = array ( $this -> alias . '.' . $this -> primaryKey => $id );
2008-06-21 02:33:04 +00:00
$query = array ( 'conditions' => $conditions , 'recursive' => - 1 , 'callbacks' => false );
2010-01-14 18:47:38 +00:00
return ( $this -> find ( 'count' , $query ) > 0 );
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns true if a record that meets given conditions exists .
2008-05-30 11:40:08 +00:00
*
* @ param array $conditions SQL conditions array
* @ return boolean True if such a record exists
*/
2010-04-05 03:19:38 +00:00
public function hasAny ( $conditions = null ) {
2008-05-30 11:40:08 +00:00
return ( $this -> find ( 'count' , array ( 'conditions' => $conditions , 'recursive' => - 1 )) != false );
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2010-07-28 01:25:31 +00:00
* Queries the datasource and returns a result set array .
2008-05-30 11:40:08 +00:00
*
2011-02-23 02:45:27 +00:00
* Also used to perform notation finds , where the first argument is type of find operation to perform
2011-12-16 06:52:07 +00:00
* ( all / first / count / neighbors / list / threaded ),
2008-10-03 18:06:15 +00:00
* second parameter options for finding ( indexed array , including : 'conditions' , 'limit' ,
2008-05-30 11:40:08 +00:00
* 'recursive' , 'page' , 'fields' , 'offset' , 'order' )
*
2009-11-12 04:17:23 +00:00
* Eg :
2009-10-06 01:01:31 +00:00
* {{{
2010-07-28 01:25:31 +00:00
* find ( 'all' , array (
* 'conditions' => array ( 'name' => 'Thomas Anderson' ),
2009-10-06 01:01:31 +00:00
* 'fields' => array ( 'name' , 'email' ),
* 'order' => 'field3 DESC' ,
* 'recursive' => 2 ,
* 'group' => 'type'
* ));
* }}}
2008-05-30 11:40:08 +00:00
*
2010-07-28 01:25:31 +00:00
* In addition to the standard query keys above , you can provide Datasource , and behavior specific
* keys . For example , when using a SQL based datasource you can use the joins key to specify additional
* joins that should be part of the query .
*
* {{{
* find ( 'all' , array (
* 'conditions' => array ( 'name' => 'Thomas Anderson' ),
* 'joins' => array (
2010-09-25 02:23:24 +00:00
* array (
* 'alias' => 'Thought' ,
* 'table' => 'thoughts' ,
* 'type' => 'LEFT' ,
* 'conditions' => '`Thought`.`person_id` = `Person`.`id`'
* )
2010-07-28 01:25:31 +00:00
* )
* ));
* }}}
*
* Behaviors and find types can also define custom finder keys which are passed into find () .
*
2011-02-23 02:45:27 +00:00
* Specifying 'fields' for notation 'list' :
2009-10-06 01:01:31 +00:00
*
2008-05-30 11:40:08 +00:00
* - If no fields are specified , then 'id' is used for key and 'model->displayField' is used for value .
* - If a single field is specified , 'id' is used for key and specified field is used for value .
* - If three fields are specified , they are used ( in order ) for key , value and group .
* - Otherwise , first and second fields are used for key and value .
*
2011-09-27 21:28:48 +00:00
* Note : find ( list ) + database views have issues with MySQL 5.0 . Try upgrading to MySQL 5.1 if you
2011-09-06 12:00:08 +00:00
* have issues with database views .
2011-02-23 02:45:27 +00:00
* @ param string $type Type of find operation ( all / first / count / neighbors / list / threaded )
2011-07-12 21:31:07 +00:00
* @ param array $query Option fields ( conditions / fields / joins / limit / offset / order / page / group / callbacks )
2008-05-30 11:40:08 +00:00
* @ return array Array of records
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / deleting - data . html #deleteall
2008-05-30 11:40:08 +00:00
*/
2011-02-23 02:45:27 +00:00
public function find ( $type = 'first' , $query = array ()) {
2008-05-30 11:40:08 +00:00
$this -> findQueryType = $type ;
$this -> id = $this -> getID ();
2011-07-12 21:31:07 +00:00
$query = $this -> buildQuery ( $type , $query );
if ( is_null ( $query )) {
return null ;
}
$results = $this -> getDataSource () -> read ( $this , $query );
$this -> resetAssociations ();
if ( $query [ 'callbacks' ] === true || $query [ 'callbacks' ] === 'after' ) {
$results = $this -> _filterResults ( $results );
}
$this -> findQueryType = null ;
if ( $type === 'all' ) {
return $results ;
} else {
if ( $this -> findMethods [ $type ] === true ) {
return $this -> { '_find' . ucfirst ( $type )}( 'after' , $query , $results );
}
}
}
/**
* Builds the query array that is used by the data source to generate the query to fetch the data .
*
* @ param string $type Type of find operation ( all / first / count / neighbors / list / threaded )
* @ param array $query Option fields ( conditions / fields / joins / limit / offset / order / page / group / callbacks )
* @ return array Query array or null if it could not be build for some reasons
* @ see Model :: find ()
*/
public function buildQuery ( $type = 'first' , $query = array ()) {
2008-05-30 11:40:08 +00:00
$query = array_merge (
array (
2008-06-21 02:33:04 +00:00
'conditions' => null , 'fields' => null , 'joins' => array (), 'limit' => null ,
2011-07-11 22:54:24 +00:00
'offset' => null , 'order' => null , 'page' => 1 , 'group' => null , 'callbacks' => true ,
2008-05-30 11:40:08 +00:00
),
2008-06-19 17:06:50 +00:00
( array ) $query
2008-05-30 11:40:08 +00:00
);
2011-02-23 02:47:27 +00:00
if ( $type !== 'all' ) {
2011-04-17 00:39:00 +00:00
if ( $this -> findMethods [ $type ] === true ) {
2008-05-30 11:40:08 +00:00
$query = $this -> { '_find' . ucfirst ( $type )}( 'before' , $query );
}
}
if ( ! is_numeric ( $query [ 'page' ]) || intval ( $query [ 'page' ]) < 1 ) {
$query [ 'page' ] = 1 ;
}
if ( $query [ 'page' ] > 1 && ! empty ( $query [ 'limit' ])) {
$query [ 'offset' ] = ( $query [ 'page' ] - 1 ) * $query [ 'limit' ];
}
if ( $query [ 'order' ] === null && $this -> order !== null ) {
$query [ 'order' ] = $this -> order ;
}
$query [ 'order' ] = array ( $query [ 'order' ]);
2008-06-21 02:33:04 +00:00
if ( $query [ 'callbacks' ] === true || $query [ 'callbacks' ] === 'before' ) {
2011-12-26 17:36:48 +00:00
$event = new CakeEvent ( 'Model.beforeFind' , $this , array ( $query ));
list ( $event -> break , $event -> breakOn , $event -> modParams ) = array ( true , array ( false , null ), 0 );
$this -> getEventManager () -> dispatch ( $event );
if ( $event -> isStopped ()) {
2008-06-21 02:33:04 +00:00
return null ;
}
2011-12-26 18:08:04 +00:00
$query = $event -> result === true ? $event -> data [ 0 ] : $event -> result ;
2008-05-30 11:40:08 +00:00
}
2011-07-31 01:03:56 +00:00
2011-07-12 21:31:07 +00:00
return $query ;
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
* Handles the before / after filter logic for find ( 'first' ) operations . Only called by Model :: find () .
*
* @ param string $state Either " before " or " after "
* @ param array $query
2011-07-30 22:38:57 +00:00
* @ param array $results
2008-05-30 11:40:08 +00:00
* @ return array
2008-10-31 19:05:30 +00:00
* @ see Model :: find ()
2008-05-30 11:40:08 +00:00
*/
2011-02-23 02:42:15 +00:00
protected function _findFirst ( $state , $query , $results = array ()) {
2011-02-23 02:47:27 +00:00
if ( $state === 'before' ) {
2008-05-30 11:40:08 +00:00
$query [ 'limit' ] = 1 ;
return $query ;
2011-02-23 02:47:27 +00:00
} elseif ( $state === 'after' ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $results [ 0 ])) {
return false ;
}
return $results [ 0 ];
}
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
* Handles the before / after filter logic for find ( 'count' ) operations . Only called by Model :: find () .
*
* @ param string $state Either " before " or " after "
* @ param array $query
2011-07-30 22:38:57 +00:00
* @ param array $results
2011-08-01 02:57:17 +00:00
* @ return integer The number of records found , or false
2008-10-31 19:05:30 +00:00
* @ see Model :: find ()
2008-05-30 11:40:08 +00:00
*/
2011-02-23 02:42:15 +00:00
protected function _findCount ( $state , $query , $results = array ()) {
2011-02-23 02:47:27 +00:00
if ( $state === 'before' ) {
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2012-02-05 17:54:20 +00:00
$query [ 'order' ] = false ;
2012-04-05 21:15:18 +00:00
if ( ! method_exists ( $db , 'calculate' )) {
2012-02-05 17:54:20 +00:00
return $query ;
}
2008-05-30 11:40:08 +00:00
if ( empty ( $query [ 'fields' ])) {
$query [ 'fields' ] = $db -> calculate ( $this , 'count' );
2012-04-05 21:15:18 +00:00
} elseif ( method_exists ( $db , 'expression' ) && is_string ( $query [ 'fields' ]) && ! preg_match ( '/count/i' , $query [ 'fields' ])) {
2008-10-01 15:27:29 +00:00
$query [ 'fields' ] = $db -> calculate ( $this , 'count' , array (
$db -> expression ( $query [ 'fields' ]), 'count'
));
2008-05-30 11:40:08 +00:00
}
return $query ;
2011-02-23 02:47:27 +00:00
} elseif ( $state === 'after' ) {
2011-08-14 01:59:21 +00:00
foreach ( array ( 0 , $this -> alias ) as $key ) {
if ( isset ( $results [ 0 ][ $key ][ 'count' ])) {
2011-09-27 21:28:48 +00:00
if (( $count = count ( $results )) > 1 ) {
return $count ;
2011-08-14 01:59:21 +00:00
} else {
return intval ( $results [ 0 ][ $key ][ 'count' ]);
}
}
2008-05-30 11:40:08 +00:00
}
return false ;
}
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
* Handles the before / after filter logic for find ( 'list' ) operations . Only called by Model :: find () .
*
* @ param string $state Either " before " or " after "
* @ param array $query
2011-07-30 22:38:57 +00:00
* @ param array $results
2008-05-30 11:40:08 +00:00
* @ return array Key / value pairs of primary keys / display field values of all records found
2008-10-31 19:05:30 +00:00
* @ see Model :: find ()
2008-05-30 11:40:08 +00:00
*/
2011-02-23 02:42:15 +00:00
protected function _findList ( $state , $query , $results = array ()) {
2011-02-23 02:47:27 +00:00
if ( $state === 'before' ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $query [ 'fields' ])) {
$query [ 'fields' ] = array ( " { $this -> alias } . { $this -> primaryKey } " , " { $this -> alias } . { $this -> displayField } " );
$list = array ( " { n}. { $this -> alias } . { $this -> primaryKey } " , " { n}. { $this -> alias } . { $this -> displayField } " , null );
} else {
if ( ! is_array ( $query [ 'fields' ])) {
$query [ 'fields' ] = String :: tokenize ( $query [ 'fields' ]);
}
2008-06-10 17:27:12 +00:00
2011-02-23 02:47:27 +00:00
if ( count ( $query [ 'fields' ]) === 1 ) {
2008-06-10 17:27:12 +00:00
if ( strpos ( $query [ 'fields' ][ 0 ], '.' ) === false ) {
$query [ 'fields' ][ 0 ] = $this -> alias . '.' . $query [ 'fields' ][ 0 ];
}
2008-05-30 11:40:08 +00:00
$list = array ( " { n}. { $this -> alias } . { $this -> primaryKey } " , '{n}.' . $query [ 'fields' ][ 0 ], null );
$query [ 'fields' ] = array ( " { $this -> alias } . { $this -> primaryKey } " , $query [ 'fields' ][ 0 ]);
2011-02-23 02:47:27 +00:00
} elseif ( count ( $query [ 'fields' ]) === 3 ) {
2008-06-11 08:54:27 +00:00
for ( $i = 0 ; $i < 3 ; $i ++ ) {
2008-06-10 17:27:12 +00:00
if ( strpos ( $query [ 'fields' ][ $i ], '.' ) === false ) {
$query [ 'fields' ][ $i ] = $this -> alias . '.' . $query [ 'fields' ][ $i ];
}
}
2008-05-30 11:40:08 +00:00
$list = array ( '{n}.' . $query [ 'fields' ][ 0 ], '{n}.' . $query [ 'fields' ][ 1 ], '{n}.' . $query [ 'fields' ][ 2 ]);
} else {
2008-06-11 08:54:27 +00:00
for ( $i = 0 ; $i < 2 ; $i ++ ) {
2008-06-10 17:27:12 +00:00
if ( strpos ( $query [ 'fields' ][ $i ], '.' ) === false ) {
$query [ 'fields' ][ $i ] = $this -> alias . '.' . $query [ 'fields' ][ $i ];
}
}
2008-05-30 11:40:08 +00:00
$list = array ( '{n}.' . $query [ 'fields' ][ 0 ], '{n}.' . $query [ 'fields' ][ 1 ], null );
}
}
if ( ! isset ( $query [ 'recursive' ]) || $query [ 'recursive' ] === null ) {
$query [ 'recursive' ] = - 1 ;
}
list ( $query [ 'list' ][ 'keyPath' ], $query [ 'list' ][ 'valuePath' ], $query [ 'list' ][ 'groupPath' ]) = $list ;
return $query ;
2011-02-23 02:47:27 +00:00
} elseif ( $state === 'after' ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $results )) {
return array ();
}
2008-09-04 01:00:08 +00:00
$lst = $query [ 'list' ];
return Set :: combine ( $results , $lst [ 'keyPath' ], $lst [ 'valuePath' ], $lst [ 'groupPath' ]);
2008-05-30 11:40:08 +00:00
}
}
2009-05-01 21:05:46 +00:00
2008-06-26 19:33:44 +00:00
/**
2008-10-31 19:05:30 +00:00
* Detects the previous field 's value, then uses logic to find the ' wrapping '
* rows and return them .
2008-06-26 19:42:07 +00:00
*
2008-06-26 19:33:44 +00:00
* @ param string $state Either " before " or " after "
2008-06-26 19:42:07 +00:00
* @ param mixed $query
* @ param array $results
2008-09-25 16:49:56 +00:00
* @ return array
2008-06-26 19:33:44 +00:00
*/
2010-04-05 03:21:28 +00:00
protected function _findNeighbors ( $state , $query , $results = array ()) {
2011-02-23 02:47:27 +00:00
if ( $state === 'before' ) {
2008-06-26 19:33:44 +00:00
extract ( $query );
$conditions = ( array ) $conditions ;
if ( isset ( $field ) && isset ( $value )) {
if ( strpos ( $field , '.' ) === false ) {
2008-06-26 19:42:07 +00:00
$field = $this -> alias . '.' . $field ;
}
2008-06-26 19:33:44 +00:00
} else {
$field = $this -> alias . '.' . $this -> primaryKey ;
$value = $this -> id ;
}
2012-03-05 03:49:38 +00:00
$query [ 'conditions' ] = array_merge ( $conditions , array ( $field . ' <' => $value ));
2008-06-26 19:33:44 +00:00
$query [ 'order' ] = $field . ' DESC' ;
$query [ 'limit' ] = 1 ;
$query [ 'field' ] = $field ;
$query [ 'value' ] = $value ;
2008-06-26 19:42:07 +00:00
return $query ;
2011-02-23 02:47:27 +00:00
} elseif ( $state === 'after' ) {
2008-06-26 19:33:44 +00:00
extract ( $query );
unset ( $query [ 'conditions' ][ $field . ' <' ]);
2008-06-26 19:42:07 +00:00
$return = array ();
if ( isset ( $results [ 0 ])) {
2008-06-26 19:33:44 +00:00
$prevVal = Set :: extract ( '/' . str_replace ( '.' , '/' , $field ), $results [ 0 ]);
$query [ 'conditions' ][ $field . ' >=' ] = $prevVal [ 0 ];
$query [ 'conditions' ][ $field . ' !=' ] = $value ;
$query [ 'limit' ] = 2 ;
} else {
$return [ 'prev' ] = null ;
$query [ 'conditions' ][ $field . ' >' ] = $value ;
$query [ 'limit' ] = 1 ;
2008-06-26 19:42:07 +00:00
}
2008-06-26 19:33:44 +00:00
$query [ 'order' ] = $field . ' ASC' ;
$return2 = $this -> find ( 'all' , $query );
if ( ! array_key_exists ( 'prev' , $return )) {
2008-06-26 19:42:07 +00:00
$return [ 'prev' ] = $return2 [ 0 ];
2008-06-26 19:33:44 +00:00
}
2011-02-23 02:47:27 +00:00
if ( count ( $return2 ) === 2 ) {
2008-06-26 19:42:07 +00:00
$return [ 'next' ] = $return2 [ 1 ];
2011-02-23 02:47:27 +00:00
} elseif ( count ( $return2 ) === 1 && ! $return [ 'prev' ]) {
2008-06-26 19:42:07 +00:00
$return [ 'next' ] = $return2 [ 0 ];
2008-06-26 19:33:44 +00:00
} else {
$return [ 'next' ] = null ;
}
return $return ;
}
}
2009-05-01 21:05:46 +00:00
2008-06-26 19:33:44 +00:00
/**
2008-08-01 16:49:56 +00:00
* In the event of ambiguous results returned ( multiple top level results , with different parent_ids )
* top level results with different parent_ids to the first result will be dropped
*
2008-06-26 19:42:07 +00:00
* @ param mixed $state
* @ param mixed $query
* @ param array $results
2008-06-26 19:33:44 +00:00
* @ return array Threaded results
*/
2010-04-05 03:21:28 +00:00
protected function _findThreaded ( $state , $query , $results = array ()) {
2011-02-23 02:47:27 +00:00
if ( $state === 'before' ) {
2008-06-26 19:33:44 +00:00
return $query ;
2011-02-23 02:47:27 +00:00
} elseif ( $state === 'after' ) {
2012-01-19 22:20:15 +00:00
$parent = 'parent_id' ;
if ( isset ( $query [ 'parent' ])) {
$parent = $query [ 'parent' ];
}
2012-01-09 23:24:38 +00:00
return Set :: nest ( $results , array (
2012-01-10 00:24:20 +00:00
'idPath' => '/' . $this -> alias . '/' . $this -> primaryKey ,
2012-01-19 22:20:15 +00:00
'parentPath' => '/' . $this -> alias . '/' . $parent
2012-01-09 23:48:15 +00:00
));
2008-06-26 19:33:44 +00:00
}
2008-06-26 19:42:07 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Passes query results through model and behavior afterFilter () methods .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param array $results Results to filter
2008-05-30 11:40:08 +00:00
* @ param boolean $primary If this is the primary model results ( results from model where the find operation was performed )
* @ return array Set of filtered results
*/
2011-02-25 16:26:14 +00:00
protected function _filterResults ( $results , $primary = true ) {
2011-12-26 17:36:48 +00:00
$event = new CakeEvent ( 'Model.afterFind' , $this , array ( $results , $primary ));
$event -> modParams = 0 ;
$this -> getEventManager () -> dispatch ( $event );
return $event -> result ;
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
* This resets the association arrays for the model back
2010-07-01 16:39:50 +00:00
* to those originally defined in the model . Normally called at the end
* of each call to Model :: find ()
2008-05-30 11:40:08 +00:00
*
* @ return boolean Success
*/
2010-04-05 03:19:38 +00:00
public function resetAssociations () {
2008-05-30 11:40:08 +00:00
if ( ! empty ( $this -> __backAssociation )) {
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associations as $type ) {
2008-05-30 11:40:08 +00:00
if ( isset ( $this -> __backAssociation [ $type ])) {
$this -> { $type } = $this -> __backAssociation [ $type ];
}
}
$this -> __backAssociation = array ();
}
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associations as $type ) {
2008-05-30 11:40:08 +00:00
foreach ( $this -> { $type } as $key => $name ) {
2010-07-14 21:28:12 +00:00
if ( property_exists ( $this , $key ) && ! empty ( $this -> { $key } -> __backAssociation )) {
2008-05-30 11:40:08 +00:00
$this -> { $key } -> resetAssociations ();
}
}
}
$this -> __backAssociation = array ();
return true ;
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns false if any fields passed match any ( by default , all if $or = false ) of their matching values .
2008-05-30 11:40:08 +00:00
*
* @ 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
*/
2010-04-05 03:19:38 +00:00
public function isUnique ( $fields , $or = true ) {
2008-05-30 11:40:08 +00:00
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 -> alias ][ $field ])) {
$value = $this -> data [ $this -> alias ][ $field ];
} else {
$value = null ;
}
}
if ( strpos ( $field , '.' ) === false ) {
unset ( $fields [ $field ]);
$fields [ $this -> alias . '.' . $field ] = $value ;
}
}
if ( $or ) {
$fields = array ( 'or' => $fields );
}
if ( ! empty ( $this -> id )) {
2012-03-04 19:18:04 +00:00
$fields [ $this -> alias . '.' . $this -> primaryKey . ' !=' ] = $this -> id ;
2008-05-30 11:40:08 +00:00
}
2008-09-26 00:46:53 +00:00
return ( $this -> find ( 'count' , array ( 'conditions' => $fields , 'recursive' => - 1 )) == 0 );
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns a resultset for a given SQL statement . Custom SQL queries should be performed with this method .
2008-05-30 11:40:08 +00:00
*
2011-08-22 01:45:34 +00:00
* @ param string $sql , ... SQL statement
2012-04-03 13:36:41 +00:00
* @ return mixed Resultset array or boolean indicating success / failure depending on the query executed
2011-10-15 17:04:31 +00:00
* @ link http :// book . cakephp . org / 2.0 / en / models / retrieving - your - data . html #model-query
2008-05-30 11:40:08 +00:00
*/
2011-08-22 01:45:34 +00:00
public function query ( $sql ) {
2008-05-30 11:40:08 +00:00
$params = func_get_args ();
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2008-05-30 11:40:08 +00:00
return call_user_func_array ( array ( & $db , 'query' ), $params );
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2009-12-15 04:21:26 +00:00
* Returns true if all fields pass validation . Will validate hasAndBelongsToMany associations
2011-08-20 04:43:34 +00:00
* that use the 'with' key as well . Since _saveMulti is incapable of exiting a save operation .
2008-05-30 11:40:08 +00:00
*
2009-12-03 05:53:31 +00:00
* Will validate the currently set data . Use Model :: set () or Model :: create () to set the active data .
*
2012-02-17 12:51:20 +00:00
* @ param array $options An optional array of custom options to be made available in the beforeValidate callback
2008-05-30 11:40:08 +00:00
* @ return boolean True if there are no errors
*/
2011-05-28 20:38:46 +00:00
public function validates ( $options = array ()) {
2008-05-30 11:40:08 +00:00
$errors = $this -> invalidFields ( $options );
2009-12-15 04:21:26 +00:00
if ( empty ( $errors ) && $errors !== false ) {
2011-08-20 04:43:34 +00:00
$errors = $this -> _validateWithModels ( $options );
2009-12-15 04:21:26 +00:00
}
2008-05-30 11:40:08 +00:00
if ( is_array ( $errors )) {
return count ( $errors ) === 0 ;
}
return $errors ;
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2009-12-15 04:21:26 +00:00
* Returns an array of fields that have failed validation . On the current model .
2008-05-30 11:40:08 +00:00
*
* @ param string $options An optional array of custom options to be made available in the beforeValidate callback
* @ return array Array of invalid fields
2009-12-03 05:53:31 +00:00
* @ see Model :: validates ()
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function invalidFields ( $options = array ()) {
2011-12-26 17:36:48 +00:00
$event = new CakeEvent ( 'Model.beforeValidate' , $this , array ( $options ));
list ( $event -> break , $event -> breakOn ) = array ( true , false );
$this -> getEventManager () -> dispatch ( $event );
if ( $event -> isStopped ()) {
2009-11-04 17:36:17 +00:00
return false ;
2008-05-30 11:40:08 +00:00
}
if ( ! isset ( $this -> validate ) || empty ( $this -> validate )) {
return $this -> validationErrors ;
}
2008-09-04 01:00:08 +00:00
2008-05-30 11:40:08 +00:00
$data = $this -> data ;
$methods = array_map ( 'strtolower' , get_class_methods ( $this ));
$behaviorMethods = array_keys ( $this -> Behaviors -> methods ());
if ( isset ( $data [ $this -> alias ])) {
$data = $data [ $this -> alias ];
} elseif ( ! is_array ( $data )) {
$data = array ();
}
2012-01-20 03:50:40 +00:00
$exists = null ;
2008-05-30 11:40:08 +00:00
2008-08-27 08:01:00 +00:00
$_validate = $this -> validate ;
2009-03-17 18:19:12 +00:00
$whitelist = $this -> whitelist ;
2010-08-22 02:48:59 +00:00
if ( ! empty ( $options [ 'fieldList' ])) {
2011-12-22 20:37:48 +00:00
if ( ! empty ( $options [ 'fieldList' ][ $this -> alias ]) && is_array ( $options [ 'fieldList' ][ $this -> alias ])) {
$whitelist = $options [ 'fieldList' ][ $this -> alias ];
} else {
$whitelist = $options [ 'fieldList' ];
}
2009-03-17 18:19:12 +00:00
}
if ( ! empty ( $whitelist )) {
2008-08-27 16:43:15 +00:00
$validate = array ();
2009-03-17 18:19:12 +00:00
foreach (( array ) $whitelist as $f ) {
2008-08-27 08:01:00 +00:00
if ( ! empty ( $this -> validate [ $f ])) {
$validate [ $f ] = $this -> validate [ $f ];
}
}
$this -> validate = $validate ;
}
2008-08-27 16:43:15 +00:00
2011-09-11 23:40:34 +00:00
$validationDomain = $this -> validationDomain ;
if ( empty ( $validationDomain )) {
$validationDomain = 'default' ;
}
2008-05-30 11:40:08 +00:00
foreach ( $this -> validate as $fieldName => $ruleSet ) {
if ( ! is_array ( $ruleSet ) || ( is_array ( $ruleSet ) && isset ( $ruleSet [ 'rule' ]))) {
$ruleSet = array ( $ruleSet );
}
2008-09-04 01:00:08 +00:00
$default = array (
'allowEmpty' => null ,
'required' => null ,
'rule' => 'blank' ,
2010-12-26 06:40:02 +00:00
'last' => true ,
2008-09-04 01:00:08 +00:00
'on' => null
);
2008-05-30 11:40:08 +00:00
foreach ( $ruleSet as $index => $validator ) {
if ( ! is_array ( $validator )) {
$validator = array ( 'rule' => $validator );
}
$validator = array_merge ( $default , $validator );
2012-02-07 14:31:27 +00:00
if ( ! empty ( $validator [ 'on' ]) || in_array ( $validator [ 'required' ], array ( 'create' , 'update' ), true )) {
2012-01-20 03:50:40 +00:00
if ( $exists === null ) {
$exists = $this -> exists ();
}
2012-02-07 11:15:04 +00:00
if ( $validator [ 'on' ] == 'create' && $exists || $validator [ 'on' ] == 'update' && ! $exists ) {
2012-01-20 03:50:40 +00:00
continue ;
}
2012-02-07 14:31:27 +00:00
if ( $validator [ 'required' ] === 'create' && ! $exists || $validator [ 'required' ] === 'update' && $exists ) {
2012-02-07 11:15:04 +00:00
$validator [ 'required' ] = true ;
}
2012-01-20 03:50:40 +00:00
}
2008-09-19 15:27:43 +00:00
2012-01-20 03:50:40 +00:00
$valid = true ;
$requiredFail = (
( ! isset ( $data [ $fieldName ]) && $validator [ 'required' ] === true ) ||
(
isset ( $data [ $fieldName ]) && ( empty ( $data [ $fieldName ]) &&
! is_numeric ( $data [ $fieldName ])) && $validator [ 'allowEmpty' ] === false
)
);
2008-05-30 11:40:08 +00:00
2012-01-20 03:50:40 +00:00
if ( ! $requiredFail && array_key_exists ( $fieldName , $data )) {
if ( empty ( $data [ $fieldName ]) && $data [ $fieldName ] != '0' && $validator [ 'allowEmpty' ] === true ) {
break ;
}
if ( is_array ( $validator [ 'rule' ])) {
$rule = $validator [ 'rule' ][ 0 ];
unset ( $validator [ 'rule' ][ 0 ]);
$ruleParams = array_merge ( array ( $data [ $fieldName ]), array_values ( $validator [ 'rule' ]));
} else {
$rule = $validator [ 'rule' ];
$ruleParams = array ( $data [ $fieldName ]);
2011-09-11 23:40:34 +00:00
}
2008-08-01 06:28:59 +00:00
2012-01-20 03:50:40 +00:00
if ( in_array ( strtolower ( $rule ), $methods )) {
$ruleParams [] = $validator ;
$ruleParams [ 0 ] = array ( $fieldName => $ruleParams [ 0 ]);
$valid = $this -> dispatchMethod ( $rule , $ruleParams );
} elseif ( in_array ( $rule , $behaviorMethods ) || in_array ( strtolower ( $rule ), $behaviorMethods )) {
$ruleParams [] = $validator ;
$ruleParams [ 0 ] = array ( $fieldName => $ruleParams [ 0 ]);
$valid = $this -> Behaviors -> dispatchMethod ( $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 ]);
} elseif ( Configure :: read ( 'debug' ) > 0 ) {
trigger_error ( __d ( 'cake_dev' , 'Could not find validation handler %s for %s' , $rule , $fieldName ), E_USER_WARNING );
}
}
if ( $requiredFail || ! $valid || ( is_string ( $valid ) && strlen ( $valid ) > 0 )) {
if ( is_string ( $valid )) {
$message = $valid ;
} elseif ( isset ( $validator [ 'message' ])) {
$args = null ;
if ( is_array ( $validator [ 'message' ])) {
$message = $validator [ 'message' ][ 0 ];
$args = array_slice ( $validator [ 'message' ], 1 );
2011-09-11 23:40:34 +00:00
} else {
2012-01-20 03:50:40 +00:00
$message = $validator [ 'message' ];
2011-09-11 23:40:34 +00:00
}
2012-01-20 03:50:40 +00:00
if ( is_array ( $validator [ 'rule' ]) && $args === null ) {
$args = array_slice ( $ruleSet [ $index ][ 'rule' ], 1 );
2008-05-30 11:40:08 +00:00
}
2012-01-20 03:50:40 +00:00
$message = __d ( $validationDomain , $message , $args );
} elseif ( is_string ( $index )) {
if ( is_array ( $validator [ 'rule' ])) {
$args = array_slice ( $ruleSet [ $index ][ 'rule' ], 1 );
$message = __d ( $validationDomain , $index , $args );
} else {
$message = __d ( $validationDomain , $index );
2008-05-30 11:40:08 +00:00
}
2012-01-20 03:50:40 +00:00
} elseif ( ! $requiredFail && is_numeric ( $index ) && count ( $ruleSet ) > 1 ) {
$message = $index + 1 ;
} else {
$message = __d ( 'cake_dev' , 'This field cannot be left blank' );
}
$this -> invalidate ( $fieldName , $message );
if ( $validator [ 'last' ]) {
break ;
2008-05-30 11:40:08 +00:00
}
}
}
}
2008-08-27 08:01:00 +00:00
$this -> validate = $_validate ;
2008-05-30 11:40:08 +00:00
return $this -> validationErrors ;
}
2009-05-01 21:05:46 +00:00
2009-12-15 04:21:26 +00:00
/**
* Runs validation for hasAndBelongsToMany associations that have 'with' keys
* set . And data in the set () data set .
*
2011-10-18 17:06:29 +00:00
* @ param array $options Array of options to use on Validation of with models
2009-12-15 04:21:26 +00:00
* @ return boolean Failure of validation on with models .
* @ see Model :: validates ()
*/
2011-08-20 04:43:34 +00:00
protected function _validateWithModels ( $options ) {
2009-12-15 04:21:26 +00:00
$valid = true ;
2009-12-15 14:25:05 +00:00
foreach ( $this -> hasAndBelongsToMany as $assoc => $association ) {
if ( empty ( $association [ 'with' ]) || ! isset ( $this -> data [ $assoc ])) {
continue ;
}
list ( $join ) = $this -> joinModel ( $this -> hasAndBelongsToMany [ $assoc ][ 'with' ]);
$data = $this -> data [ $assoc ];
$newData = array ();
foreach (( array ) $data as $row ) {
if ( isset ( $row [ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]])) {
$newData [] = $row ;
} elseif ( isset ( $row [ $join ]) && isset ( $row [ $join ][ $this -> hasAndBelongsToMany [ $assoc ][ 'associationForeignKey' ]])) {
$newData [] = $row [ $join ];
2009-12-15 04:21:26 +00:00
}
}
2009-12-15 14:25:05 +00:00
if ( empty ( $newData )) {
continue ;
}
foreach ( $newData as $data ) {
$data [ $this -> hasAndBelongsToMany [ $assoc ][ 'foreignKey' ]] = $this -> id ;
$this -> { $join } -> create ( $data );
$valid = ( $valid && $this -> { $join } -> validates ( $options ));
}
2009-12-15 04:21:26 +00:00
}
return $valid ;
2008-05-30 11:40:08 +00:00
}
2011-12-06 20:52:48 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Marks a field as invalid , optionally setting the name of validation
* rule ( in case of multiple validation for field ) that was broken .
2008-05-30 11:40:08 +00:00
*
* @ param string $field The name of the field to invalidate
2009-08-02 19:18:54 +00:00
* @ param mixed $value Name of validation rule that was not failed , or validation message to
2010-03-06 03:07:39 +00:00
* be returned . If no validation key is provided , defaults to true .
2011-07-30 22:38:57 +00:00
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function invalidate ( $field , $value = true ) {
2008-05-30 11:40:08 +00:00
if ( ! is_array ( $this -> validationErrors )) {
$this -> validationErrors = array ();
}
2012-03-04 19:18:04 +00:00
$this -> validationErrors [ $field ][] = $value ;
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns true if given field name is a foreign key in this model .
2008-05-30 11:40:08 +00:00
*
* @ param string $field Returns true if the input string ends in " _id "
* @ return boolean True if the field is a foreign key listed in the belongsTo array .
*/
2010-04-05 03:19:38 +00:00
public function isForeignKey ( $field ) {
2008-05-30 11:40:08 +00:00
$foreignKeys = array ();
if ( ! empty ( $this -> belongsTo )) {
foreach ( $this -> belongsTo as $assoc => $data ) {
$foreignKeys [] = $data [ 'foreignKey' ];
}
}
return in_array ( $field , $foreignKeys );
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2010-03-15 10:55:47 +00:00
* Escapes the field name and prepends the model name . Escaping is done according to the
2010-03-06 03:07:39 +00:00
* current database driver ' s rules .
2008-05-30 11:40:08 +00:00
*
* @ param string $field Field to escape ( e . g : id )
* @ param string $alias Alias for the model ( e . g : Post )
* @ return string The name of the escaped field for this Model ( i . e . id becomes `Post` . `id` ) .
*/
2010-04-05 03:19:38 +00:00
public function escapeField ( $field = null , $alias = null ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $alias )) {
$alias = $this -> alias ;
}
if ( empty ( $field )) {
$field = $this -> primaryKey ;
}
2010-07-15 03:49:38 +00:00
$db = $this -> getDataSource ();
2010-03-17 15:02:36 +00:00
if ( strpos ( $field , $db -> name ( $alias ) . '.' ) === 0 ) {
2008-05-30 11:40:08 +00:00
return $field ;
}
return $db -> name ( $alias . '.' . $field );
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
* Returns the current record ' s ID
*
* @ param integer $list Index on which the composed ID is located
* @ return mixed The ID of the current record , false if no ID
*/
2010-04-05 03:19:38 +00:00
public function getID ( $list = 0 ) {
2008-05-30 11:40:08 +00:00
if ( empty ( $this -> id ) || ( is_array ( $this -> id ) && isset ( $this -> id [ 0 ]) && empty ( $this -> id [ 0 ]))) {
return false ;
}
if ( ! is_array ( $this -> id )) {
return $this -> id ;
}
if ( isset ( $this -> id [ $list ]) && ! empty ( $this -> id [ $list ])) {
return $this -> id [ $list ];
} elseif ( isset ( $this -> id [ $list ])) {
return false ;
}
2011-12-14 06:19:50 +00:00
return current ( $this -> id );
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns the ID of the last record this model inserted .
2008-05-30 11:40:08 +00:00
*
* @ return mixed Last inserted ID
*/
2010-04-05 03:19:38 +00:00
public function getLastInsertID () {
2008-05-30 11:40:08 +00:00
return $this -> getInsertID ();
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns the ID of the last record this model inserted .
2008-05-30 11:40:08 +00:00
*
* @ return mixed Last inserted ID
*/
2010-04-05 03:19:38 +00:00
public function getInsertID () {
2011-08-20 04:43:34 +00:00
return $this -> _insertID ;
2008-05-30 11:40:08 +00:00
}
2009-05-01 21:05:46 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Sets the ID of the last record this model inserted
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param mixed $id Last inserted ID
* @ return void
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function setInsertID ( $id ) {
2011-08-20 04:43:34 +00:00
$this -> _insertID = $id ;
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns the number of rows returned from the last query .
2008-05-30 11:40:08 +00:00
*
2011-08-01 02:57:17 +00:00
* @ return integer Number of rows
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function getNumRows () {
2010-07-15 03:49:38 +00:00
return $this -> getDataSource () -> lastNumRows ();
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Returns the number of rows affected by the last query .
2008-05-30 11:40:08 +00:00
*
2011-08-01 02:57:17 +00:00
* @ return integer Number of rows
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function getAffectedRows () {
2010-07-15 03:49:38 +00:00
return $this -> getDataSource () -> lastAffected ();
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Sets the DataSource to which this model is bound .
2008-05-30 11:40:08 +00:00
*
2011-06-20 00:28:40 +00:00
* @ param string $dataSource The name of the DataSource , as defined in app / Config / database . php
2012-04-16 00:33:43 +00:00
* @ return void
2011-07-31 20:55:52 +00:00
* @ throws MissingConnectionException
2008-05-30 11:40:08 +00:00
*/
2010-04-05 03:19:38 +00:00
public function setDataSource ( $dataSource = null ) {
2008-05-30 11:40:08 +00:00
$oldConfig = $this -> useDbConfig ;
if ( $dataSource != null ) {
$this -> useDbConfig = $dataSource ;
}
2010-07-16 01:46:52 +00:00
$db = ConnectionManager :: getDataSource ( $this -> useDbConfig );
2008-05-30 11:40:08 +00:00
if ( ! empty ( $oldConfig ) && isset ( $db -> config [ 'prefix' ])) {
2010-07-16 02:46:19 +00:00
$oldDb = ConnectionManager :: getDataSource ( $oldConfig );
2008-05-30 11:40:08 +00:00
2008-08-19 01:18:33 +00:00
if ( ! isset ( $this -> tablePrefix ) || ( ! isset ( $oldDb -> config [ 'prefix' ]) || $this -> tablePrefix == $oldDb -> config [ 'prefix' ])) {
2008-05-30 11:40:08 +00:00
$this -> tablePrefix = $db -> config [ 'prefix' ];
}
} elseif ( isset ( $db -> config [ 'prefix' ])) {
$this -> tablePrefix = $db -> config [ 'prefix' ];
}
2011-11-05 10:57:08 +00:00
$this -> schemaName = $db -> getSchemaName ();
2009-10-13 03:38:55 +00:00
if ( empty ( $db ) || ! is_object ( $db )) {
2010-08-30 01:37:25 +00:00
throw new MissingConnectionException ( array ( 'class' => $this -> name ));
2008-05-30 11:40:08 +00:00
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
* Gets the DataSource to which this model is bound .
*
2011-08-01 02:57:17 +00:00
* @ return DataSource A DataSource object
2008-05-30 11:40:08 +00:00
*/
2010-07-16 03:47:13 +00:00
public function getDataSource () {
2011-08-20 04:43:34 +00:00
if ( ! $this -> _sourceConfigured && $this -> useTable !== false ) {
$this -> _sourceConfigured = true ;
2010-07-16 01:46:52 +00:00
$this -> setSource ( $this -> useTable );
}
2010-07-15 03:49:38 +00:00
return ConnectionManager :: getDataSource ( $this -> useDbConfig );
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2010-04-04 08:17:43 +00:00
/**
* Get associations
*
* @ return array
*/
2010-04-05 03:19:38 +00:00
public function associations () {
2011-08-20 04:43:34 +00:00
return $this -> _associations ;
2010-04-04 08:17:43 +00:00
}
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Gets all the models with which this model is associated .
2008-05-30 11:40:08 +00:00
*
* @ param string $type Only result associations of this type
* @ return array Associations
*/
2010-04-05 03:19:38 +00:00
public function getAssociated ( $type = null ) {
2008-05-30 11:40:08 +00:00
if ( $type == null ) {
$associated = array ();
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associations as $assoc ) {
2008-05-30 11:40:08 +00:00
if ( ! empty ( $this -> { $assoc })) {
$models = array_keys ( $this -> { $assoc });
foreach ( $models as $m ) {
$associated [ $m ] = $assoc ;
}
}
}
return $associated ;
2011-08-20 04:43:34 +00:00
} elseif ( in_array ( $type , $this -> _associations )) {
2008-05-30 11:40:08 +00:00
if ( empty ( $this -> { $type })) {
return array ();
}
return array_keys ( $this -> { $type });
} else {
2009-05-01 21:05:46 +00:00
$assoc = array_merge (
$this -> hasOne ,
$this -> hasMany ,
$this -> belongsTo ,
$this -> hasAndBelongsToMany
);
2008-05-30 11:40:08 +00:00
if ( array_key_exists ( $type , $assoc )) {
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associations as $a ) {
2008-05-30 11:40:08 +00:00
if ( isset ( $this -> { $a }[ $type ])) {
$assoc [ $type ][ 'association' ] = $a ;
break ;
}
}
return $assoc [ $type ];
}
return null ;
}
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2009-05-01 21:05:46 +00:00
* Gets the name and fields to be used by a join model . This allows specifying join fields
* in the association definition .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param string | array $assoc The model to be joined
2008-05-30 11:40:08 +00:00
* @ param array $keys Any join keys which must be merged with the keys queried
* @ return array
*/
2010-04-05 03:19:38 +00:00
public function joinModel ( $assoc , $keys = array ()) {
2008-05-30 11:40:08 +00:00
if ( is_string ( $assoc )) {
2010-07-14 22:24:19 +00:00
list (, $assoc ) = pluginSplit ( $assoc );
2008-05-30 11:40:08 +00:00
return array ( $assoc , array_keys ( $this -> { $assoc } -> schema ()));
} elseif ( is_array ( $assoc )) {
$with = key ( $assoc );
return array ( $with , array_unique ( array_merge ( $assoc [ $with ], $keys )));
}
2009-05-01 21:05:46 +00:00
trigger_error (
2011-03-20 15:35:43 +00:00
__d ( 'cake_dev' , 'Invalid join model settings in %s' , $model -> alias ),
2009-05-01 21:05:46 +00:00
E_USER_WARNING
);
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Called before each find operation . Return false if you want to halt the find
* call , otherwise return the ( modified ) query data .
2008-05-30 11:40:08 +00:00
*
* @ param array $queryData Data used to execute this query , i . e . conditions , order , etc .
2009-05-01 21:05:46 +00:00
* @ return mixed true if the operation should continue , false if it should abort ; or , modified
* $queryData to continue with new $queryData
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #beforeFind-1049
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function beforeFind ( $queryData ) {
2008-05-30 11:40:08 +00:00
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Called after each find operation . Can be used to modify any results returned by find () .
2008-11-08 02:54:07 +00:00
* Return value should be the ( modified ) results .
2008-05-30 11:40:08 +00:00
*
* @ param mixed $results The results of the find operation
* @ param boolean $primary Whether this model is being queried directly ( vs . being queried as an association )
* @ return mixed Result of the find operation
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #afterFind-1050
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function afterFind ( $results , $primary = false ) {
2008-05-30 11:40:08 +00:00
return $results ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Called before each save operation , after validation . Return a non - true result
* to halt the save .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param array $options
2008-05-30 11:40:08 +00:00
* @ return boolean True if the operation should continue , false if it should abort
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #beforeSave-1052
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function beforeSave ( $options = array ()) {
2008-05-30 11:40:08 +00:00
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-11-08 02:54:07 +00:00
* Called after each successful save operation .
2008-05-30 11:40:08 +00:00
*
* @ param boolean $created True if this save created a new record
2011-07-30 22:38:57 +00:00
* @ return void
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #afterSave-1053
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function afterSave ( $created ) {
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2009-05-22 01:20:47 +00:00
* Called before every deletion operation .
2008-05-30 11:40:08 +00:00
*
* @ param boolean $cascade If true records that depend on this record will also be deleted
* @ return boolean True if the operation should continue , false if it should abort
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #beforeDelete-1054
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function beforeDelete ( $cascade = true ) {
2008-05-30 11:40:08 +00:00
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Called after every deletion operation .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ return void
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #afterDelete-1055
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function afterDelete () {
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2009-11-04 17:36:17 +00:00
* Called during validation operations , before validation . Please note that custom
2008-10-31 19:05:30 +00:00
* validation rules can be defined in $validate .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ param array $options Options passed from model :: save (), see $options of model :: save () .
2008-05-30 11:40:08 +00:00
* @ return boolean True if validate operation should continue , false to abort
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #beforeValidate-1051
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function beforeValidate ( $options = array ()) {
2008-05-30 11:40:08 +00:00
return true ;
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2008-10-31 19:05:30 +00:00
* Called when a DataSource - level error occurs .
2008-05-30 11:40:08 +00:00
*
2011-07-30 22:38:57 +00:00
* @ return void
2010-03-06 03:07:39 +00:00
* @ link http :// book . cakephp . org / view / 1048 / Callback - Methods #onError-1056
2008-05-30 11:40:08 +00:00
*/
2011-05-28 20:38:46 +00:00
public function onError () {
2008-05-30 11:40:08 +00:00
}
2009-07-24 19:18:37 +00:00
2008-05-30 11:40:08 +00:00
/**
2011-08-20 04:43:34 +00:00
* Clears cache for this model .
2008-05-30 11:40:08 +00:00
*
* @ param string $type If null this deletes cached views if Cache . check is true
2010-03-06 03:07:39 +00:00
* Will be used to allow deleting query cache also
2008-05-30 11:40:08 +00:00
* @ return boolean true on delete
*/
2011-05-28 20:38:46 +00:00
protected function _clearCache ( $type = null ) {
2008-05-30 11:40:08 +00:00
if ( $type === null ) {
if ( Configure :: read ( 'Cache.check' ) === true ) {
$assoc [] = strtolower ( Inflector :: pluralize ( $this -> alias ));
2008-10-26 18:51:38 +00:00
$assoc [] = strtolower ( Inflector :: underscore ( Inflector :: pluralize ( $this -> alias )));
2011-08-20 04:43:34 +00:00
foreach ( $this -> _associations as $key => $association ) {
2008-05-30 11:40:08 +00:00
foreach ( $this -> $association as $key => $className ) {
$check = strtolower ( Inflector :: pluralize ( $className [ 'className' ]));
if ( ! in_array ( $check , $assoc )) {
$assoc [] = strtolower ( Inflector :: pluralize ( $className [ 'className' ]));
2008-10-26 18:51:38 +00:00
$assoc [] = strtolower ( Inflector :: underscore ( Inflector :: pluralize ( $className [ 'className' ])));
2008-05-30 11:40:08 +00:00
}
}
}
clearCache ( $assoc );
return true ;
}
} else {
//Will use for query cache deleting
}
}
2012-03-04 19:18:04 +00:00
2008-05-30 11:40:08 +00:00
}