TYPO3 API  SVNRelease
Backend.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 class is a backport of the corresponding class of FLOW3.
00009 *  All credits go to the v5 team.
00010 *
00011 *  This script is part of the TYPO3 project. The TYPO3 project is
00012 *  free software; you can redistribute it and/or modify
00013 *  it under the terms of the GNU General Public License as published by
00014 *  the Free Software Foundation; either version 2 of the License, or
00015 *  (at your option) any later version.
00016 *
00017 *  The GNU General Public License can be found at
00018 *  http://www.gnu.org/copyleft/gpl.html.
00019 *
00020 *  This script is distributed in the hope that it will be useful,
00021 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 *  GNU General Public License for more details.
00024 *
00025 *  This copyright notice MUST APPEAR in all copies of the script!
00026 ***************************************************************/
00027 
00028 /**
00029  * A persistence backend. This backend maps objects to the relational model of the storage backend.
00030  * It persists all added, removed and changed objects.
00031  *
00032  * @package Extbase
00033  * @subpackage Persistence
00034  * @version $Id: Backend.php 2292 2010-05-25 11:11:04Z jocrau $
00035  */
00036 class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendInterface, t3lib_Singleton {
00037 
00038     /**
00039      * @var Tx_Extbase_Persistence_Session
00040      */
00041     protected $session;
00042 
00043     /**
00044      * @var Tx_Extbase_Persistence_ObjectStorage
00045      */
00046     protected $aggregateRootObjects;
00047 
00048     /**
00049      * @var Tx_Extbase_Persistence_ObjectStorage
00050      */
00051     protected $visitedDuringPersistence;
00052 
00053     /**
00054      * @var Tx_Extbase_Persistence_IdentityMap
00055      **/
00056     protected $identityMap;
00057 
00058     /**
00059      * @var Tx_Extbase_Reflection_Service
00060      */
00061     protected $reflectionService;
00062 
00063     /**
00064      * @var Tx_Extbase_Persistence_QueryFactoryInterface
00065      */
00066     protected $queryFactory;
00067 
00068     /**
00069      * @var Tx_Extbase_Persistence_QOM_QueryObjectModelFactory
00070      */
00071     protected $qomFactory;
00072 
00073     /**
00074      * @var Tx_Extbase_Persistence_Storage_BackendInterface
00075      */
00076     protected $storageBackend;
00077 
00078     /**
00079      * @var Tx_Extbase_Persistence_DataMapper
00080      */
00081     protected $dataMapper;
00082 
00083     /**
00084      * The TYPO3 reference index object
00085      *
00086      * @var t3lib_refindex
00087      **/
00088     protected $referenceIndex;
00089 
00090     /**
00091      * @var Tx_Extbase_Configuration_ConfigurationManagerInterface
00092      */
00093     protected $configurationManager;
00094 
00095     /**
00096      * Constructs the backend
00097      *
00098      * @return void
00099      */
00100     public function __construct(Tx_Extbase_Configuration_ConfigurationManagerInterface $configurationManager) {
00101         $this->configurationManager = $configurationManager;
00102         $frameworkConfiguration = $configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
00103         if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
00104             $this->referenceIndex = t3lib_div::makeInstance('t3lib_refindex');
00105         }
00106     }
00107 
00108     /**
00109      * @param Tx_Extbase_Persistence_Session $session
00110      * @return void
00111      */
00112     public function injectSession(Tx_Extbase_Persistence_Session $session) {
00113         $this->session = $session;
00114     }
00115 
00116     /**
00117      * @param Tx_Extbase_Persistence_Storage_BackendInterface $storageBackend
00118      * @return void
00119      */
00120     public function injectStorageBackend(Tx_Extbase_Persistence_Storage_BackendInterface $storageBackend) {
00121         $this->storageBackend = $storageBackend;
00122     }
00123 
00124     /**
00125      * Injects the DataMapper to map nodes to objects
00126      *
00127      * @param Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper
00128      * @return void
00129      */
00130     public function injectDataMapper(Tx_Extbase_Persistence_Mapper_DataMapper $dataMapper) {
00131         $this->dataMapper = $dataMapper;
00132     }
00133 
00134     /**
00135      * Injects the identity map
00136      *
00137      * @param Tx_Extbase_Persistence_IdentityMap $identityMap
00138      * @return void
00139      */
00140     public function injectIdentityMap(Tx_Extbase_Persistence_IdentityMap $identityMap) {
00141         $this->identityMap = $identityMap;
00142     }
00143 
00144     /**
00145      * Injects the Reflection Service
00146      *
00147      * @param Tx_Extbase_Reflection_Service
00148      * @return void
00149      */
00150     public function injectReflectionService(Tx_Extbase_Reflection_Service $reflectionService) {
00151         $this->reflectionService = $reflectionService;
00152     }
00153 
00154     /**
00155      * Injects the QueryFactory
00156      *
00157      * @param Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory
00158      * @return void
00159      */
00160     public function injectQueryFactory(Tx_Extbase_Persistence_QueryFactoryInterface $queryFactory) {
00161         $this->queryFactory = $queryFactory;
00162     }
00163 
00164     /**
00165      * Injects the QueryObjectModelFactory
00166      *
00167      * @param Tx_Extbase_Persistence_QOM_QueryObjectModelFactory $qomFactory
00168      * @return void
00169      */
00170     public function injectQomFactory(Tx_Extbase_Persistence_QOM_QueryObjectModelFactory $qomFactory) {
00171         $this->qomFactory = $qomFactory;
00172     }
00173 
00174     /**
00175      * Returns the repository session
00176      *
00177      * @return Tx_Extbase_Persistence_Session
00178      */
00179     public function getSession() {
00180         return $this->session;
00181     }
00182 
00183     /**
00184      * Returns the Data Mapper
00185      *
00186      * @return Tx_Extbase_Persistence_Mapper_DataMapper
00187      */
00188     public function getDataMapper() {
00189         return $this->dataMapper;
00190     }
00191 
00192     /**
00193      * Returns the current QOM factory
00194      *
00195      * @return Tx_Extbase_Persistence_QOM_QueryObjectModelFactory
00196      */
00197     public function getQomFactory() {
00198         return $this->qomFactory;
00199     }
00200 
00201     /**
00202      * Returns the current identityMap
00203      *
00204      * @return Tx_Extbase_Persistence_IdentityMap
00205      */
00206     public function getIdentityMap() {
00207         return $this->identityMap;
00208     }
00209 
00210     /**
00211      * Returns the reflection service
00212      *
00213      * @return Tx_Extbase_Reflection_Service
00214      */
00215     public function getReflectionService() {
00216         return $this->reflectionService;
00217     }
00218 
00219     /**
00220      * Returns the number of records matching the query.
00221      *
00222      * @param Tx_Extbase_Persistence_QueryInterface $query
00223      * @return integer
00224      * @api
00225      */
00226     public function getObjectCountByQuery(Tx_Extbase_Persistence_QueryInterface $query) {
00227         return $this->storageBackend->getObjectCountByQuery($query);
00228     }
00229 
00230     /**
00231      * Returns the object data matching the $query.
00232      *
00233      * @param Tx_Extbase_Persistence_QueryInterface $query
00234      * @return array
00235      * @api
00236      */
00237     public function getObjectDataByQuery(Tx_Extbase_Persistence_QueryInterface $query) {
00238         return $this->storageBackend->getObjectDataByQuery($query);
00239     }
00240 
00241     /**
00242      * Returns the (internal) identifier for the object, if it is known to the
00243      * backend. Otherwise NULL is returned.
00244      *
00245      * @param object $object
00246      * @return string The identifier for the object if it is known, or NULL
00247      */
00248     public function getIdentifierByObject($object) {
00249         if ($object instanceof Tx_Extbase_Persistence_LazyLoadingProxy) {
00250             $object = $object->_loadRealInstance();
00251             if (!is_object($object)) {
00252                 return NULL;
00253             }
00254         }
00255         if ($this->identityMap->hasObject($object)) {
00256             return $this->identityMap->getIdentifierByObject($object);
00257         } else {
00258             return NULL;
00259         }
00260     }
00261 
00262     /**
00263      * Returns the object with the (internal) identifier, if it is known to the
00264      * backend. Otherwise NULL is returned.
00265      *
00266      * @param string $identifier
00267      * @param string $className
00268      * @return object The object for the identifier if it is known, or NULL
00269      */
00270     public function getObjectByIdentifier($identifier, $className) {
00271         if ($this->identityMap->hasIdentifier($identifier, $className)) {
00272             return $this->identityMap->getObjectByIdentifier($identifier, $className);
00273         } else {
00274             $query = $this->queryFactory->create($className);
00275             return $query->matching(
00276                 $query->withUid($identifier))
00277                 ->execute()
00278                 ->getFirst();
00279         }
00280     }
00281 
00282     /**
00283      * Checks if the given object has ever been persisted.
00284      *
00285      * @param object $object The object to check
00286      * @return boolean TRUE if the object is new, FALSE if the object exists in the repository
00287      */
00288     public function isNewObject($object) {
00289         return ($this->getIdentifierByObject($object) === NULL);
00290     }
00291 
00292     /**
00293      * Replaces the given object by the second object.
00294      *
00295      * This method will unregister the existing object at the identity map and
00296      * register the new object instead. The existing object must therefore
00297      * already be registered at the identity map which is the case for all
00298      * reconstituted objects.
00299      *
00300      * The new object will be identified by the uid which formerly belonged
00301      * to the existing object. The existing object looses its uid.
00302      *
00303      * @param object $existingObject The existing object
00304      * @param object $newObject The new object
00305      * @return void
00306      */
00307     public function replaceObject($existingObject, $newObject) {
00308         $existingUid = $this->getIdentifierByObject($existingObject);
00309         if ($existingUid === NULL) throw new Tx_Extbase_Persistence_Exception_UnknownObject('The given object is unknown to this persistence backend.', 1238070163);
00310 
00311         $this->identityMap->unregisterObject($existingObject);
00312         $this->identityMap->registerObject($newObject, $existingUid);
00313     }
00314 
00315     /**
00316      * Sets the aggregate root objects
00317      *
00318      * @param Tx_Extbase_Persistence_ObjectStorage $objects
00319      * @return void
00320      */
00321     public function setAggregateRootObjects(Tx_Extbase_Persistence_ObjectStorage $objects) {
00322         $this->aggregateRootObjects = $objects;
00323     }
00324 
00325     /**
00326      * Sets the deleted objects
00327      *
00328      * @param Tx_Extbase_Persistence_ObjectStorage $objects
00329      * @return void
00330      */
00331     public function setDeletedObjects(Tx_Extbase_Persistence_ObjectStorage $objects) {
00332         $this->deletedObjects = $objects;
00333     }
00334 
00335     /**
00336      * Commits the current persistence session.
00337      *
00338      * @return void
00339      */
00340     public function commit() {
00341         $this->persistObjects();
00342         $this->processDeletedObjects();
00343     }
00344 
00345     /**
00346      * Traverse and persist all aggregate roots and their object graph.
00347      *
00348      * @return void
00349      */
00350     protected function persistObjects() {
00351         $this->visitedDuringPersistence = new Tx_Extbase_Persistence_ObjectStorage();
00352         foreach ($this->aggregateRootObjects as $object) {
00353             if (!$this->identityMap->hasObject($object)) {
00354                 $this->insertObject($object);
00355             }
00356         }
00357         foreach ($this->aggregateRootObjects as $object) {
00358             $this->persistObject($object);
00359         }
00360     }
00361 
00362     /**
00363      * Persists the given object.
00364      *
00365      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be inserted
00366      * @return void
00367      */
00368     protected function persistObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
00369         if (isset($this->visitedDuringPersistence[$object])) {
00370             return;
00371         }
00372         $row = array();
00373         $queue = array();
00374         $dataMap = $this->dataMapper->getDataMap(get_class($object));
00375         $properties = $object->_getProperties();
00376         foreach ($properties as $propertyName => $propertyValue) {
00377             if (!$dataMap->isPersistableProperty($propertyName) || $this->propertyValueIsLazyLoaded($propertyValue)) continue;
00378             $columnMap = $dataMap->getColumnMap($propertyName);
00379             if ($propertyValue instanceof Tx_Extbase_Persistence_ObjectStorage) {
00380                 if ($object->_isNew() || $propertyValue->_isDirty()) {
00381                     $this->persistObjectStorage($propertyValue, $object, $propertyName, $row);
00382                 }
00383                 foreach ($propertyValue as $containedObject) {
00384                     if ($containedObject instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
00385                         $queue[] = $containedObject;
00386                     }
00387                 }
00388             } elseif ($propertyValue instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
00389                 if ($object->_isDirty($propertyName)) {
00390                     if ($propertyValue->_isNew()) {
00391                         $this->insertObject($propertyValue);
00392                     }
00393                     $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
00394                 }
00395                 $queue[] = $propertyValue;
00396             } elseif ($object->_isNew() || $object->_isDirty($propertyName)) {
00397                 $row[$columnMap->getColumnName()] = $this->getPlainValue($propertyValue);
00398             }
00399         }
00400         if (count($row) > 0) {
00401             $this->updateObject($object, $row);
00402             $object->_memorizeCleanState();
00403         }
00404         $this->visitedDuringPersistence[$object] = $object->getUid();
00405         foreach ($queue as $queuedObject) {
00406             $this->persistObject($queuedObject);
00407         }
00408     }
00409 
00410     /**
00411      * Checks, if the property value is lazy loaded and was not initialized
00412      *
00413      * @param mixed $propertyValue The property value
00414      * @return bool
00415      */
00416     protected function propertyValueIsLazyLoaded($propertyValue) {
00417         if ($propertyValue instanceof Tx_Extbase_Persistence_LazyLoadingProxy) return TRUE;
00418         if ($propertyValue instanceof Tx_Extbase_Persistence_LazyObjectStorage) {
00419             if ($propertyValue->isInitialized() === FALSE) {
00420                 return TRUE;
00421             }
00422         }
00423         return FALSE;
00424     }
00425 
00426     /**
00427      * Persists a an object storage. Objects of a 1:n or m:n relation are queued and processed with the parent object. A 1:1 relation
00428      * gets persisted immediately. Objects which were removed from the property were detached from the parent object. They will not be
00429      * deleted by default. You have to annotate the property with "@cascade remove" if you want them to be deleted as well.
00430      *
00431      * @param Tx_Extbase_Persistence_ObjectStorage $objectStorage The object storage to be persisted.
00432      * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The parent object. One of the properties holds the object storage.
00433      * @param string $propertyName The name of the property holding the object storage.
00434      * @param array $row The row array of the parent object to be persisted. It's passed by reference and gets filled with either a comma separated list of uids (csv) or the number of contained objects. 
00435      * @return void
00436      */
00437     protected function persistObjectStorage(Tx_Extbase_Persistence_ObjectStorage $objectStorage, Tx_Extbase_DomainObject_DomainObjectInterface $parentObject, $propertyName, array &$row) {
00438         $className = get_class($parentObject);
00439         $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName);
00440         $columnName = $columnMap->getColumnName();
00441         $propertyMetaData = $this->reflectionService->getClassSchema($className)->getProperty($propertyName);
00442 
00443         foreach ($this->getRemovedChildObjects($parentObject, $propertyName) as $removedObject) {
00444             if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY && $propertyMetaData['cascade'] === 'remove') {
00445                 $this->removeObject($removedObject);
00446             } else {
00447                 $this->detachObjectFromParentObject($removedObject, $parentObject, $propertyName);
00448             }
00449         }
00450 
00451         if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
00452             $this->deleteAllRelationsFromRelationtable($parentObject, $propertyName);
00453         }
00454 
00455         $currentUids = array();
00456         $sortingPosition = 1;
00457         foreach ($objectStorage as $object) {
00458             if ($object->_isNew()) {
00459                 $this->insertObject($object);
00460             }
00461             $currentUids[] = $object->getUid();
00462             $this->attachObjectToParentObject($object, $parentObject, $propertyName, $sortingPosition);
00463             $sortingPosition++;
00464         }
00465 
00466         if ($columnMap->getParentKeyFieldName() === NULL) {
00467             $row[$columnMap->getColumnName()] = implode(',', $currentUids);
00468         } else {
00469             $row[$columnMap->getColumnName()] = $this->dataMapper->countRelated($parentObject, $propertyName);
00470         }
00471     }
00472 
00473     /**
00474      * Returns the current field value of the given object property from the storage backend.
00475      *
00476      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object
00477      * @param string $propertyName The property name
00478      * @return mixed The field value
00479      */
00480     protected function getCurrentFieldValue(Tx_Extbase_DomainObject_DomainObjectInterface $object, $propertyName) {
00481         $className = get_class($object);
00482         $columnMap = $this->dataMapper->getDataMap($className)->getColumnMap($propertyName);
00483         $query = $this->queryFactory->create($className);
00484         $query->getQuerySettings()->setReturnRawQueryResult(TRUE);
00485         $currentRow = $query->matching(
00486             $query->withUid($object->getUid()))
00487             ->execute()
00488             ->getFirst();
00489         $fieldValue = $currentRow[$columnMap->getColumnName()];
00490         return $fieldValue;
00491     }
00492 
00493     /**
00494      * Returns the removed objects determined by a comparison of the clean property value
00495      * with the actual property value.
00496      *
00497      * @param Tx_Extbase_DomainObject_AbstractEntity $object The object
00498      * @param string $parentPropertyName The name of the property
00499      * @return array An array of removed objects
00500      */
00501     protected function getRemovedChildObjects(Tx_Extbase_DomainObject_AbstractEntity $object, $propertyName) {
00502         $removedObjects = array();
00503         $cleanPropertyValue = $object->_getCleanProperty($propertyName);
00504         if (is_array($cleanPropertyValue) || $cleanPropertyValue instanceof Iterator) {
00505             $propertyValue = $object->_getProperty($propertyName);
00506             foreach ($cleanPropertyValue as $containedObject) {
00507                 if (!$propertyValue->contains($containedObject)) {
00508                     $removedObjects[] = $containedObject;
00509                 }
00510             }
00511         }
00512         return $removedObjects;
00513     }
00514 
00515     /**
00516      * Updates the fields defining the relation between the object and the parent object.
00517      *
00518      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
00519      * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject
00520      * @param string $parentPropertyName
00521      * @return void
00522      */
00523     protected function attachObjectToParentObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, Tx_Extbase_DomainObject_AbstractEntity $parentObject, $parentPropertyName, $sortingPosition = 0) {
00524         $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
00525         $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
00526         if ($parentColumnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
00527             $row = array();
00528             $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
00529             if ($parentKeyFieldName !== NULL) {
00530                 $row[$parentKeyFieldName] = $parentObject->getUid();
00531                 $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
00532                 if ($parentTableFieldName !== NULL) {
00533                     $row[$parentTableFieldName] = $parentDataMap->getTableName();
00534                 }
00535             }
00536             $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
00537             if (!empty($childSortByFieldName)) {
00538                 $row[$childSortByFieldName] = $sortingPosition;
00539             }
00540             if (count($row) > 0) {
00541                 $this->updateObject($object, $row);
00542             }
00543         } elseif ($parentColumnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
00544             $this->insertRelationInRelationtable($object, $parentObject, $parentPropertyName, $sortingPosition);
00545         }
00546     }
00547 
00548     /**
00549      * Updates the fields defining the relation between the object and the parent object.
00550      *
00551      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
00552      * @param Tx_Extbase_DomainObject_AbstractEntity $parentObject
00553      * @param string $parentPropertyName
00554      * @return void
00555      */
00556     protected function detachObjectFromParentObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, Tx_Extbase_DomainObject_AbstractEntity $parentObject, $parentPropertyName) {
00557         $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
00558         $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
00559         if ($parentColumnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
00560             $row = array();
00561             $parentKeyFieldName = $parentColumnMap->getParentKeyFieldName();
00562             if ($parentKeyFieldName !== NULL) {
00563                 $row[$parentKeyFieldName] = '';
00564                 $parentTableFieldName = $parentColumnMap->getParentTableFieldName();
00565                 if ($parentTableFieldName !== NULL) {
00566                     $row[$parentTableFieldName] = '';
00567                 }
00568             }
00569             $childSortByFieldName = $parentColumnMap->getChildSortByFieldName();
00570             if (!empty($childSortByFieldName)) {
00571                 $row[$childSortByFieldName] = 0;
00572             }
00573             if (count($row) > 0) {
00574                 $this->updateObject($object, $row);
00575             }
00576         } elseif ($parentColumnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_AND_BELONGS_TO_MANY) {
00577             $this->deleteRelationFromRelationtable($object, $parentObject, $parentPropertyName);
00578         }
00579     }
00580 
00581     /**
00582      * Inserts an object in the storage backend
00583      *
00584      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
00585      * @return void
00586      */
00587     protected function insertObject(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
00588         if ($object instanceof Tx_Extbase_DomainObject_AbstractValueObject) {
00589             $result = $this->getUidOfAlreadyPersistedValueObject($object);
00590             if ($result !== FALSE) {
00591                 $object->_setProperty('uid', (int)$result);
00592                 return;
00593             }
00594         }
00595 
00596         $dataMap = $this->dataMapper->getDataMap(get_class($object));
00597         $row = array();
00598         $this->addCommonFieldsToRow($object, $row);
00599         if($dataMap->getLanguageIdColumnName() !== NULL) {
00600             $row[$dataMap->getLanguageIdColumnName()] = -1;
00601         }
00602         $uid = $this->storageBackend->addRow(
00603             $dataMap->getTableName(),
00604             $row
00605             );
00606         $object->_setProperty('uid', (int)$uid);
00607         $frameworkConfiguration = $this->configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
00608         if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
00609             $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $uid);
00610         }
00611         $this->identityMap->registerObject($object, $uid);
00612     }
00613 
00614     /**
00615      * Tests, if the given Value Object already exists in the storage backend and if so, it returns the uid.
00616      *
00617      * @param Tx_Extbase_DomainObject_AbstractValueObject $object The object to be tested
00618      */
00619     protected function getUidOfAlreadyPersistedValueObject(Tx_Extbase_DomainObject_AbstractValueObject $object) {
00620         return $this->storageBackend->getUidOfAlreadyPersistedValueObject($object);
00621     }
00622 
00623     /**
00624      * Inserts mm-relation into a relation table
00625      *
00626      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The related object
00627      * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The parent object
00628      * @param string $propertyName The name of the parent object's property where the related objects are stored in
00629      * @return void
00630      */
00631     protected function insertRelationInRelationtable(Tx_Extbase_DomainObject_DomainObjectInterface $object, Tx_Extbase_DomainObject_DomainObjectInterface $parentObject, $propertyName, $sortingPosition = NULL) {
00632         $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
00633         $columnMap = $dataMap->getColumnMap($propertyName);
00634         $row = array(
00635             $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
00636             $columnMap->getChildKeyFieldName() => (int)$object->getUid(),
00637             $columnMap->getChildSortByFieldName() => !is_null($sortingPosition) ? (int)$sortingPosition : 0
00638             );
00639         $relationTableName = $columnMap->getRelationTableName();
00640         // FIXME Reenable support for tablenames
00641         // $childTableName = $columnMap->getChildTableName();
00642         // if (isset($childTableName)) {
00643         //  $row['tablenames'] = $childTableName;
00644         // }
00645         if ($columnMap->getRelationTablePageIdColumnName() !== NULL) {
00646             $row[$columnMap->getRelationTablePageIdColumnName()] = $this->determineStoragePageIdForNewRecord();
00647         }
00648 
00649         $relationTableInsertFields = $columnMap->getRelationTableInsertFields();
00650         if (count($relationTableInsertFields)) {
00651             foreach($relationTableInsertFields as $insertField => $insertValue) {
00652                 $row[$insertField] = $insertValue;
00653             }
00654         }
00655 
00656         $res = $this->storageBackend->addRow(
00657             $relationTableName,
00658             $row,
00659             TRUE);
00660         return $res;
00661     }
00662 
00663     /**
00664      * Delete all mm-relations of a parent from a relation table
00665      *
00666      * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The parent object
00667      * @param string $parentPropertyName The name of the parent object's property where the related objects are stored in
00668      * @return void
00669      */
00670     protected function deleteAllRelationsFromRelationtable(Tx_Extbase_DomainObject_DomainObjectInterface $parentObject, $parentPropertyName) {
00671         $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
00672         $columnMap = $dataMap->getColumnMap($parentPropertyName);
00673         $relationTableName = $columnMap->getRelationTableName();
00674 
00675         $relationMatchFields = array(
00676             $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid()
00677         );
00678 
00679         $relationTableMatchFields = $columnMap->getRelationTableMatchFields();
00680         if (is_array($relationTableMatchFields) && count($relationTableMatchFields) > 0) {
00681             $relationMatchFields = array_merge($relationTableMatchFields,$relationMatchFields);
00682         }
00683 
00684         $res = $this->storageBackend->removeRow(
00685             $relationTableName,
00686             $relationMatchFields,
00687             FALSE);
00688         return $res;
00689     }
00690 
00691     /**
00692      * Delete an mm-relation from a relation table
00693      *
00694      * @param Tx_Extbase_DomainObject_DomainObjectInterface $relatedObject The related object
00695      * @param Tx_Extbase_DomainObject_DomainObjectInterface $parentObject The parent object
00696      * @param string $parentPropertyName The name of the parent object's property where the related objects are stored in
00697      * @return void
00698      */
00699     protected function deleteRelationFromRelationtable(Tx_Extbase_DomainObject_DomainObjectInterface $relatedObject, Tx_Extbase_DomainObject_DomainObjectInterface $parentObject, $parentPropertyName) {
00700         $dataMap = $this->dataMapper->getDataMap(get_class($parentObject));
00701         $columnMap = $dataMap->getColumnMap($parentPropertyName);
00702         $relationTableName = $columnMap->getRelationTableName();
00703         $res = $this->storageBackend->removeRow(
00704             $relationTableName,
00705             array(
00706                 $columnMap->getParentKeyFieldName() => (int)$parentObject->getUid(),
00707                 $columnMap->getChildKeyFieldName() => (int)$relatedObject->getUid(),
00708                 ),
00709             FALSE);
00710         return $res;
00711     }
00712 
00713     /**
00714      * Updates a given object in the storage
00715      *
00716      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
00717      * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
00718      * @param string|NULL $parentPropertyName The name of the property
00719      * @param array $row The $row
00720      */
00721     protected function updateObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, array $row) {
00722         $dataMap = $this->dataMapper->getDataMap(get_class($object));
00723         $this->addCommonFieldsToRow($object, $row);
00724         $row['uid'] = $object->getUid();
00725         if($dataMap->getLanguageIdColumnName() !== NULL) {
00726             $row[$dataMap->getLanguageIdColumnName()] = $object->_getProperty('_languageUid');
00727             if ($object->_getProperty('_localizedUid') !== NULL) {
00728                 $row['uid'] = $object->_getProperty('_localizedUid');
00729             }
00730         }
00731         $res = $this->storageBackend->updateRow(
00732             $dataMap->getTableName(),
00733             $row
00734             );
00735         $frameworkConfiguration = $this->configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
00736         if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
00737             $this->referenceIndex->updateRefIndexTable($dataMap->getTableName(), $row['uid']);
00738         }
00739         return $res;
00740     }
00741 
00742     /**
00743      * Returns a table row to be inserted or updated in the database
00744      *
00745      * @param Tx_Extbase_Persistence_Mapper_DataMap $dataMap The appropriate data map representing a database table
00746      * @param array $properties The properties of the object
00747      * @return array A single row to be inserted in the database
00748      */
00749     protected function addCommonFieldsToRow(Tx_Extbase_DomainObject_DomainObjectInterface $object, array &$row) {
00750         $className = get_class($object);
00751         $dataMap = $this->dataMapper->getDataMap($className);
00752         if ($object->_isNew() && ($dataMap->getCreationDateColumnName() !== NULL)) {
00753             $row[$dataMap->getCreationDateColumnName()] = $GLOBALS['EXEC_TIME'];
00754         }
00755         if ($dataMap->getModificationDateColumnName() !== NULL) {
00756             $row[$dataMap->getModificationDateColumnName()] = $GLOBALS['EXEC_TIME'];
00757         }
00758         if ($dataMap->getRecordTypeColumnName() !== NULL && $dataMap->getRecordType() !== NULL) {
00759             $row[$dataMap->getRecordTypeColumnName()] = $dataMap->getRecordType();
00760         }
00761         if ($object->_isNew() && !isset($row['pid'])) {
00762             $row['pid'] = $this->determineStoragePageIdForNewRecord($object);
00763         }
00764     }
00765 
00766     /**
00767      * Iterate over deleted aggregate root objects and process them
00768      *
00769      * @return void
00770      */
00771     protected function processDeletedObjects() {
00772         foreach ($this->deletedObjects as $object) {
00773             $this->removeObject($object);
00774             $this->identityMap->unregisterObject($object);
00775         }
00776         $this->deletedObjects = new Tx_Extbase_Persistence_ObjectStorage();
00777     }
00778 
00779     /**
00780      * Deletes an object
00781      *
00782      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
00783      * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
00784      * @param string|NULL $parentPropertyName The name of the property
00785      * @param bool $markAsDeleted Shold we only mark the row as deleted instead of deleting (TRUE by default)?
00786      * @return void
00787      */
00788     protected function removeObject(Tx_Extbase_DomainObject_DomainObjectInterface $object, $markAsDeleted = TRUE) {
00789         $dataMap = $this->dataMapper->getDataMap(get_class($object));
00790         $tableName = $dataMap->getTableName();
00791         if (($markAsDeleted === TRUE) && ($dataMap->getDeletedFlagColumnName() !== NULL)) {
00792             $deletedColumnName = $dataMap->getDeletedFlagColumnName();
00793             $res = $this->storageBackend->updateRow(
00794                 $tableName,
00795                 array(
00796                     'uid' => $object->getUid(),
00797                     $deletedColumnName => 1
00798                     )
00799                 );
00800         } else {
00801             $res = $this->storageBackend->removeRow(
00802                 $tableName,
00803                 array('uid' => $object->getUid())
00804                 );
00805         }
00806         $this->removeRelatedObjects($object);
00807         $frameworkConfiguration = $this->configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
00808         if ($frameworkConfiguration['persistence']['updateReferenceIndex'] === '1') {
00809             $this->referenceIndex->updateRefIndexTable($tableName, $object->getUid());
00810         }
00811     }
00812 
00813     /**
00814      * Remove related objects
00815      *
00816      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to scanned for related objects
00817      * @return void
00818      */
00819     protected function removeRelatedObjects(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
00820         $className = get_class($object);
00821         $dataMap = $this->dataMapper->getDataMap($className);
00822         $classSchema = $this->reflectionService->getClassSchema($className);
00823 
00824         $properties = $object->_getProperties();
00825         foreach ($properties as $propertyName => $propertyValue) {
00826             $columnMap = $dataMap->getColumnMap($propertyName);
00827             $propertyMetaData = $classSchema->getProperty($propertyName);
00828             if ($propertyMetaData['cascade'] === 'remove') {
00829                 if ($columnMap->getTypeOfRelation() === Tx_Extbase_Persistence_Mapper_ColumnMap::RELATION_HAS_MANY) {
00830                     foreach ($propertyValue as $containedObject) {
00831                         $this->removeObject($containedObject);
00832                     }
00833                 } elseif ($propertyValue instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
00834                     $this->removeObject($propertyValue);
00835                 }
00836             }
00837         }
00838     }
00839 
00840     /**
00841      * Determine the storage page ID for a given NEW record
00842      *
00843      * This does the following:
00844      * - If there is a TypoScript configuration "classes.CLASSNAME.newRecordStoragePid", that is used to store new records.
00845      * - If there is no such TypoScript configuration, it uses the first value of The "storagePid" taken for reading records.
00846      *
00847      * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
00848      * @return int the storage Page ID where the object should be stored
00849      */
00850     protected function determineStoragePageIdForNewRecord(Tx_Extbase_DomainObject_DomainObjectInterface $object = NULL) {
00851         $frameworkConfiguration = $this->configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
00852         if ($object !== NULL) {
00853             $className = get_class($object);
00854             if (isset($frameworkConfiguration['persistence']['classes'][$className]) && !empty($frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'])) {
00855                 return (int)$frameworkConfiguration['persistence']['classes'][$className]['newRecordStoragePid'];
00856             }
00857         }
00858         $storagePidList = t3lib_div::intExplode(',', $frameworkConfiguration['persistence']['storagePid']);
00859         return (int) $storagePidList[0];
00860     }
00861 
00862     /**
00863      * Returns a plain value, i.e. objects are flattened out if possible.
00864      *
00865      * @param mixed $input
00866      * @return mixed
00867      */
00868     protected function getPlainValue($input) {
00869         if ($input instanceof DateTime) {
00870             return $input->format('U');
00871         } elseif ($input instanceof Tx_Extbase_DomainObject_DomainObjectInterface) {
00872             return $input->getUid();
00873         } elseif (is_bool($input)) {
00874             return $input === TRUE ? 1 : 0;
00875         } else {
00876             return $input;
00877         }
00878     }
00879 
00880 }
00881 
00882 ?>