2007-01-19 23:47:24 +03:00
< ? php
/*
* $Id $
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL . For more information , see
2008-01-23 01:52:53 +03:00
* < http :// www . phpdoctrine . org >.
2007-01-19 23:47:24 +03:00
*/
2007-06-27 21:46:34 +04:00
Doctrine :: autoload ( 'Doctrine_Record_Abstract' );
2007-01-19 23:47:24 +03:00
/**
* Doctrine_Record
* All record classes should inherit this super class
*
2007-10-04 01:43:22 +04:00
* @ package Doctrine
* @ subpackage Record
2007-01-19 23:47:24 +03:00
* @ author Konsta Vesterinen < kvesteri @ cc . hut . fi >
2008-02-04 00:29:57 +03:00
* @ author Roman Borschel < roman @ code - factory . org >
2007-01-19 23:47:24 +03:00
* @ license http :// www . opensource . org / licenses / lgpl - license . php LGPL
2008-02-22 21:11:35 +03:00
* @ link www . phpdoctrine . org
2007-01-19 23:47:24 +03:00
* @ since 1.0
* @ version $Revision $
2008-02-20 23:54:20 +03:00
* @ todo Remove the depdency on the ClassMetadata . All operations that involve the metadata
* should be left to the mapper .
2007-01-19 23:47:24 +03:00
*/
2007-06-27 20:59:23 +04:00
abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Countable , IteratorAggregate , Serializable
2007-01-19 23:47:24 +03:00
{
/**
* STATE CONSTANTS
*/
/**
* DIRTY STATE
* a Doctrine_Record is in dirty state when its properties are changed
*/
2008-02-04 00:29:57 +03:00
const STATE_DIRTY = 1 ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* TDIRTY STATE
2007-12-11 14:10:27 +03:00
* a Doctrine_Record is in transient dirty state when it is created
2007-07-21 00:41:13 +04:00
* and some of its fields are modified but it is NOT yet persisted into database
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
const STATE_TDIRTY = 2 ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* CLEAN STATE
* a Doctrine_Record is in clean state when all of its properties are loaded from the database
* and none of its properties are changed
*/
2008-02-04 00:29:57 +03:00
const STATE_CLEAN = 3 ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* PROXY STATE
* a Doctrine_Record is in proxy state when its properties are not fully loaded
*/
2008-02-04 00:29:57 +03:00
const STATE_PROXY = 4 ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* NEW TCLEAN
* a Doctrine_Record is in transient clean state when it is created and none of its fields are modified
*/
2008-02-04 00:29:57 +03:00
const STATE_TCLEAN = 5 ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2007-07-07 01:18:36 +04:00
* LOCKED STATE
2007-07-21 00:41:13 +04:00
* a Doctrine_Record is temporarily locked during deletes and saves
*
* This state is used internally to ensure that circular deletes
* and saves will not cause infinite loops
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
const STATE_LOCKED = 6 ;
2008-02-24 01:04:39 +03:00
/**
* Index used for creating object identifiers ( oid ' s ) .
*
* @ var integer $index
*/
private static $_index = 1 ;
/**
* Boolean flag that indicated whether automatic accessor overriding is enabled .
*/
private static $_useAutoAccessorOverride ;
/**
* The accessor cache is used as a memory for the existance of custom accessors
* for fields .
* Only used when ATTR_ACCESSOR_OVERRIDE is set to ACCESSOR_OVERRIDE_AUTO .
*/
private static $_accessorCache = array ();
/**
* The mutator cache is used as a memory for the existance of custom mutators
* for fields .
* Only used when ATTR_ACCESSOR_OVERRIDE is set to ACCESSOR_OVERRIDE_MANUAL .
*/
private static $_mutatorCache = array ();
2007-08-03 15:52:24 +04:00
2008-01-05 22:55:56 +03:00
/**
*
*/
2008-02-24 01:04:39 +03:00
protected $_entityName ;
2008-01-05 22:55:56 +03:00
2007-02-08 15:53:32 +03:00
/**
2007-04-13 22:06:48 +04:00
* @ var Doctrine_Node_ < TreeImpl > node object
2008-02-04 00:29:57 +03:00
* @ todo Specific to the NestedSet Behavior plugin . Move outta here .
2007-02-08 15:53:32 +03:00
*/
protected $_node ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The values that make up the ID / primary key of the object .
*
* @ var array
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
protected $_id = array ();
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The record data .
*
* @ var array
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
protected $_data = array ();
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The values array , aggregate values and such are mapped into this array .
*
* @ var array
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
protected $_values = array ();
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The state of the object .
*
* @ var integer
2007-01-19 23:47:24 +03:00
* @ see STATE_ * constants
*/
protected $_state ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The names of fields that have been modified but not yet persisted .
*
* @ var array
2007-11-19 13:00:44 +03:00
* @ todo Better name ? $_modifiedFields ?
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
protected $_modified = array ();
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The error stack used to collect errors during validation .
*
2008-02-24 01:04:39 +03:00
* @ var Doctrine_Validator_ErrorStack
* @ internal Uses lazy initialization to reduce memory usage .
2007-01-19 23:47:24 +03:00
*/
protected $_errorStack ;
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The names of all relations .
*
* @ var array $_references
2007-01-19 23:47:24 +03:00
*/
2008-02-04 00:29:57 +03:00
protected $_references = array ();
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* The object identifier of the object . Each object has a unique identifier during runtime .
*
* @ var integer $oid
2007-01-19 23:47:24 +03:00
*/
2007-05-18 13:22:31 +04:00
private $_oid ;
2007-01-19 23:47:24 +03:00
/**
2008-02-04 00:29:57 +03:00
* Constructor .
*
2007-01-19 23:47:24 +03:00
* @ param Doctrine_Table | null $table a Doctrine_Table object or null ,
* if null the table object is retrieved from current connection
*
* @ param boolean $isNewEntry whether or not this record is transient
*
* @ throws Doctrine_Connection_Exception if object is created using the new operator and there are no
* open connections
* @ throws Doctrine_Record_Exception if the cleanData operation fails somehow
*/
2008-01-12 22:49:11 +03:00
public function __construct ( $mapper = null , $isNewEntry = false , array $data = array ())
2007-01-19 23:47:24 +03:00
{
2008-02-20 23:54:20 +03:00
if ( isset ( $mapper ) && $mapper instanceof Doctrine_Mapper ) {
2007-11-19 20:55:23 +03:00
$class = get_class ( $this );
2008-01-05 22:55:56 +03:00
$this -> _mapper = Doctrine_Manager :: getInstance () -> getMapper ( $class );
2008-02-20 23:54:20 +03:00
$this -> _table = $this -> _mapper -> getClassMetadata ();
2008-01-05 22:55:56 +03:00
$exists = ! $isNewEntry ;
} else {
$this -> _mapper = Doctrine_Manager :: getInstance () -> getMapper ( get_class ( $this ));
2008-02-20 23:54:20 +03:00
$this -> _table = $this -> _mapper -> getClassMetadata ();
2007-01-19 23:47:24 +03:00
$exists = false ;
}
2007-05-30 14:20:21 +04:00
2008-02-24 01:04:39 +03:00
$this -> _entityName = $this -> _mapper -> getMappedClassName ();
2007-11-18 19:06:37 +03:00
$this -> _oid = self :: $_index ;
2008-01-05 22:55:56 +03:00
2007-11-18 19:06:37 +03:00
self :: $_index ++ ;
2007-01-19 23:47:24 +03:00
2007-11-18 19:06:37 +03:00
// get the data array
2008-01-12 22:49:11 +03:00
$this -> _data = $data ;
2007-07-16 23:19:29 +04:00
2007-11-18 19:06:37 +03:00
// get the column count
$count = count ( $this -> _data );
2008-01-05 22:55:56 +03:00
2007-11-18 19:06:37 +03:00
$this -> _values = $this -> cleanData ( $this -> _data );
2007-01-19 23:47:24 +03:00
2008-02-20 23:54:20 +03:00
$this -> _extractIdentifier ( $exists );
2008-01-05 22:55:56 +03:00
2007-11-18 19:06:37 +03:00
if ( ! $exists ) {
if ( $count > count ( $this -> _values )) {
$this -> _state = Doctrine_Record :: STATE_TDIRTY ;
2007-01-19 23:47:24 +03:00
} else {
2007-11-18 19:06:37 +03:00
$this -> _state = Doctrine_Record :: STATE_TCLEAN ;
2007-01-19 23:47:24 +03:00
}
2007-11-18 19:06:37 +03:00
// set the default values for this record
$this -> assignDefaultValues ();
} else {
2007-11-19 20:55:23 +03:00
$this -> _state = Doctrine_Record :: STATE_CLEAN ;
2007-11-18 19:06:37 +03:00
if ( $count < $this -> _table -> getColumnCount ()) {
$this -> _state = Doctrine_Record :: STATE_PROXY ;
}
2007-01-19 23:47:24 +03:00
}
2008-02-24 01:04:39 +03:00
self :: $_useAutoAccessorOverride = false ; // @todo read from attribute the first time
$this -> _mapper -> manage ( $this );
2007-11-18 19:06:37 +03:00
$this -> construct ();
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-05-31 21:45:07 +04:00
/**
* _index
*
* @ return integer
*/
public static function _index ()
{
return self :: $_index ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* setUp
* this method is used for setting up relations and attributes
* it should be implemented by child classes
*
* @ return void
*/
2008-02-08 01:21:18 +03:00
/* public function setUp ()
{ } */
2008-01-05 22:55:56 +03:00
2007-01-19 23:47:24 +03:00
/**
* construct
2007-09-13 00:26:59 +04:00
* Empty template method to provide concrete Record classes with the possibility
2007-01-19 23:47:24 +03:00
* to hook into the constructor procedure
*
* @ return void
*/
public function construct ()
{ }
2008-01-05 22:55:56 +03:00
2007-01-19 23:47:24 +03:00
/**
2007-05-18 13:22:31 +04:00
* getOid
2007-01-19 23:47:24 +03:00
* returns the object identifier
*
* @ return integer
*/
2007-05-18 13:22:31 +04:00
public function getOid ()
2007-01-19 23:47:24 +03:00
{
2007-05-18 13:22:31 +04:00
return $this -> _oid ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* isValid
*
2007-11-19 20:55:23 +03:00
* @ return boolean whether or not this record is valid
2007-01-19 23:47:24 +03:00
*/
public function isValid ()
{
2008-01-05 22:55:56 +03:00
if ( ! $this -> _mapper -> getAttribute ( Doctrine :: ATTR_VALIDATE )) {
2007-01-19 23:47:24 +03:00
return true ;
}
2008-02-20 23:54:20 +03:00
2007-01-19 23:47:24 +03:00
// Clear the stack from any previous errors.
2008-02-20 23:54:20 +03:00
$this -> getErrorStack () -> clear ();
2007-01-19 23:47:24 +03:00
// Run validation process
$validator = new Doctrine_Validator ();
$validator -> validateRecord ( $this );
$this -> validate ();
if ( $this -> _state == self :: STATE_TDIRTY || $this -> _state == self :: STATE_TCLEAN ) {
$this -> validateOnInsert ();
} else {
$this -> validateOnUpdate ();
}
2008-02-20 23:54:20 +03:00
return $this -> getErrorStack () -> count () == 0 ? true : false ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2007-06-20 03:33:04 +04:00
* Empty template method to provide concrete Record classes with the possibility
2007-01-19 23:47:24 +03:00
* to hook into the validation procedure , doing any custom / specialized
* validations that are neccessary .
*/
protected function validate ()
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-01-19 23:47:24 +03:00
/**
2007-06-25 01:37:19 +04:00
* Empty template method to provide concrete Record classes with the possibility
2007-01-19 23:47:24 +03:00
* to hook into the validation procedure only when the record is going to be
* updated .
*/
protected function validateOnUpdate ()
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-01-19 23:47:24 +03:00
/**
2007-06-25 01:37:19 +04:00
* Empty template method to provide concrete Record classes with the possibility
2007-01-19 23:47:24 +03:00
* to hook into the validation procedure only when the record is going to be
* inserted into the data store the first time .
*/
protected function validateOnInsert ()
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 21:24:20 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure .
*/
2008-02-04 00:29:57 +03:00
public function preSerialize ( Doctrine_Event $event )
2007-06-25 21:24:20 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 21:24:20 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure .
*/
2008-02-04 00:29:57 +03:00
public function postSerialize ( Doctrine_Event $event )
2007-06-25 21:24:20 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 21:24:20 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure .
*/
2008-02-04 00:29:57 +03:00
public function preUnserialize ( Doctrine_Event $event )
2007-06-25 21:24:20 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 21:24:20 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the serializing procedure .
*/
2008-02-04 00:29:57 +03:00
public function postUnserialize ( Doctrine_Event $event )
2007-06-25 21:24:20 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure .
*/
2008-02-04 00:29:57 +03:00
public function preSave ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure .
*/
2008-02-04 00:29:57 +03:00
public function postSave ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the deletion procedure .
*/
2008-02-04 00:29:57 +03:00
public function preDelete ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the deletion procedure .
*/
2008-02-04 00:29:57 +03:00
public function postDelete ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* updated .
*/
2008-02-04 00:29:57 +03:00
public function preUpdate ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* updated .
*/
2008-02-04 00:29:57 +03:00
public function postUpdate ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* inserted into the data store the first time .
*/
2008-02-04 00:29:57 +03:00
public function preInsert ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-06-25 01:37:19 +04:00
/**
* Empty template method to provide concrete Record classes with the possibility
* to hook into the saving procedure only when the record is going to be
* inserted into the data store the first time .
*/
2008-02-04 00:29:57 +03:00
public function postInsert ( Doctrine_Event $event )
2007-06-25 01:37:19 +04:00
{ }
2008-01-05 22:55:56 +03:00
2007-01-19 23:47:24 +03:00
/**
* getErrorStack
*
* @ return Doctrine_Validator_ErrorStack returns the errorStack associated with this record
*/
public function getErrorStack ()
{
2008-02-20 23:54:20 +03:00
if ( is_null ( $this -> _errorStack )) {
$this -> _errorStack = new Doctrine_Validator_ErrorStack ();
}
2007-01-19 23:47:24 +03:00
return $this -> _errorStack ;
}
2007-10-21 10:23:59 +04:00
2007-01-21 21:31:51 +03:00
/**
* errorStack
* assigns / returns record errorStack
*
* @ param Doctrine_Validator_ErrorStack errorStack to be assigned for this record
* @ return void | Doctrine_Validator_ErrorStack returns the errorStack associated with this record
*/
public function errorStack ( $stack = null )
{
2007-09-03 18:57:18 +04:00
if ( $stack !== null ) {
if ( ! ( $stack instanceof Doctrine_Validator_ErrorStack )) {
2007-04-03 21:36:46 +04:00
throw new Doctrine_Record_Exception ( 'Argument should be an instance of Doctrine_Validator_ErrorStack.' );
}
2007-01-21 21:31:51 +03:00
$this -> _errorStack = $stack ;
2007-04-03 21:36:46 +04:00
} else {
2008-02-20 23:54:20 +03:00
return $this -> getErrorStack ();
2007-01-21 21:31:51 +03:00
}
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* setDefaultValues
* sets the default values for records internal data
*
* @ param boolean $overwrite whether or not to overwrite the already set values
* @ return boolean
2008-02-08 01:21:18 +03:00
* @ todo Maybe better placed in the Mapper ?
2007-01-19 23:47:24 +03:00
*/
2007-01-21 21:31:51 +03:00
public function assignDefaultValues ( $overwrite = false )
2007-01-19 23:47:24 +03:00
{
if ( ! $this -> _table -> hasDefaultValues ()) {
return false ;
}
foreach ( $this -> _data as $column => $value ) {
$default = $this -> _table -> getDefaultValueOf ( $column );
2007-05-24 20:53:51 +04:00
if ( $default === null ) {
2007-10-22 00:12:36 +04:00
continue ;
2007-05-24 20:53:51 +04:00
}
2007-12-11 14:10:27 +03:00
2007-05-18 13:22:31 +04:00
if ( $value === self :: $_null || $overwrite ) {
2007-01-19 23:47:24 +03:00
$this -> _data [ $column ] = $default ;
$this -> _modified [] = $column ;
$this -> _state = Doctrine_Record :: STATE_TDIRTY ;
}
}
}
2007-10-21 10:23:59 +04:00
2007-07-16 23:19:29 +04:00
/**
* cleanData
2007-12-01 02:49:46 +03:00
* leaves the $data array only with values whose key is a field inside this
2008-01-19 05:35:39 +03:00
* record and returns the values that were removed from $data . Also converts
* any values of 'null' to objects of type Doctrine_Null .
2007-07-16 23:19:29 +04:00
*
* @ param array $data data array to be cleaned
2007-12-01 02:49:46 +03:00
* @ return array $tmp values cleaned from data
2008-02-08 01:21:18 +03:00
* @ todo Maybe better placed in the Mapper ?
2007-07-16 23:19:29 +04:00
*/
public function cleanData ( & $data )
{
2007-09-03 18:57:18 +04:00
$tmp = $data ;
2007-07-16 23:19:29 +04:00
$data = array ();
2008-01-05 22:55:56 +03:00
$fieldNames = $this -> _mapper -> getFieldNames ();
foreach ( $fieldNames as $fieldName ) {
2007-12-01 04:21:55 +03:00
if ( isset ( $tmp [ $fieldName ])) {
2007-11-18 19:06:37 +03:00
$data [ $fieldName ] = $tmp [ $fieldName ];
2008-01-19 05:35:39 +03:00
} else if ( array_key_exists ( $fieldName , $tmp )) {
$data [ $fieldName ] = self :: $_null ;
2007-12-01 04:21:55 +03:00
} else if ( ! isset ( $this -> _data [ $fieldName ])) {
$data [ $fieldName ] = self :: $_null ;
2007-07-16 23:19:29 +04:00
}
2007-11-18 19:06:37 +03:00
unset ( $tmp [ $fieldName ]);
2007-07-16 23:19:29 +04:00
}
2007-07-23 22:27:00 +04:00
2007-07-16 23:19:29 +04:00
return $tmp ;
}
2007-10-21 10:23:59 +04:00
2007-04-17 21:25:08 +04:00
/**
* hydrate
* hydrates this object from given array
*
* @ param array $data
* @ return boolean
*/
public function hydrate ( array $data )
{
2007-10-29 22:26:22 +03:00
$this -> _values = array_merge ( $this -> _values , $this -> cleanData ( $data ));
2007-08-30 02:15:25 +04:00
$this -> _data = array_merge ( $this -> _data , $data );
2008-02-20 23:54:20 +03:00
$this -> _extractIdentifier ( true );
2007-04-17 21:25:08 +04:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* prepareIdentifiers
* prepares identifiers for later use
*
* @ param boolean $exists whether or not this record exists in persistent data store
* @ return void
2008-02-08 01:21:18 +03:00
* @ todo Maybe better placed in the Mapper ?
2007-01-19 23:47:24 +03:00
*/
2008-02-20 23:54:20 +03:00
private function _extractIdentifier ( $exists = true )
2007-01-19 23:47:24 +03:00
{
switch ( $this -> _table -> getIdentifierType ()) {
2007-06-26 13:51:08 +04:00
case Doctrine :: IDENTIFIER_AUTOINC :
case Doctrine :: IDENTIFIER_SEQUENCE :
2007-08-04 01:02:17 +04:00
case Doctrine :: IDENTIFIER_NATURAL :
2008-02-24 23:31:49 +03:00
$name = ( array ) $this -> _table -> getIdentifier ();
$name = $name [ 0 ];
2007-01-19 23:47:24 +03:00
if ( $exists ) {
2007-05-18 13:22:31 +04:00
if ( isset ( $this -> _data [ $name ]) && $this -> _data [ $name ] !== self :: $_null ) {
2007-01-19 23:47:24 +03:00
$this -> _id [ $name ] = $this -> _data [ $name ];
}
}
break ;
2007-06-26 13:51:08 +04:00
case Doctrine :: IDENTIFIER_COMPOSITE :
2008-02-24 23:31:49 +03:00
$names = ( array ) $this -> _table -> getIdentifier ();
2007-01-19 23:47:24 +03:00
foreach ( $names as $name ) {
2007-05-18 13:22:31 +04:00
if ( $this -> _data [ $name ] === self :: $_null ) {
2007-01-19 23:47:24 +03:00
$this -> _id [ $name ] = null ;
} else {
$this -> _id [ $name ] = $this -> _data [ $name ];
}
}
break ;
2007-01-23 19:27:20 +03:00
}
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-01-12 22:49:11 +03:00
* Serializes the entity .
* This method is automatically called when the entity is serialized .
*
* Part of the implementation of the Serializable interface .
2007-01-19 23:47:24 +03:00
*
* @ return array
*/
public function serialize ()
{
2007-09-03 18:57:18 +04:00
$event = new Doctrine_Event ( $this , Doctrine_Event :: RECORD_SERIALIZE );
2007-06-25 21:24:20 +04:00
$this -> preSerialize ( $event );
2007-01-19 23:47:24 +03:00
$vars = get_object_vars ( $this );
2007-05-22 21:42:47 +04:00
unset ( $vars [ '_references' ]);
2008-01-05 22:55:56 +03:00
unset ( $vars [ '_mapper' ]);
2007-04-11 22:37:05 +04:00
unset ( $vars [ '_errorStack' ]);
2007-05-22 21:42:47 +04:00
unset ( $vars [ '_filter' ]);
unset ( $vars [ '_node' ]);
2007-01-19 23:47:24 +03:00
2008-02-24 23:31:49 +03:00
//$name = (array)$this->_table->getIdentifier();
2007-01-19 23:47:24 +03:00
$this -> _data = array_merge ( $this -> _data , $this -> _id );
foreach ( $this -> _data as $k => $v ) {
2007-08-07 19:37:30 +04:00
if ( $v instanceof Doctrine_Record && $this -> _table -> getTypeOf ( $k ) != 'object' ) {
2007-01-19 23:47:24 +03:00
unset ( $vars [ '_data' ][ $k ]);
2008-01-05 22:55:56 +03:00
} else if ( $v === self :: $_null ) {
2007-01-19 23:47:24 +03:00
unset ( $vars [ '_data' ][ $k ]);
} else {
switch ( $this -> _table -> getTypeOf ( $k )) {
2007-05-08 02:46:47 +04:00
case 'array' :
case 'object' :
2007-01-19 23:47:24 +03:00
$vars [ '_data' ][ $k ] = serialize ( $vars [ '_data' ][ $k ]);
break ;
2007-05-08 02:46:47 +04:00
case 'gzip' :
$vars [ '_data' ][ $k ] = gzcompress ( $vars [ '_data' ][ $k ]);
break ;
case 'enum' :
$vars [ '_data' ][ $k ] = $this -> _table -> enumIndex ( $k , $vars [ '_data' ][ $k ]);
break ;
2007-01-23 19:27:20 +03:00
}
2007-01-19 23:47:24 +03:00
}
}
2008-01-05 22:55:56 +03:00
2007-06-25 21:24:20 +04:00
$str = serialize ( $vars );
2007-12-11 14:10:27 +03:00
2007-06-25 21:24:20 +04:00
$this -> postSerialize ( $event );
return $str ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-01-12 22:49:11 +03:00
* Reconstructs the entity from it ' s serialized form .
* This method is automatically called everytime the entity is unserialized .
2007-01-19 23:47:24 +03:00
*
* @ param string $serialized Doctrine_Record as serialized string
* @ throws Doctrine_Record_Exception if the cleanData operation fails somehow
* @ return void
*/
public function unserialize ( $serialized )
{
2007-09-03 18:57:18 +04:00
$event = new Doctrine_Event ( $this , Doctrine_Event :: RECORD_UNSERIALIZE );
2007-07-12 02:03:47 +04:00
2007-09-03 18:57:18 +04:00
$this -> preUnserialize ( $event );
2007-07-12 02:03:47 +04:00
2007-01-19 23:47:24 +03:00
$manager = Doctrine_Manager :: getInstance ();
2007-03-31 23:49:23 +04:00
$connection = $manager -> getConnectionForComponent ( get_class ( $this ));
2007-01-19 23:47:24 +03:00
2007-05-22 21:42:47 +04:00
$this -> _oid = self :: $_index ;
self :: $_index ++ ;
2007-01-19 23:47:24 +03:00
2008-01-05 22:55:56 +03:00
$this -> _mapper = $connection -> getMapper ( get_class ( $this ));
2007-01-19 23:47:24 +03:00
$array = unserialize ( $serialized );
2007-05-22 21:42:47 +04:00
foreach ( $array as $k => $v ) {
$this -> $k = $v ;
2007-01-19 23:47:24 +03:00
}
2008-01-05 22:55:56 +03:00
$this -> _table = $this -> _mapper -> getTable ();
2007-05-22 22:09:54 +04:00
2007-08-07 19:37:30 +04:00
foreach ( $this -> _data as $k => $v ) {
switch ( $this -> _table -> getTypeOf ( $k )) {
case 'array' :
case 'object' :
$this -> _data [ $k ] = unserialize ( $this -> _data [ $k ]);
break ;
case 'gzip' :
$this -> _data [ $k ] = gzuncompress ( $this -> _data [ $k ]);
break ;
case 'enum' :
$this -> _data [ $k ] = $this -> _table -> enumValue ( $k , $this -> _data [ $k ]);
break ;
2007-12-11 14:10:27 +03:00
2007-08-07 19:37:30 +04:00
}
}
2007-12-11 14:10:27 +03:00
2008-02-28 18:30:55 +03:00
$this -> _mapper -> manage ( $this );
2007-07-16 23:19:29 +04:00
$this -> cleanData ( $this -> _data );
2008-02-20 23:54:20 +03:00
$this -> _extractIdentifier ( $this -> exists ());
2008-01-12 22:49:11 +03:00
2007-07-12 02:03:47 +04:00
$this -> postUnserialize ( $event );
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* state
* returns / assigns the state of this record
*
* @ param integer | string $state if set , this method tries to set the record state to $state
* @ see Doctrine_Record :: STATE_ * constants
*
* @ throws Doctrine_Record_State_Exception if trying to set an unknown state
* @ return null | integer
*/
public function state ( $state = null )
{
if ( $state == null ) {
return $this -> _state ;
}
$err = false ;
if ( is_integer ( $state )) {
if ( $state >= 1 && $state <= 6 ) {
$this -> _state = $state ;
} else {
$err = true ;
}
2007-11-18 19:06:37 +03:00
} else if ( is_string ( $state )) {
2007-01-19 23:47:24 +03:00
$upper = strtoupper ( $state );
2007-12-11 14:10:27 +03:00
2007-07-07 00:55:15 +04:00
$const = 'Doctrine_Record::STATE_' . $upper ;
if ( defined ( $const )) {
2007-12-11 14:10:27 +03:00
$this -> _state = constant ( $const );
2007-07-07 00:55:15 +04:00
} else {
$err = true ;
2007-01-19 23:47:24 +03:00
}
}
2007-05-24 00:41:03 +04:00
if ( $this -> _state === Doctrine_Record :: STATE_TCLEAN ||
2007-11-19 20:55:23 +03:00
$this -> _state === Doctrine_Record :: STATE_CLEAN ) {
2007-05-24 00:41:03 +04:00
$this -> _modified = array ();
}
if ( $err ) {
2008-01-12 22:49:11 +03:00
throw new Doctrine_Record_Exception ( " Unknown record state ' $state '. " );
2007-05-24 00:41:03 +04:00
}
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* refresh
* refresh internal data from the database
*
2007-11-28 22:35:44 +03:00
* @ param bool $deep If true , fetch also current relations . Caution : this deletes
2007-12-11 14:10:27 +03:00
* any aggregated values you may have queried beforee
2007-11-28 22:35:44 +03:00
*
2007-01-19 23:47:24 +03:00
* @ throws Doctrine_Record_Exception When the refresh operation fails ( when the database row
* this record represents does not exist anymore )
* @ return boolean
2008-02-08 01:21:18 +03:00
* @ todo Logic is better placed in the Mapper . Just forward to the mapper .
2007-01-19 23:47:24 +03:00
*/
2007-11-28 22:35:44 +03:00
public function refresh ( $deep = false )
2007-01-19 23:47:24 +03:00
{
2007-07-06 03:21:29 +04:00
$id = $this -> identifier ();
2007-01-19 23:47:24 +03:00
if ( ! is_array ( $id )) {
$id = array ( $id );
}
if ( empty ( $id )) {
return false ;
}
$id = array_values ( $id );
2007-11-28 22:35:44 +03:00
if ( $deep ) {
2008-01-05 22:55:56 +03:00
$query = $this -> _mapper -> createQuery ();
2007-11-28 22:35:44 +03:00
foreach ( array_keys ( $this -> _references ) as $name ) {
$query -> leftJoin ( get_class ( $this ) . '.' . $name );
}
2008-01-05 22:55:56 +03:00
$query -> where ( implode ( ' = ? AND ' , $this -> _table -> getIdentifierColumnNames ()) . ' = ?' );
2007-11-28 22:35:44 +03:00
$record = $query -> fetchOne ( $id );
} else {
// Use FETCH_ARRAY to avoid clearing object relations
2008-01-05 22:55:56 +03:00
$record = $this -> _mapper -> find ( $id , Doctrine :: HYDRATE_ARRAY );
2007-11-28 22:35:44 +03:00
if ( $record ) {
$this -> hydrate ( $record );
}
}
2007-01-19 23:47:24 +03:00
2007-09-04 05:23:11 +04:00
if ( $record === false ) {
2007-07-01 15:27:45 +04:00
throw new Doctrine_Record_Exception ( 'Failed to refresh. Record does not exist.' );
2007-05-22 20:58:34 +04:00
}
2007-05-22 21:42:47 +04:00
2007-01-19 23:47:24 +03:00
$this -> _modified = array ();
2008-02-20 23:54:20 +03:00
$this -> _extractIdentifier ();
2007-01-19 23:47:24 +03:00
2007-11-18 19:06:37 +03:00
$this -> _state = Doctrine_Record :: STATE_CLEAN ;
2007-01-19 23:47:24 +03:00
2007-07-06 00:03:38 +04:00
return $this ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-08-11 21:49:43 +04:00
/**
* refresh
* refres data of related objects from the database
*
2007-08-30 02:20:30 +04:00
* @ param string $name name of a related component .
* if set , this method only refreshes the specified related component
*
* @ return Doctrine_Record this object
2008-02-08 01:21:18 +03:00
* @ todo Logic is better placed in the Mapper . Just forward to the mapper .
2007-08-11 21:49:43 +04:00
*/
public function refreshRelated ( $name = null )
{
if ( is_null ( $name )) {
foreach ( $this -> _table -> getRelations () as $rel ) {
2007-09-03 18:57:18 +04:00
$this -> _references [ $rel -> getAlias ()] = $rel -> fetchRelatedFor ( $this );
2007-08-11 21:49:43 +04:00
}
} else {
$rel = $this -> _table -> getRelation ( $name );
$this -> _references [ $name ] = $rel -> fetchRelatedFor ( $this );
}
}
2007-09-04 05:23:02 +04:00
/**
* clearRelated
* unsets all the relationships this object has
*
* ( references to related objects still remain on Table objects )
*/
public function clearRelated ()
{
$this -> _references = array ();
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-08 01:21:18 +03:00
* Gets the current property values .
2007-01-19 23:47:24 +03:00
*
2008-02-08 01:21:18 +03:00
* @ return array The current properties and their values .
2007-01-19 23:47:24 +03:00
*/
2007-05-22 21:42:47 +04:00
public function getData ()
2007-01-19 23:47:24 +03:00
{
return $this -> _data ;
}
2008-01-05 22:55:56 +03:00
2008-02-08 01:21:18 +03:00
/**
*
*/
2008-01-05 22:55:56 +03:00
public function getValues ()
{
return $this -> _values ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* rawGet
* returns the value of a property , if the property is not yet loaded
* this method does NOT load it
*
* @ param $name name of the property
* @ throws Doctrine_Record_Exception if trying to get an unknown property
* @ return mixed
*/
2007-11-18 19:06:37 +03:00
public function rawGet ( $fieldName )
2007-01-19 23:47:24 +03:00
{
2007-11-18 19:06:37 +03:00
if ( ! isset ( $this -> _data [ $fieldName ])) {
throw new Doctrine_Record_Exception ( 'Unknown property ' . $fieldName );
2007-01-19 23:47:24 +03:00
}
2007-11-18 19:06:37 +03:00
if ( $this -> _data [ $fieldName ] === self :: $_null ) {
2007-01-19 23:47:24 +03:00
return null ;
2007-11-18 19:06:37 +03:00
}
2007-01-19 23:47:24 +03:00
2007-11-18 19:06:37 +03:00
return $this -> _data [ $fieldName ];
2007-01-19 23:47:24 +03:00
}
/**
* load
2007-11-19 13:00:44 +03:00
* loads all the uninitialized properties from the database
2007-01-19 23:47:24 +03:00
*
* @ return boolean
*/
public function load ()
{
// only load the data from database if the Doctrine_Record is in proxy state
if ( $this -> _state == Doctrine_Record :: STATE_PROXY ) {
$this -> refresh ();
$this -> _state = Doctrine_Record :: STATE_CLEAN ;
return true ;
}
return false ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* get
* returns a value of a property or a related component
*
* @ param mixed $name name of the property or related component
2007-06-05 02:38:39 +04:00
* @ param boolean $load whether or not to invoke the loading procedure
2007-01-19 23:47:24 +03:00
* @ throws Doctrine_Record_Exception if trying to get a value of unknown property / related component
* @ return mixed
*/
2007-11-18 19:06:37 +03:00
public function get ( $fieldName , $load = true )
2007-01-19 23:47:24 +03:00
{
2008-02-24 01:04:39 +03:00
/*// check for custom accessor , if not done yet .
if ( ! isset ( self :: $_accessorCache [ $this -> _entityName ][ $fieldName ])) {
if ( self :: $_useAutoAccessorOverride ) {
$getterMethod = 'get' . Doctrine :: classify ( $fieldName );
if ( method_exists ( $this , $getterMethod )) {
self :: $_accessorCache [ $this -> _entityName ][ $fieldName ] = $getterMethod ;
} else {
self :: $_accessorCache [ $this -> _entityName ][ $fieldName ] = false ;
}
}
if ( $getter = $this -> _table -> getCustomAccessor ( $fieldName )) {
self :: $_accessorCache [ $this -> _entityName ][ $fieldName ] = $getter ;
} else if ( ! isset ( self :: $_accessorCache [ $this -> _entityName ][ $fieldName ])) {
self :: $_accessorCache [ $this -> _entityName ][ $fieldName ] = false ;
}
}
// invoke custom accessor, if it exists.
if ( $getter = self :: $_accessorCache [ $this -> _entityName ][ $fieldName ]) {
return $this -> $getter ();
} */
// Use built-in accessor functionality
2007-07-23 22:27:00 +04:00
$value = self :: $_null ;
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _data [ $fieldName ])) {
2008-02-24 01:04:39 +03:00
if ( $this -> _data [ $fieldName ] !== self :: $_null ) {
return $this -> _data [ $fieldName ];
}
2007-11-18 19:06:37 +03:00
if ( $this -> _data [ $fieldName ] === self :: $_null && $load ) {
2007-01-19 23:47:24 +03:00
$this -> load ();
}
2007-11-18 19:06:37 +03:00
if ( $this -> _data [ $fieldName ] === self :: $_null ) {
2007-01-19 23:47:24 +03:00
$value = null ;
}
2007-05-24 00:26:21 +04:00
return $value ;
2007-01-19 23:47:24 +03:00
}
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _values [ $fieldName ])) {
return $this -> _values [ $fieldName ];
2007-01-19 23:47:24 +03:00
}
try {
2007-11-18 19:06:37 +03:00
if ( ! isset ( $this -> _references [ $fieldName ]) && $load ) {
$rel = $this -> _table -> getRelation ( $fieldName );
$this -> _references [ $fieldName ] = $rel -> fetchRelatedFor ( $this );
2007-01-19 23:47:24 +03:00
}
2007-11-18 19:06:37 +03:00
return $this -> _references [ $fieldName ];
2008-02-04 00:29:57 +03:00
} catch ( Doctrine_Relation_Exception $e ) {
2007-09-21 17:13:43 +04:00
foreach ( $this -> _table -> getFilters () as $filter ) {
2007-11-18 19:06:37 +03:00
if (( $value = $filter -> filterGet ( $this , $fieldName , $value )) !== null ) {
2007-09-21 17:13:43 +04:00
return $value ;
}
}
2007-01-19 23:47:24 +03:00
}
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* mapValue
* This simple method is used for mapping values to $values property .
* Usually this method is used internally by Doctrine for the mapping of
* aggregate values .
*
* @ param string $name the name of the mapped value
* @ param mixed $value mixed value to be mapped
* @ return void
2008-02-08 01:21:18 +03:00
* @ todo Maybe better placed in the Mapper .
2007-01-19 23:47:24 +03:00
*/
public function mapValue ( $name , $value )
{
$this -> _values [ $name ] = $value ;
}
2008-02-28 18:30:55 +03:00
public function getClassName ()
{
return $this -> _entityName ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* set
* method for altering properties and Doctrine_Record references
* if the load parameter is set to false this method will not try to load uninitialized record data
*
* @ param mixed $name name of the property or reference
* @ param mixed $value value of the property or reference
* @ param boolean $load whether or not to refresh / load the uninitialized record data
*
* @ throws Doctrine_Record_Exception if trying to set a value for unknown property / related component
* @ throws Doctrine_Record_Exception if trying to set a value of wrong type for related component
*
* @ return Doctrine_Record
*/
2007-11-18 19:06:37 +03:00
public function set ( $fieldName , $value , $load = true )
2008-01-11 16:53:30 +03:00
{
2008-01-05 22:55:56 +03:00
if ( isset ( $this -> _data [ $fieldName ])) {
2007-08-14 02:01:27 +04:00
if ( $value instanceof Doctrine_Record ) {
2007-11-18 19:06:37 +03:00
$type = $this -> _table -> getTypeOf ( $fieldName );
2007-01-19 23:47:24 +03:00
$id = $value -> getIncremented ();
2007-08-14 02:01:27 +04:00
if ( $id !== null && $type !== 'object' ) {
2007-01-19 23:47:24 +03:00
$value = $id ;
2007-01-23 19:27:20 +03:00
}
2007-01-19 23:47:24 +03:00
}
if ( $load ) {
2007-11-18 19:06:37 +03:00
$old = $this -> get ( $fieldName , $load );
2007-01-19 23:47:24 +03:00
} else {
2007-11-18 19:06:37 +03:00
$old = $this -> _data [ $fieldName ];
2007-01-19 23:47:24 +03:00
}
if ( $old !== $value ) {
2007-05-24 00:26:21 +04:00
if ( $value === null ) {
2007-05-18 13:22:31 +04:00
$value = self :: $_null ;
2007-05-24 00:26:21 +04:00
}
2007-05-24 00:41:03 +04:00
2007-11-18 19:06:37 +03:00
$this -> _data [ $fieldName ] = $value ;
$this -> _modified [] = $fieldName ;
2007-01-19 23:47:24 +03:00
switch ( $this -> _state ) {
case Doctrine_Record :: STATE_CLEAN :
$this -> _state = Doctrine_Record :: STATE_DIRTY ;
break ;
case Doctrine_Record :: STATE_TCLEAN :
$this -> _state = Doctrine_Record :: STATE_TDIRTY ;
break ;
2007-05-24 20:53:51 +04:00
}
2007-01-19 23:47:24 +03:00
}
} else {
try {
2008-01-05 22:55:56 +03:00
$this -> _coreSetRelated ( $fieldName , $value );
2008-02-04 00:29:57 +03:00
} catch ( Doctrine_Relation_Exception $e ) {
2007-09-21 17:48:31 +04:00
foreach ( $this -> _table -> getFilters () as $filter ) {
2007-11-18 19:06:37 +03:00
if (( $value = $filter -> filterSet ( $this , $fieldName , $value )) !== null ) {
2007-09-21 17:48:31 +04:00
return $value ;
}
}
2007-01-19 23:47:24 +03:00
}
}
}
2007-12-11 14:10:27 +03:00
2007-11-18 19:06:37 +03:00
/**
2008-02-08 01:21:18 +03:00
* Sets a related component .
2007-11-18 19:06:37 +03:00
* @ todo Refactor . What about composite keys ?
*/
2008-01-05 22:55:56 +03:00
private function _coreSetRelated ( $name , $value )
2007-01-19 23:47:24 +03:00
{
$rel = $this -> _table -> getRelation ( $name );
// one-to-many or one-to-one relation
if ( $rel instanceof Doctrine_Relation_ForeignKey ||
2007-06-05 02:38:39 +04:00
$rel instanceof Doctrine_Relation_LocalKey ) {
2007-01-19 23:47:24 +03:00
if ( ! $rel -> isOneToOne ()) {
// one-to-many relation found
if ( ! ( $value instanceof Doctrine_Collection )) {
2008-02-24 23:31:49 +03:00
throw new Doctrine_Record_Exception ( " Couldn't call Doctrine::set(), second "
. " argument should be an instance of Doctrine_Collection when "
. " setting one-to-many references. " );
2007-01-19 23:47:24 +03:00
}
2007-05-22 22:09:54 +04:00
if ( isset ( $this -> _references [ $name ])) {
$this -> _references [ $name ] -> setData ( $value -> getData ());
return $this ;
}
2007-01-19 23:47:24 +03:00
} else {
2007-06-07 21:04:56 +04:00
if ( $value !== self :: $_null ) {
2007-11-18 19:06:37 +03:00
$relatedTable = $value -> getTable ();
2008-01-05 22:55:56 +03:00
$foreignFieldName = $rel -> getForeignFieldName ();
$localFieldName = $rel -> getLocalFieldName ();
2007-12-11 14:10:27 +03:00
2007-06-07 21:04:56 +04:00
// one-to-one relation found
if ( ! ( $value instanceof Doctrine_Record )) {
2008-02-24 23:31:49 +03:00
throw new Doctrine_Record_Exception ( " Couldn't call Doctrine::set(), "
. " second argument should be an instance of Doctrine_Record "
. " or Doctrine_Null when setting one-to-one references. " );
2007-06-07 21:04:56 +04:00
}
if ( $rel instanceof Doctrine_Relation_LocalKey ) {
2008-02-24 23:31:49 +03:00
$idFieldNames = ( array ) $value -> getTable () -> getIdentifier ();
if ( ! empty ( $foreignFieldName ) && $foreignFieldName != $idFieldNames [ 0 ]) {
2007-11-18 19:06:37 +03:00
$this -> set ( $localFieldName , $value -> rawGet ( $foreignFieldName ), false );
} else {
$this -> set ( $localFieldName , $value , false );
}
2007-06-07 21:04:56 +04:00
} else {
2007-11-18 19:06:37 +03:00
$value -> set ( $foreignFieldName , $this , false );
}
2007-01-19 23:47:24 +03:00
}
}
2007-11-18 19:06:37 +03:00
} else if ( $rel instanceof Doctrine_Relation_Association ) {
2007-01-19 23:47:24 +03:00
// join table relation found
if ( ! ( $value instanceof Doctrine_Collection )) {
throw new Doctrine_Record_Exception ( " Couldn't call Doctrine::set(), second argument should be an instance of Doctrine_Collection when setting many-to-many references. " );
}
}
2007-05-22 01:06:17 +04:00
$this -> _references [ $name ] = $value ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* contains
*
* @ param string $name
* @ return boolean
*/
2007-11-18 19:06:37 +03:00
public function contains ( $fieldName )
2007-01-19 23:47:24 +03:00
{
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _data [ $fieldName ])) {
2007-01-19 23:47:24 +03:00
return true ;
}
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _id [ $fieldName ])) {
2007-01-19 23:47:24 +03:00
return true ;
}
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _values [ $fieldName ])) {
2007-12-11 14:10:27 +03:00
return true ;
2007-06-28 23:40:33 +04:00
}
2007-12-11 14:10:27 +03:00
if ( isset ( $this -> _references [ $fieldName ]) &&
2007-11-18 19:06:37 +03:00
$this -> _references [ $fieldName ] !== self :: $_null ) {
2007-06-07 21:04:56 +04:00
2007-01-19 23:47:24 +03:00
return true ;
}
return false ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* @ param string $name
* @ return void
*/
2008-02-14 23:20:35 +03:00
public function remove ( $fieldName )
2007-01-19 23:47:24 +03:00
{
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _data [ $fieldName ])) {
$this -> _data [ $fieldName ] = array ();
2007-12-09 20:46:28 +03:00
} else if ( isset ( $this -> _references [ $fieldName ])) {
2007-12-09 04:56:53 +03:00
if ( $this -> _references [ $fieldName ] instanceof Doctrine_Record ) {
// todo: delete related record when saving $this
$this -> _references [ $fieldName ] = self :: $_null ;
2008-01-05 22:55:56 +03:00
} else if ( $this -> _references [ $fieldName ] instanceof Doctrine_Collection ) {
2007-12-09 04:56:53 +03:00
$this -> _references [ $fieldName ] -> setData ( array ());
}
}
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-24 01:04:39 +03:00
* Applies the changes made to this object into database .
* This method also saves the related components .
2007-01-19 23:47:24 +03:00
*
* @ param Doctrine_Connection $conn optional connection parameter
* @ return void
*/
public function save ( Doctrine_Connection $conn = null )
{
2008-01-12 22:49:11 +03:00
$this -> _mapper -> save ( $this , $conn );
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-24 01:04:39 +03:00
* Tries to save the object and all its related objects .
2007-01-19 23:47:24 +03:00
* In contrast to Doctrine_Record :: save (), this method does not
* throw an exception when validation fails but returns TRUE on
* success or FALSE on failure .
2007-12-11 14:10:27 +03:00
*
2007-01-19 23:47:24 +03:00
* @ param Doctrine_Connection $conn optional connection parameter
* @ return TRUE if the record was saved sucessfully without errors , FALSE otherwise .
*/
public function trySave ( Doctrine_Connection $conn = null ) {
try {
$this -> save ( $conn );
return true ;
} catch ( Doctrine_Validator_Exception $ignored ) {
return false ;
}
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* replace
* Execute a SQL REPLACE query . A REPLACE query is identical to a INSERT
* query , except that if there is already a row in the table with the same
* key field values , the REPLACE query just updates its values instead of
* inserting a new row .
*
* The REPLACE type of query does not make part of the SQL standards . Since
* practically only MySQL and SQLIte implement it natively , this type of
* query isemulated through this method for other DBMS using standard types
* of queries inside a transaction to assure the atomicity of the operation .
*
* @ param Doctrine_Connection $conn optional connection parameter
* @ throws Doctrine_Connection_Exception if some of the key values was null
* @ throws Doctrine_Connection_Exception if there were no key fields
2007-11-10 16:21:40 +03:00
* @ throws Doctrine_Connection_Exception if something fails at database level
2007-01-19 23:47:24 +03:00
* @ return integer number of rows affected
*/
public function replace ( Doctrine_Connection $conn = null )
{
if ( $conn === null ) {
2008-01-05 22:55:56 +03:00
$conn = $this -> _mapper -> getConnection ();
2007-01-19 23:47:24 +03:00
}
2007-11-18 19:06:37 +03:00
return $conn -> replace ( $this -> _table , $this -> getPrepared (), $this -> _id );
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* returns an array of modified fields and associated values
* @ return array
2008-01-05 22:55:56 +03:00
* @ deprecated
2007-01-19 23:47:24 +03:00
*/
public function getModified ()
2008-01-05 22:55:56 +03:00
{
return $this -> getModifiedFields ();
}
/**
2008-02-24 01:04:39 +03:00
* Gets the names and values of all fields that have been modified since
* the entity was last synch ' d with the database .
2008-01-05 22:55:56 +03:00
*
* @ return array
*/
public function getModifiedFields ()
2007-01-19 23:47:24 +03:00
{
$a = array ();
foreach ( $this -> _modified as $k => $v ) {
$a [ $v ] = $this -> _data [ $v ];
}
return $a ;
}
2007-12-11 14:10:27 +03:00
2007-01-19 23:47:24 +03:00
/**
* getPrepared
*
* returns an array of modified fields and values with data preparation
* adds column aggregation inheritance and converts Records into primary key values
*
* @ param array $array
* @ return array
2007-11-18 19:06:37 +03:00
* @ todo What about a little bit more expressive name ? getPreparedData ?
2008-02-08 01:21:18 +03:00
* @ todo Maybe not the best place here ... need to think about it .
2007-01-19 23:47:24 +03:00
*/
2007-12-11 14:10:27 +03:00
public function getPrepared ( array $array = array ())
2007-07-26 00:45:25 +04:00
{
2008-02-24 01:04:39 +03:00
$dataSet = array ();
2007-01-19 23:47:24 +03:00
if ( empty ( $array )) {
2007-11-18 19:06:37 +03:00
$modifiedFields = $this -> _modified ;
2007-01-19 23:47:24 +03:00
}
2007-07-26 00:45:25 +04:00
2007-11-18 19:06:37 +03:00
foreach ( $modifiedFields as $field ) {
$type = $this -> _table -> getTypeOf ( $field );
2007-01-19 23:47:24 +03:00
2007-11-18 19:06:37 +03:00
if ( $this -> _data [ $field ] === self :: $_null ) {
2008-02-24 01:04:39 +03:00
$dataSet [ $field ] = null ;
2007-01-19 23:47:24 +03:00
continue ;
}
switch ( $type ) {
case 'array' :
case 'object' :
2008-02-24 01:04:39 +03:00
$dataSet [ $field ] = serialize ( $this -> _data [ $field ]);
2007-01-19 23:47:24 +03:00
break ;
case 'gzip' :
2008-02-24 01:04:39 +03:00
$dataSet [ $field ] = gzcompress ( $this -> _data [ $field ], 5 );
2007-01-19 23:47:24 +03:00
break ;
case 'boolean' :
2008-02-24 01:04:39 +03:00
$dataSet [ $field ] = $this -> getTable () -> getConnection () -> convertBooleans ( $this -> _data [ $field ]);
2007-01-19 23:47:24 +03:00
break ;
case 'enum' :
2008-02-24 01:04:39 +03:00
$dataSet [ $field ] = $this -> _table -> enumIndex ( $field , $this -> _data [ $field ]);
2007-01-19 23:47:24 +03:00
break ;
default :
2007-11-18 19:06:37 +03:00
if ( $this -> _data [ $field ] instanceof Doctrine_Record ) {
$this -> _data [ $field ] = $this -> _data [ $field ] -> getIncremented ();
2007-07-06 00:03:38 +04:00
}
2007-07-23 22:50:32 +04:00
/** TODO :
2007-07-23 22:27:00 +04:00
if ( $this -> _data [ $v ] === null ) {
throw new Doctrine_Record_Exception ( 'Unexpected null value.' );
}
2007-07-23 22:50:32 +04:00
*/
2007-01-19 23:47:24 +03:00
2008-02-24 01:04:39 +03:00
$dataSet [ $field ] = $this -> _data [ $field ];
2007-01-19 23:47:24 +03:00
}
}
2008-02-04 00:29:57 +03:00
// @todo cleanup
2008-02-08 01:21:18 +03:00
// populates the discriminator field in Single & Class Table Inheritance
2008-02-04 00:29:57 +03:00
if ( $this -> _table -> getInheritanceType () == Doctrine :: INHERITANCETYPE_JOINED ||
$this -> _table -> getInheritanceType () == Doctrine :: INHERITANCETYPE_SINGLE_TABLE ) {
$discCol = $this -> _table -> getInheritanceOption ( 'discriminatorColumn' );
$discMap = $this -> _table -> getInheritanceOption ( 'discriminatorMap' );
$old = $this -> get ( $discCol , false );
2008-02-24 01:04:39 +03:00
$discValue = array_search ( $this -> _entityName , $discMap );
if (( string ) $old !== ( string ) $discValue || $old === null ) {
$dataSet [ $discCol ] = $discValue ;
$this -> _data [ $discCol ] = $discValue ;
2007-01-19 23:47:24 +03:00
}
}
2008-02-24 01:04:39 +03:00
return $dataSet ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* count
* this class implements countable interface
*
2008-01-12 22:49:11 +03:00
* Implementation of the Countable interface .
*
2007-01-19 23:47:24 +03:00
* @ return integer the number of columns in this record
2008-02-08 01:21:18 +03:00
* @ todo IMHO this is unintuitive .
2007-01-19 23:47:24 +03:00
*/
public function count ()
{
return count ( $this -> _data );
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-08 01:21:18 +03:00
* Creates an array representation of the object ' s data .
2007-01-19 23:47:24 +03:00
*
2007-08-28 20:45:22 +04:00
* @ param boolean $deep - Return also the relations
2007-01-19 23:47:24 +03:00
* @ return array
*/
2007-11-27 21:23:13 +03:00
public function toArray ( $deep = true , $prefixKey = false )
2007-01-19 23:47:24 +03:00
{
$a = array ();
foreach ( $this as $column => $value ) {
2007-11-08 21:54:55 +03:00
if ( $value === self :: $_null || is_object ( $value )) {
2007-07-06 03:47:48 +04:00
$value = null ;
}
2007-01-19 23:47:24 +03:00
$a [ $column ] = $value ;
}
2007-11-27 21:23:13 +03:00
2008-02-24 01:04:39 +03:00
if ( $this -> _table -> getIdentifierType () == Doctrine :: IDENTIFIER_AUTOINC ) {
2008-02-24 23:31:49 +03:00
$idFieldNames = ( array ) $this -> _table -> getIdentifier ();
$id = $idFieldNames [ 0 ];
$a [ $id ] = $this -> getIncremented ();
2007-01-19 23:47:24 +03:00
}
2007-11-27 21:23:13 +03:00
2007-08-28 20:45:22 +04:00
if ( $deep ) {
foreach ( $this -> _references as $key => $relation ) {
2007-10-21 10:23:59 +04:00
if ( ! $relation instanceof Doctrine_Null ) {
2007-09-26 01:39:38 +04:00
$a [ $key ] = $relation -> toArray ( $deep , $prefixKey );
}
2007-08-28 20:45:22 +04:00
}
}
2007-11-27 21:23:13 +03:00
2008-01-17 16:26:31 +03:00
// [FIX] Prevent mapped Doctrine_Records from being displayed fully
foreach ( $this -> _values as $key => $value ) {
if ( $value instanceof Doctrine_Record ) {
$a [ $key ] = $value -> toArray ( $deep , $prefixKey );
} else {
$a [ $key ] = $value ;
}
}
return $a ;
2007-01-19 23:47:24 +03:00
}
2007-11-27 21:23:13 +03:00
/**
2008-02-24 01:04:39 +03:00
* Merges this record with an array of values
2007-11-27 21:23:13 +03:00
* or with another existing instance of this object
*
* @ param mixed $data Data to merge . Either another instance of this model or an array
* @ param bool $deep Bool value for whether or not to merge the data deep
* @ return void
*/
public function merge ( $data , $deep = true )
{
if ( $data instanceof $this ) {
$array = $data -> toArray ( $deep );
} else if ( is_array ( $data )) {
$array = $data ;
2008-01-05 22:55:56 +03:00
} else {
$array = array ();
2007-11-27 21:23:13 +03:00
}
return $this -> fromArray ( $array , $deep );
}
/**
* fromArray
*
* @ param string $array
* @ param bool $deep Bool value for whether or not to merge the data deep
* @ return void
*/
public function fromArray ( $array , $deep = true )
2007-09-22 01:40:54 +04:00
{
2007-09-22 05:32:48 +04:00
if ( is_array ( $array )) {
foreach ( $array as $key => $value ) {
2007-11-27 21:23:13 +03:00
if ( $this -> getTable () -> hasRelation ( $key ) && $deep ) {
$this -> $key -> fromArray ( $value , $deep );
2007-12-11 18:25:23 +03:00
} else if ( $this -> getTable () -> hasField ( $key )) {
2007-11-08 21:54:55 +03:00
$this -> set ( $key , $value );
2007-09-22 05:32:48 +04:00
}
2007-09-22 01:40:54 +04:00
}
2007-12-09 04:56:53 +03:00
}
}
/**
2008-01-23 03:54:58 +03:00
* synchronizeFromArray
2007-12-09 04:56:53 +03:00
* synchronizes a Doctrine_Record and its relations with data from an array
*
* it expects an array representation of a Doctrine_Record similar to the return
* value of the toArray () method . If the array contains relations it will create
* those that don ' t exist , update the ones that do , and delete the ones missing
* on the array but available on the Doctrine_Record
*
* @ param array $array representation of a Doctrine_Record
*/
2008-01-23 03:54:58 +03:00
public function synchronizeFromArray ( array $array )
2007-12-09 04:56:53 +03:00
{
foreach ( $array as $key => $value ) {
if ( $this -> getTable () -> hasRelation ( $key )) {
2008-01-23 11:04:54 +03:00
$this -> get ( $key ) -> synchronizeFromArray ( $value );
} else if ( $this -> getTable () -> hasColumn ( $key )) {
2007-12-09 04:56:53 +03:00
$this -> set ( $key , $value );
}
}
// eliminate relationships missing in the $array
foreach ( $this -> _references as $name => $obj ) {
2008-01-05 22:55:56 +03:00
if ( ! isset ( $array [ $name ])) {
2007-12-09 04:56:53 +03:00
unset ( $this -> $name );
}
2007-09-22 01:40:54 +04:00
}
}
2007-11-27 21:23:13 +03:00
/**
* exportTo
*
2007-12-11 14:10:27 +03:00
* @ param string $type
* @ param string $deep
2007-11-27 21:23:13 +03:00
* @ return void
*/
public function exportTo ( $type , $deep = true )
2007-09-27 02:36:32 +04:00
{
if ( $type == 'array' ) {
return $this -> toArray ( $deep );
} else {
return Doctrine_Parser :: dump ( $this -> toArray ( $deep , true ), $type );
}
}
2007-11-27 21:23:13 +03:00
/**
* importFrom
*
2007-12-11 14:10:27 +03:00
* @ param string $type
* @ param string $data
2007-11-27 21:23:13 +03:00
* @ return void
* @ author Jonathan H . Wage
*/
2007-09-27 02:36:32 +04:00
public function importFrom ( $type , $data )
{
if ( $type == 'array' ) {
return $this -> fromArray ( $data );
} else {
return $this -> fromArray ( Doctrine_Parser :: load ( $data , $type ));
}
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-08 01:21:18 +03:00
* Checks whether the entity already has a persistent state .
2007-01-19 23:47:24 +03:00
*
2008-02-08 01:21:18 +03:00
* @ return boolean TRUE if the object is managed and has persistent state , FALSE otherwise .
2007-01-19 23:47:24 +03:00
*/
public function exists ()
{
return ( $this -> _state !== Doctrine_Record :: STATE_TCLEAN &&
$this -> _state !== Doctrine_Record :: STATE_TDIRTY );
}
2007-10-21 10:23:59 +04:00
2007-06-13 16:31:03 +04:00
/**
2008-02-08 01:21:18 +03:00
* Checks whether the entity has been modified since it was last synchronized
* with the database .
2007-06-13 16:31:03 +04:00
*
2008-02-08 01:21:18 +03:00
* @ return boolean TRUE if the object has been modified , FALSE otherwise .
2007-06-13 16:31:03 +04:00
*/
public function isModified ()
{
return ( $this -> _state === Doctrine_Record :: STATE_DIRTY ||
$this -> _state === Doctrine_Record :: STATE_TDIRTY );
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* method for checking existence of properties and Doctrine_Record references
2008-02-08 01:21:18 +03:00
*
2007-01-19 23:47:24 +03:00
* @ param mixed $name name of the property or reference
* @ return boolean
*/
2007-11-18 19:06:37 +03:00
public function hasRelation ( $fieldName )
2007-01-19 23:47:24 +03:00
{
2007-11-18 19:06:37 +03:00
if ( isset ( $this -> _data [ $fieldName ]) || isset ( $this -> _id [ $fieldName ])) {
2007-01-19 23:47:24 +03:00
return true ;
}
2007-11-18 19:06:37 +03:00
return $this -> _table -> hasRelation ( $fieldName );
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* getIterator
* @ return Doctrine_Record_Iterator a Doctrine_Record_Iterator that iterates through the data
*/
public function getIterator ()
{
return new Doctrine_Record_Iterator ( $this );
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-08 01:21:18 +03:00
* Deletes the entity .
2007-01-19 23:47:24 +03:00
*
2008-02-24 01:04:39 +03:00
* Triggered events : onPreDelete , onDelete .
2007-01-19 23:47:24 +03:00
*
* @ return boolean true on success , false on failure
*/
public function delete ( Doctrine_Connection $conn = null )
{
2008-01-12 22:49:11 +03:00
return $this -> _mapper -> delete ( $this , $conn );
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
2008-02-08 01:21:18 +03:00
* Creates a copy of the entity .
2007-01-19 23:47:24 +03:00
*
* @ return Doctrine_Record
*/
2007-11-27 21:23:13 +03:00
public function copy ( $deep = true )
2007-01-19 23:47:24 +03:00
{
2007-09-03 18:57:18 +04:00
$data = $this -> _data ;
2007-08-04 01:02:17 +04:00
if ( $this -> _table -> getIdentifierType () === Doctrine :: IDENTIFIER_AUTOINC ) {
2008-02-24 23:31:49 +03:00
$idFieldNames = ( array ) $this -> _table -> getIdentifier ();
$id = $idFieldNames [ 0 ];
2007-08-04 01:02:17 +04:00
unset ( $data [ $id ]);
}
2008-01-05 22:55:56 +03:00
$ret = $this -> _mapper -> create ( $data );
2007-01-19 23:47:24 +03:00
$modified = array ();
2007-08-04 01:02:17 +04:00
foreach ( $data as $key => $val ) {
2007-04-13 22:06:48 +04:00
if ( ! ( $val instanceof Doctrine_Null )) {
2007-01-19 23:47:24 +03:00
$ret -> _modified [] = $key ;
}
2007-11-27 21:23:13 +03:00
}
2007-04-13 22:06:48 +04:00
2007-11-27 21:23:13 +03:00
if ( $deep ) {
foreach ( $this -> _references as $key => $value ) {
if ( $value instanceof Doctrine_Collection ) {
foreach ( $value as $record ) {
2008-02-08 01:27:29 +03:00
$ret -> { $key }[] = $record -> copy ( $deep );
2007-11-27 21:23:13 +03:00
}
} else {
2008-02-08 01:27:29 +03:00
$ret -> set ( $key , $value -> copy ( $deep ));
2007-04-12 22:32:07 +04:00
}
}
}
2007-11-27 21:23:13 +03:00
return $ret ;
2007-04-12 22:32:07 +04:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* assignIdentifier
*
* @ param integer $id
* @ return void
2008-02-08 01:21:18 +03:00
* @ todo Not sure this is the right place here .
2007-01-19 23:47:24 +03:00
*/
2007-05-27 22:56:04 +04:00
public function assignIdentifier ( $id = false )
2007-01-19 23:47:24 +03:00
{
if ( $id === false ) {
$this -> _id = array ();
2007-09-21 00:15:34 +04:00
$this -> _data = $this -> cleanData ( $this -> _data );
2007-01-19 23:47:24 +03:00
$this -> _state = Doctrine_Record :: STATE_TCLEAN ;
$this -> _modified = array ();
2008-01-05 22:55:56 +03:00
} else if ( $id === true ) {
2008-02-20 23:54:20 +03:00
$this -> _extractIdentifier ( true );
2007-01-19 23:47:24 +03:00
$this -> _state = Doctrine_Record :: STATE_CLEAN ;
$this -> _modified = array ();
} else {
2007-12-28 14:51:48 +03:00
if ( is_array ( $id )) {
foreach ( $id as $fieldName => $value ) {
$this -> _id [ $fieldName ] = $value ;
$this -> _data [ $fieldName ] = $value ;
}
} else {
2008-02-24 23:31:49 +03:00
$idFieldNames = ( array ) $this -> _table -> getIdentifier ();
$name = $idFieldNames [ 0 ];
2007-12-28 14:51:48 +03:00
$this -> _id [ $name ] = $id ;
$this -> _data [ $name ] = $id ;
}
$this -> _state = Doctrine_Record :: STATE_CLEAN ;
$this -> _modified = array ();
2007-01-19 23:47:24 +03:00
}
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* returns the primary keys of this object
*
* @ return array
*/
2007-07-06 03:21:29 +04:00
public function identifier ()
2007-01-19 23:47:24 +03:00
{
return $this -> _id ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* returns the value of autoincremented primary key of this object ( if any )
*
* @ return integer
2008-02-08 01:21:18 +03:00
* @ todo Better name ? Not sure this is the right place here .
2007-01-19 23:47:24 +03:00
*/
final public function getIncremented ()
{
$id = current ( $this -> _id );
2007-05-17 02:22:54 +04:00
if ( $id === false ) {
2007-01-19 23:47:24 +03:00
return null ;
2007-05-17 02:22:54 +04:00
}
2007-01-19 23:47:24 +03:00
return $id ;
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* hasRefence
* @ param string $name
* @ return boolean
*/
public function hasReference ( $name )
{
2007-05-22 01:06:17 +04:00
return isset ( $this -> _references [ $name ]);
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-09-21 17:48:31 +04:00
/**
* reference
*
* @ param string $name
*/
public function reference ( $name )
{
if ( isset ( $this -> _references [ $name ])) {
return $this -> _references [ $name ];
}
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* obtainReference
*
* @ param string $name
* @ throws Doctrine_Record_Exception if trying to get an unknown related component
*/
public function obtainReference ( $name )
{
2007-05-22 01:06:17 +04:00
if ( isset ( $this -> _references [ $name ])) {
return $this -> _references [ $name ];
2007-01-19 23:47:24 +03:00
}
2008-02-08 01:21:18 +03:00
throw new Doctrine_Record_Exception ( " Unknown reference $name . " );
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* getReferences
* @ return array all references
*/
public function getReferences ()
{
2007-05-22 01:06:17 +04:00
return $this -> _references ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* setRelated
*
* @ param string $alias
* @ param Doctrine_Access $coll
*/
final public function setRelated ( $alias , Doctrine_Access $coll )
{
2007-05-22 01:06:17 +04:00
$this -> _references [ $alias ] = $coll ;
2007-01-19 23:47:24 +03:00
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* loadReference
* loads a related component
*
* @ throws Doctrine_Table_Exception if trying to load an unknown related component
* @ param string $name
* @ return void
*/
2007-05-30 14:20:21 +04:00
public function loadReference ( $name )
2007-01-19 23:47:24 +03:00
{
2007-05-30 14:20:21 +04:00
$rel = $this -> _table -> getRelation ( $name );
$this -> _references [ $name ] = $rel -> fetchRelatedFor ( $this );
2007-01-19 23:47:24 +03:00
}
2007-06-27 20:22:41 +04:00
2007-01-19 23:47:24 +03:00
/**
* call
*
* @ param string | array $callback valid callback
* @ param string $column column name
* @ param mixed arg1 ... argN optional callback arguments
* @ return Doctrine_Record
*/
public function call ( $callback , $column )
{
$args = func_get_args ();
array_shift ( $args );
if ( isset ( $args [ 0 ])) {
2007-11-18 19:06:37 +03:00
$fieldName = $args [ 0 ];
$args [ 0 ] = $this -> get ( $fieldName );
2007-01-19 23:47:24 +03:00
$newvalue = call_user_func_array ( $callback , $args );
2007-11-18 19:06:37 +03:00
$this -> _data [ $fieldName ] = $newvalue ;
2007-01-19 23:47:24 +03:00
}
return $this ;
}
2007-10-21 10:23:59 +04:00
2007-02-08 15:53:32 +03:00
/**
* getter for node assciated with this record
*
* @ return mixed if tree returns Doctrine_Node otherwise returns false
2008-02-08 01:21:18 +03:00
* @ todo Should go to the NestedSet Behavior plugin .
2007-12-11 14:10:27 +03:00
*/
public function getNode ()
2007-04-13 22:06:48 +04:00
{
if ( ! $this -> _table -> isTree ()) {
return false ;
}
2007-02-08 15:53:32 +03:00
2007-04-13 22:06:48 +04:00
if ( ! isset ( $this -> _node )) {
$this -> _node = Doctrine_Node :: factory ( $this ,
2008-01-05 22:55:56 +03:00
$this -> getTable () -> getOption ( 'treeImpl' ),
$this -> getTable () -> getOption ( 'treeOptions' ));
2007-04-13 22:06:48 +04:00
}
2007-12-11 14:10:27 +03:00
2007-04-13 22:06:48 +04:00
return $this -> _node ;
2007-02-08 15:53:32 +03:00
}
2008-01-05 22:55:56 +03:00
2007-07-21 00:41:13 +04:00
/**
* revert
* reverts this record to given version , this method only works if versioning plugin
* is enabled
*
* @ throws Doctrine_Record_Exception if given version does not exist
* @ param integer $version an integer > 1
* @ return Doctrine_Record this object
2008-02-08 01:21:18 +03:00
* @ todo Should go to the Versionable plugin .
2007-07-21 00:41:13 +04:00
*/
2007-06-08 23:29:01 +04:00
public function revert ( $version )
{
2007-07-18 00:59:09 +04:00
$data = $this -> _table
2008-02-24 19:54:02 +03:00
-> getBehavior ( 'Doctrine_Template_Versionable' )
2007-07-18 00:59:09 +04:00
-> getAuditLog ()
-> getVersion ( $this , $version );
2007-07-21 00:41:13 +04:00
2007-07-18 23:31:43 +04:00
if ( ! isset ( $data [ 0 ])) {
2007-07-21 00:41:13 +04:00
throw new Doctrine_Record_Exception ( 'Version ' . $version . ' does not exist!' );
2007-07-18 23:31:43 +04:00
}
2007-06-08 23:29:01 +04:00
$this -> _data = $data [ 0 ];
2007-07-21 00:41:13 +04:00
return $this ;
2007-06-08 23:29:01 +04:00
}
2008-01-05 22:55:56 +03:00
2007-11-10 16:21:40 +03:00
public function unshiftFilter ( Doctrine_Record_Filter $filter )
{
return $this -> _table -> unshiftFilter ( $filter );
}
2008-01-05 22:55:56 +03:00
2007-08-12 01:35:58 +04:00
/**
2007-09-21 17:48:31 +04:00
* unlink
2007-08-15 00:30:33 +04:00
* removes links from this record to given records
2007-09-13 02:07:57 +04:00
* if no ids are given , it removes all links
2007-08-12 01:35:58 +04:00
*
2007-08-15 00:30:33 +04:00
* @ param string $alias related component alias
* @ param array $ids the identifiers of the related records
* @ return Doctrine_Record this object
2007-08-12 01:35:58 +04:00
*/
2007-09-13 02:07:57 +04:00
public function unlink ( $alias , $ids = array ())
2007-08-12 01:35:58 +04:00
{
$ids = ( array ) $ids ;
2007-12-11 14:10:27 +03:00
2007-08-12 01:35:58 +04:00
$q = new Doctrine_Query ();
$rel = $this -> getTable () -> getRelation ( $alias );
2007-08-15 00:30:33 +04:00
if ( $rel instanceof Doctrine_Relation_Association ) {
$q -> delete ()
-> from ( $rel -> getAssociationTable () -> getComponentName ())
2007-09-13 02:07:57 +04:00
-> where ( $rel -> getLocal () . ' = ?' , array_values ( $this -> identifier ()));
if ( count ( $ids ) > 0 ) {
$q -> whereIn ( $rel -> getForeign (), $ids );
}
2007-08-15 00:49:07 +04:00
$q -> execute ();
2007-11-18 19:06:37 +03:00
} else if ( $rel instanceof Doctrine_Relation_ForeignKey ) {
2007-08-15 01:20:00 +04:00
$q -> update ( $rel -> getTable () -> getComponentName ())
-> set ( $rel -> getForeign (), '?' , array ( null ))
2007-09-13 02:07:57 +04:00
-> addWhere ( $rel -> getForeign () . ' = ?' , array_values ( $this -> identifier ()));
if ( count ( $ids ) > 0 ) {
2008-02-24 23:31:49 +03:00
$relTableIdFieldNames = ( array ) $rel -> getTable () -> getIdentifier ();
$q -> whereIn ( $relTableIdFieldNames [ 0 ], $ids );
2007-09-13 02:07:57 +04:00
}
2007-08-15 01:20:00 +04:00
$q -> execute ();
}
if ( isset ( $this -> _references [ $alias ])) {
foreach ( $this -> _references [ $alias ] as $k => $record ) {
2008-01-05 22:55:56 +03:00
2007-08-15 01:20:00 +04:00
if ( in_array ( current ( $record -> identifier ()), $ids )) {
$this -> _references [ $alias ] -> remove ( $k );
2007-08-12 01:35:58 +04:00
}
2008-01-05 22:55:56 +03:00
2007-08-12 01:35:58 +04:00
}
2008-01-05 22:55:56 +03:00
2007-08-15 01:20:00 +04:00
$this -> _references [ $alias ] -> takeSnapshot ();
2007-08-12 01:35:58 +04:00
}
return $this ;
}
2007-10-21 10:23:59 +04:00
2007-12-11 14:10:27 +03:00
/**
* link
* creates links from this record to given records
*
* @ param string $alias related component alias
* @ param array $ids the identifiers of the related records
* @ return Doctrine_Record this object
*/
public function link ( $alias , array $ids )
{
if ( ! count ( $ids )) {
return $this ;
}
$identifier = array_values ( $this -> identifier ());
$identifier = array_shift ( $identifier );
$rel = $this -> getTable () -> getRelation ( $alias );
if ( $rel instanceof Doctrine_Relation_Association ) {
$modelClassName = $rel -> getAssociationTable () -> getComponentName ();
2007-12-11 14:31:13 +03:00
$localFieldName = $rel -> getLocalFieldName ();
2007-12-11 14:10:27 +03:00
$localFieldDef = $rel -> getAssociationTable () -> getColumnDefinition ( $localFieldName );
if ( $localFieldDef [ 'type' ] == 'integer' ) {
$identifier = ( integer ) $identifier ;
}
2007-12-11 14:31:13 +03:00
$foreignFieldName = $rel -> getForeignFieldName ();
2007-12-11 14:10:27 +03:00
$foreignFieldDef = $rel -> getAssociationTable () -> getColumnDefinition ( $foreignFieldName );
if ( $foreignFieldDef [ 'type' ] == 'integer' ) {
for ( $i = 0 ; $i < count ( $ids ); $i ++ ) {
$ids [ $i ] = ( integer ) $ids [ $i ];
}
}
foreach ( $ids as $id ) {
$record = new $modelClassName ;
$record [ $localFieldName ] = $identifier ;
$record [ $foreignFieldName ] = $id ;
$record -> save ();
}
} else if ( $rel instanceof Doctrine_Relation_ForeignKey ) {
$q = new Doctrine_Query ();
$q -> update ( $rel -> getTable () -> getComponentName ())
-> set ( $rel -> getForeign (), '?' , array_values ( $this -> identifier ()));
if ( count ( $ids ) > 0 ) {
2008-02-24 23:31:49 +03:00
$relTableIdFieldNames = ( array ) $rel -> getTable () -> getIdentifier ();
$q -> whereIn ( $relTableIdFieldNames [ 0 ], $ids );
2007-12-11 14:10:27 +03:00
}
$q -> execute ();
} else if ( $rel instanceof Doctrine_Relation_LocalKey ) {
$q = new Doctrine_Query ();
$q -> update ( $this -> getTable () -> getComponentName ())
2008-01-05 22:55:56 +03:00
-> set ( $rel -> getLocalFieldName (), '?' , $ids );
2007-12-11 14:10:27 +03:00
if ( count ( $ids ) > 0 ) {
2008-02-24 23:31:49 +03:00
$relTableIdFieldNames = ( array ) $rel -> getTable () -> getIdentifier ();
$q -> whereIn ( $relTableIdFieldNames [ 0 ], array_values ( $this -> identifier ()));
2007-12-11 14:10:27 +03:00
}
$q -> execute ();
}
return $this ;
}
2007-08-30 02:13:47 +04:00
/**
* __call
* this method is a magic method that is being used for method overloading
*
* the function of this method is to try to find given method from the templates
* this record is using and if it finds given method it will execute it
*
* So , in sense , this method replicates the usage of mixins ( as seen in some programming languages )
*
* @ param string $method name of the method
* @ param array $args method arguments
* @ return mixed the return value of the given method
*/
2007-12-11 14:10:27 +03:00
public function __call ( $method , $args )
2007-08-18 01:22:03 +04:00
{
2008-02-24 19:54:02 +03:00
if (( $behavior = $this -> _table -> getBehaviorForMethod ( $method )) !== false ) {
$behavior -> setInvoker ( $this );
return call_user_func_array ( array ( $behavior , $method ), $args );
2007-09-13 00:26:59 +04:00
}
2007-12-11 14:10:27 +03:00
2008-02-24 19:54:02 +03:00
foreach ( $this -> _table -> getBehaviors () as $behavior ) {
if ( method_exists ( $behavior , $method )) {
$behavior -> setInvoker ( $this );
$this -> _table -> addBehaviorMethod ( $method , $behavior );
return call_user_func_array ( array ( $behavior , $method ), $args );
2007-08-18 01:22:03 +04:00
}
}
2007-12-11 14:10:27 +03:00
2008-01-26 02:13:04 +03:00
throw new Doctrine_Record_Exception ( sprintf ( 'Unknown method %s::%s' , get_class ( $this ), $method ));
2007-08-18 01:22:03 +04:00
}
2007-10-21 10:23:59 +04:00
2007-02-08 15:53:32 +03:00
/**
* used to delete node from tree - MUST BE USE TO DELETE RECORD IF TABLE ACTS AS TREE
*
2008-02-08 01:21:18 +03:00
* @ todo Should go to the NestedSet Behavior plugin .
2007-12-11 14:10:27 +03:00
*/
2008-01-05 22:55:56 +03:00
public function deleteNode ()
{
2007-04-13 22:06:48 +04:00
$this -> getNode () -> delete ();
2007-02-08 15:53:32 +03:00
}
2008-01-05 22:55:56 +03:00
2007-05-24 17:01:58 +04:00
public function toString ()
{
return Doctrine :: dump ( get_object_vars ( $this ));
}
2007-10-21 10:23:59 +04:00
2007-01-19 23:47:24 +03:00
/**
* returns a string representation of this object
*/
public function __toString ()
{
2007-05-24 17:01:58 +04:00
return ( string ) $this -> _oid ;
2007-01-19 23:47:24 +03:00
}
2008-01-05 22:55:56 +03:00
2008-02-24 01:04:39 +03:00
/**
* Helps freeing the memory occupied by the entity .
* Cuts all references the entity has to other entities and removes the entity
* from the instance pool .
* Note : The entity is no longer useable after free () has been called . Any operations
* done with the entity afterwards can lead to unpredictable results .
*/
2008-01-05 22:55:56 +03:00
public function free ()
{
2008-02-29 22:33:31 +03:00
if ( $this -> _state != self :: STATE_LOCKED ) {
$this -> _mapper -> detach ( $this );
$this -> _mapper -> removeRecord ( $this );
$this -> _data = array ();
$this -> _id = array ();
if ( $deep ) {
foreach ( $this -> _references as $name => $reference ) {
if ( ! ( $reference instanceof Doctrine_Null )) {
$reference -> free ( $deep );
}
}
}
$this -> _references = array ();
}
2008-01-05 22:55:56 +03:00
}
2008-02-29 22:33:31 +03:00
2007-10-08 02:43:04 +04:00
}