TYPO3 API  SVNRelease
AbstractDomainObject.php
Go to the documentation of this file.
00001 <?php
00002 /***************************************************************
00003 *  Copyright notice
00004 *
00005 *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
00006 *  All rights reserved
00007 *
00008 *  This script is part of the TYPO3 project. The TYPO3 project is
00009 *  free software; you can redistribute it and/or modify
00010 *  it under the terms of the GNU General Public License as published by
00011 *  the Free Software Foundation; either version 2 of the License, or
00012 *  (at your option) any later version.
00013 *
00014 *  The GNU General Public License can be found at
00015 *  http://www.gnu.org/copyleft/gpl.html.
00016 *
00017 *  This script is distributed in the hope that it will be useful,
00018 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 *  GNU General Public License for more details.
00021 *
00022 *  This copyright notice MUST APPEAR in all copies of the script!
00023 ***************************************************************/
00024 
00025 /**
00026  * A generic Domain Object.
00027  *
00028  * All Model domain objects need to inherit from either AbstractEntity or AbstractValueObject, as this provides important framework information.
00029  *
00030  * @package Extbase
00031  * @subpackage DomainObject
00032  * @version $ID:$
00033  */
00034 abstract class Tx_Extbase_DomainObject_AbstractDomainObject implements Tx_Extbase_DomainObject_DomainObjectInterface, Tx_Extbase_Persistence_ObjectMonitoringInterface {
00035 
00036     /**
00037      * @var int The uid of the record. The uid is only unique in the context of the database table.
00038      */
00039     protected $uid;
00040 
00041     /**
00042      * @var int The uid of the localized record. In TYPO3 v4.x the property "uid" holds the uid of the record in default language (the translationOrigin).
00043      */
00044     protected $_localizedUid;
00045 
00046     /**
00047      * @var int The uid of the language of the object. In TYPO3 v4.x this is the uid of the language record in the table sys_language.
00048      */
00049     protected $_languageUid;
00050 
00051     /**
00052      * @var int The id of the page the record is "stored".
00053      */
00054     protected $pid;
00055 
00056     /**
00057      * TRUE if the object is a clone
00058      * @var boolean
00059      */
00060     private $_isClone = FALSE;
00061 
00062     /**
00063      * @var An array holding the clean property values. Set right after reconstitution of the object
00064      */
00065     private $_cleanProperties;
00066 
00067     /**
00068      * This is the magic __wakeup() method. It's invoked by the unserialize statement in the reconstitution process
00069      * of the object. If you want to implement your own __wakeup() method in your Domain Object you have to call
00070      * parent::__wakeup() first!
00071      *
00072      * @return void
00073      */
00074     public function __wakeup() {
00075         $this->initializeObject();
00076     }
00077 
00078     public function initializeObject() {
00079     }
00080 
00081     /**
00082      * Getter for uid.
00083      *
00084      * @return int the uid or NULL if none set yet.
00085      */
00086     final public function getUid() {
00087         if ($this->uid !== NULL) {
00088             return (int)$this->uid;
00089         } else {
00090             return NULL;
00091         }
00092     }
00093 
00094     /**
00095      * Setter for the pid.
00096      *
00097      * @return void
00098      */
00099     public function setPid($pid) {
00100         if ($pid === NULL) {
00101             $this->pid = NULL;
00102         } else {
00103             $this->pid = (int)$pid;
00104         }
00105     }
00106 
00107     /**
00108      * Getter for the pid.
00109      *
00110      * @return int The pid or NULL if none set yet.
00111      */
00112     public function getPid() {
00113         if ($this->pid === NULL) {
00114             return NULL;
00115         } else {
00116             return (int)$this->pid;
00117         }
00118     }
00119     
00120     /**
00121      * Reconstitutes a property. Only for internal use.
00122      *
00123      * @param string $propertyName
00124      * @param string $value
00125      * @return void
00126      */
00127     public function _setProperty($propertyName, $propertyValue) {
00128         if ($this->_hasProperty($propertyName)) {
00129             $this->$propertyName = $propertyValue;
00130             return TRUE;
00131         }
00132         return FALSE;
00133     }
00134 
00135     /**
00136      * Returns the property value of the given property name. Only for internal use.
00137      *
00138      * @return mixed The propertyValue
00139      */
00140     public function _getProperty($propertyName) {
00141         return $this->$propertyName;
00142     }
00143 
00144     /**
00145      * Returns a hash map of property names and property values. Only for internal use.
00146      *
00147      * @return array The properties
00148      */
00149     public function _getProperties() {
00150         $properties = get_object_vars($this);
00151         foreach ($properties as $propertyName => $propertyValue) {
00152             if (substr($propertyName, 0, 1) === '_') {
00153                 unset($properties[$propertyName]);
00154             }
00155         }
00156         return $properties;
00157     }
00158     
00159     /**
00160      * Returns the property value of the given property name. Only for internal use.
00161      *
00162      * @return boolean TRUE bool true if the property exists, FALSE if it doesn't exist or
00163      * NULL in case of an error.
00164      */
00165     public function _hasProperty($propertyName) {
00166         return property_exists($this, $propertyName);
00167     }
00168 
00169     /**
00170      * Returns TRUE if the object is new (the uid was not set, yet). Only for internal use
00171      *
00172      * @return boolean
00173      */
00174     public function _isNew() {
00175         return $this->uid === NULL;
00176     }
00177 
00178     /**
00179      * Register an object's clean state, e.g. after it has been reconstituted
00180      * from the database.
00181      *
00182      * @param string $propertyName The name of the property to be memorized. If omitted all persistable properties are memorized.
00183      * @return void
00184      */
00185     public function _memorizeCleanState($propertyName = NULL) {
00186         if ($propertyName !== NULL) {
00187             $this->_memorizePropertyCleanState($propertyName);
00188         } else {
00189             $this->_cleanProperties = array();
00190             $properties = get_object_vars($this);
00191             foreach ($properties as $propertyName => $propertyValue) {
00192                 if (substr($propertyName, 0, 1) === '_') continue; // Do not memorize "internal" properties
00193                 $this->_memorizePropertyCleanState($propertyName);
00194             }
00195         }
00196     }
00197 
00198     /**
00199      * Register an properties's clean state, e.g. after it has been reconstituted
00200      * from the database.
00201      *
00202      * @param string $propertyName The name of the property to be memorized. If omittet all persistable properties are memorized.
00203      * @return void
00204      */
00205     public function _memorizePropertyCleanState($propertyName) {
00206         $propertyValue = $this->$propertyName;
00207         if (!is_array($this->_cleanProperties)) {
00208             $this->_cleanProperties = array();
00209         }
00210         if (is_object($propertyValue)) {
00211             $this->_cleanProperties[$propertyName] = clone($propertyValue);
00212 
00213             // We need to make sure the clone and the original object
00214             // are identical when compared with == (see _isDirty()).
00215             // After the cloning, the Domain Object will have the property
00216             // "isClone" set to TRUE, so we manually have to set it to FALSE
00217             // again. Possible fix: Somehow get rid of the "isClone" property,
00218             // which is currently needed in Fluid.
00219             if ($propertyValue instanceof Tx_Extbase_DomainObject_AbstractDomainObject) {
00220                 $this->_cleanProperties[$propertyName]->_setClone(FALSE);
00221             }
00222         } else {
00223             $this->_cleanProperties[$propertyName] = $propertyValue;
00224         }
00225     }
00226 
00227     /**
00228      * Returns a hash map of clean properties and $values.
00229      *
00230      * @return array
00231      */
00232     public function _getCleanProperties() {
00233         return $this->_cleanProperties;
00234     }
00235 
00236     /**
00237      * Returns the clean value of the given property. The returned value will be NULL if the clean state was not memorized before, or
00238      * if the clean value is NULL.
00239      *
00240      * @param string $propertyName The name of the property to be memorized. If omittet all persistable properties are memorized.
00241      * @return mixed The clean property value or NULL
00242      */
00243     public function _getCleanProperty($propertyName) {
00244         if (is_array($this->_cleanProperties)) {
00245             return isset($this->_cleanProperties[$propertyName]) ? $this->_cleanProperties[$propertyName] : NULL;
00246         } else {
00247             return NULL;
00248         }
00249     }
00250     
00251     /**
00252      * Returns TRUE if the properties were modified after reconstitution
00253      *
00254      * @param string $propertyName An optional name of a property to be checked if its value is dirty
00255      * @return boolean
00256      */
00257     public function _isDirty($propertyName = NULL) {
00258         if ($this->uid !== NULL && is_array($this->_cleanProperties) && $this->uid != $this->_getCleanProperty('uid')) throw new Tx_Extbase_Persistence_Exception_TooDirty('The uid "' . $this->uid . '" has been modified, that is simply too much.', 1222871239);
00259         if ($propertyName === NULL) {
00260             foreach ($this->_getCleanProperties() as $propertyName => $cleanPropertyValue) {
00261                 if ($this->isPropertyDirty($cleanPropertyValue, $this->$propertyName) === TRUE) return TRUE;
00262             }
00263         } else {
00264             if ($this->isPropertyDirty($this->_getCleanProperty($propertyName), $this->$propertyName) === TRUE) return TRUE;
00265         }
00266         return FALSE;
00267     }
00268 
00269     /**
00270      * Checks the $value against the $cleanState.
00271      *
00272      * @param mixed $previousValue
00273      * @param mixed $currentValue
00274      * @return boolan
00275      */
00276     protected function isPropertyDirty($previousValue, $currentValue) {
00277         $result = FALSE;
00278         // In case it is an object and it implements the ObjectMonitoringInterface, we call _isDirty() instead of a simple comparison of objects.
00279         // We do this, because if the object itself contains a lazy loaded property, the comparison of the objects might fail even if the object didn't change
00280         if (is_object($currentValue)) {
00281             if ($currentValue instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
00282                 $result = !is_object($previousValue) || (get_class($previousValue) !== get_class($currentValue)) || ($currentValue->getUid() !== $previousValue->getUid());
00283             } elseif ($currentValue instanceof Tx_Extbase_Persistence_ObjectMonitoringInterface) {
00284                 $result = !is_object($previousValue) || $currentValue->_isDirty() || (get_class($previousValue) !== get_class($currentValue));
00285             } else {
00286                 // For all other objects we do only a simple comparison (!=) as we want cloned objects to return the same values.
00287                 $result = ($previousValue != $currentValue);
00288             }
00289         } else {
00290             $result = ($previousValue !== $currentValue);
00291         }
00292         return $result;
00293     }
00294     
00295     /**
00296      * Returns TRUE if the object has been clonesd, cloned, FALSE otherwise.
00297      *
00298      * @return boolean TRUE if the object has been cloned
00299      */
00300     public function _isClone() {
00301         return $this->_isClone;
00302     }
00303 
00304     /**
00305      * Setter whether this Domain Object is a clone of another one.
00306      * NEVER SET THIS PROPERTY DIRECTLY. We currently need it to make the
00307      * _isDirty check inside AbstractEntity work, but it is just a work-
00308      * around right now.
00309      *
00310      * @param boolean $clone
00311      */
00312     public function _setClone($clone) {
00313         $this->_isClone = (boolean)$clone;
00314     }
00315 
00316     /**
00317      * Clone method. Sets the _isClone property.
00318      *
00319      * @return void
00320      */
00321     public function __clone() {
00322         $this->_isClone = TRUE;
00323     }
00324 
00325     /**
00326      * Returns the class name and the uid of the object as string
00327      *
00328      * @return string
00329      */
00330     public function __toString() {
00331         return get_class($this) . ':' . (string)$this->uid;
00332     }
00333 
00334 }
00335 ?>