[!!!][+FEATURE] Extbase (Persistence): Improved handling of PID columns. There are...
authorSebastian Kurfürst <sebastian@typo3.org>
Fri, 31 Jul 2009 08:03:23 +0000 (08:03 +0000)
committerSebastian Kurfürst <sebastian@typo3.org>
Fri, 31 Jul 2009 08:03:23 +0000 (08:03 +0000)
typo3/sysext/extbase/Classes/Configuration/Manager.php
typo3/sysext/extbase/Classes/Persistence/Backend.php
typo3/sysext/extbase/Classes/Persistence/Storage/Typo3DbBackend.php

index 9da651d..0766f3a 100644 (file)
  */
 class Tx_Extbase_Configuration_Manager {
 
-       const DEFAULT_STORAGE_PID = 0;
+       /**
+        * Default backend storage PID
+        */
+       const DEFAULT_BACKEND_STORAGE_PID = 0;
 
        /**
         * Storage for the settings, loaded by loadGlobalSettings()
@@ -104,32 +107,31 @@ class Tx_Extbase_Configuration_Manager {
        }
 
        /**
-        * Extracts the default storage PID from $this->cObj->data['pages']. ONLY ALLOWS ONE STORAGE PID!
+        * Extracts the default storage PID from $this->cObj->data['pages'].
         * If this one is empty, tries to use $this->cObj->data['storage_pid'].
-        * If this one is empty, tries to use $this->cObj->parentRecord->data['storage_pid']. If all tree  are empty, uses current page.
+        * If this one is empty, tries to use $this->cObj->parentRecord->data['storage_pid'].
+        * If all three are empty, uses getStorageSiterootPids() in FE, and 0 in BE.
         *
         * @param tslib_cObj $cObj The current Content Object
-        * @return integer
-        * @throws InvalidArgumentException if more than one storage page ID is given
+        * @return string a comma separated list of integers to be used to fetch records from.
         */
        protected function getDefaultStoragePageId($cObj) {
                if (is_string($cObj->data['pages'])) {
-                       if (count(explode(',', $cObj->data['pages'])) > 1) {
-                               // TODO Should we take the first pid after explode?
-                               throw new InvalidArgumentException('More than one storage page ID given. This is currently not supported.', 1247597243);
-                       }
-                       return (int)$cObj->data['pages'];
+                       return $cObj->data['pages'];
                }
 
                if ($cObj->data['storage_pid'] > 0) {
-                       return (int)$cObj->data['storage_pid'];
+                       return $cObj->data['storage_pid'];
                }
 
                if ($cObj->parentRecord->data['storage_pid'] > 0) {
-                       return (int)$cObj->parentRecord->data['storage_pid'];
+                       return $cObj->parentRecord->data['storage_pid'];
+               }
+               if (TYPO3_MODE === 'FE') {
+                       return $GLOBALS['TSFE']->getStorageSiterootPids();
+               } else {
+                       return self::DEFAULT_BACKEND_STORAGE_PID;
                }
-               // FIXME Take $GLOBALS['TSFE']->getStorageSiterootPids(); as default for FE and 0 for BE
-               return self::DEFAULT_STORAGE_PID;
        }
 
        /**
index 38d737f..fd0934f 100644 (file)
@@ -5,7 +5,7 @@
 *  (c) 2009 Jochen Rau <jochen.rau@typoplanet.de>
 *  All rights reserved
 *
-*  This class is a backport of the corresponding class of FLOW3. 
+*  This class is a backport of the corresponding class of FLOW3.
 *  All credits go to the v5 team.
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -139,7 +139,7 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        public function getSession() {
                return $this->session;
        }
-       
+
        /**
         * Returns the Data Mapper
         *
@@ -285,7 +285,7 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                if ($object instanceof Tx_Extbase_DomainObject_AbstractValueObject) {
                        $this->mapAlreadyPersistedValueObject($object);
                }
-               
+
                $properties = $object->_getProperties();
                // Fill up $row[$columnName] array with changed values which need to be stored
                foreach ($properties as $propertyName => $propertyValue) {
@@ -312,14 +312,14 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                } elseif ($object->_isDirty()) {
                        $this->updateObject($object, $parentObject, $parentPropertyName, $row);
                }
-               
+
                // SK: Where does $queueChildObjects come from? Do we need the code below?
-               $objectHasToBeUpdated = $this->processQueuedChildObjects($object, $queuedObjects, $row);                
+               $objectHasToBeUpdated = $this->processQueuedChildObjects($object, $queuedObjects, $row);
                if ($objectHasToBeUpdated === TRUE) {
                        // TODO Check if this can be merged with the first update
                        $this->updateObject($object, $parentObject, $parentPropertyName, $row);
                }
-               
+
                // SK: I need to check the code below more thoroughly
                if ($parentObject instanceof Tx_Extbase_DomainObject_DomainObjectInterface && !empty($parentPropertyName)) {
                        $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
@@ -328,15 +328,15 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                                $this->insertRelationInRelationtable($object, $parentObject, $parentPropertyName);
                        }
                }
-               
+
                $this->identityMap->registerObject($object, $object->getUid());
                $object->_memorizeCleanState();
        }
-       
+
        /**
         * Persists a relation. Objects of a 1:n or m:n relation are queued and processed with the parent object. A 1:1 relation
         * gets persisted immediately. Objects which were removed from the property were deleted immediately, too.
-        * 
+        *
         * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be inserted
         * @param string $propertyName The name of the property the related objects are stored in
         * @param mixed $propertyValue The property value (an array of Domain Objects, ObjectStorage holding Domain Objects or a Domain Object itself)
@@ -362,11 +362,11 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                                $row[$columnName] = $propertyValue->getUid();
                        }
        }
-       
+
        /**
         * Returns the deleted objects determined by a comparison of the clean property value
         * with the actual property value.
-        * 
+        *
         * @param Tx_Extbase_DomainObject_AbstractEntity $object The object to be insterted in the storage
         * @param string $parentPropertyName The name of the property
         * @return array An array of deleted objects
@@ -385,21 +385,21 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                        }
                        $deletedObjects = array_diff($cleanPropertyValue, $propertyValue);
                }
-               
+
                return $deletedObjects;
        }
-       
+
        /**
-        * This function processes the queued child objects to be persisted. The queue is build while looping over the 
+        * This function processes the queued child objects to be persisted. The queue is build while looping over the
         * collection of Domain Objects stored in a object property.
-        * 
+        *
         * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object holding the collection
         * @param array $queuedObjects The queued child objects
         * @param array $row The row to be inseted or updated in the database. Passed as reference.
         * @return boolean TRUE if the object holding the collection has to be updated; otherwise FALSE
         */
        protected function processQueuedChildObjects(Tx_Extbase_DomainObject_DomainObjectInterface $object, array $queuedChildObjects, array &$row) {
-               $objectHasToBeUpdated = FALSE;          
+               $objectHasToBeUpdated = FALSE;
                $className = get_class($object);
                $dataMap = $this->dataMapper->getDataMap($className);
                foreach ($queuedChildObjects as $propertyName => $childObjects) {
@@ -420,7 +420,7 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
        }
 
        /*
-        * Tests, if the given Value Object already exists in the storage backend. If so, it maps the uid 
+        * Tests, if the given Value Object already exists in the storage backend. If so, it maps the uid
         * to the given object.
         *
         * @param Tx_Extbase_DomainObject_AbstractValueObject $object The object to be tested
@@ -436,7 +436,7 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
 
        /**
         * Inserts an object in the storage
-        * 
+        *
         * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
         * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
         * @param string|NULL $parentPropertyName The name of the property
@@ -481,7 +481,7 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
 
        /**
         * Updates a given object in the storage
-        * 
+        *
         * @param Tx_Extbase_DomainObject_DomainObjectInterface $object The object to be insterted in the storage
         * @param Tx_Extbase_DomainObject_AbstractEntity|NULL $parentObject The parent object (if any)
         * @param string|NULL $parentPropertyName The name of the property
@@ -509,7 +509,6 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
         * @param array $properties The properties of the object
         * @return array A single row to be inserted in the database
         */
-       // TODO Should we pass an extra flag (UPDATE/INSERT)?
        protected function addCommonFieldsToRow(Tx_Extbase_DomainObject_DomainObjectInterface $object, $parentObject = NULL, $parentPropertyName = NULL, array &$row) {
                $className = get_class($object);
                $dataMap = $this->dataMapper->getDataMap($className);
@@ -519,11 +518,11 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                if ($dataMap->hasTimestampColumn()) {
                        $row[$dataMap->getTimestampColumnName()] = $GLOBALS['EXEC_TIME'];
                }
-               if ($dataMap->hasPidColumn() && !isset($row['pid'])) {
-                       $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
-                       // TODO Allow plugin settings for the storage pid
-                       $row['pid'] = $extbaseSettings['storagePid'];
+
+               if ($object->_isNew() && $dataMap->hasPidColumn() && !isset($row['pid'])) {
+                       $row['pid'] = $this->determineStoragePageIdForNewRecord($object);
                }
+
                if ($parentObject instanceof Tx_Extbase_DomainObject_DomainObjectInterface && !empty($parentPropertyName)) {
                        $parentDataMap = $this->dataMapper->getDataMap(get_class($parentObject));
                        $parentColumnMap = $parentDataMap->getColumnMap($parentPropertyName);
@@ -541,6 +540,28 @@ class Tx_Extbase_Persistence_Backend implements Tx_Extbase_Persistence_BackendIn
                }
        }
 
+       /**
+        * Determine the storage page ID for a given NEW record
+        *
+        * This does the following:
+        * - If there is a TypoScript configuration "classes.CLASSNAME.newRecordStoragePid", that is used to store new records.
+        * - If there is no such TypoScript configuration, it uses the first value of The "storagePid" taken for reading records.
+        *
+        * @param Tx_Extbase_DomainObject_DomainObjectInterface $object
+        * @return int the storage Page ID where the object should be stored
+        */
+       protected function determineStoragePageIdForNewRecord(Tx_Extbase_DomainObject_DomainObjectInterface $object) {
+               $className = get_class($object);
+               $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
+
+               if (isset($extbaseSettings['classes'][$className]) && !empty($extbaseSettings['classes'][$className]['newRecordStoragePid'])) {
+                       return (int)$extbaseSettings['classes'][$className]['newRecordStoragePid'];
+               } else {
+                       $storagePidList = t3lib_div::intExplode(',', $extbaseSettings['storagePid']);
+                       return (int) $storagePidList[0];
+               }
+       }
+
        /**
         * Iterate over deleted aggregate root objects and process them
         *
index 1fd94e1..916388b 100644 (file)
@@ -53,7 +53,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
 
        /**
         * TRUE if automatic cache clearing in TCEMAIN should be done on insert/update/delete, FALSE otherwise.
-        *  
+        *
         * @var boolean
         */
        protected $automaticCacheClearing = FALSE;
@@ -66,11 +66,11 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        public function __construct($databaseHandle) {
                $this->databaseHandle = $databaseHandle;
        }
-       
+
        /**
         * Set the automatic cache clearing flag.
         * If TRUE, then inserted/updated/deleted records trigger a TCEMAIN cache clearing.
-        * 
+        *
         * @param $automaticCacheClearing boolean if TRUE, enables automatic cache clearing
         * @return void
         * @internal
@@ -172,10 +172,10 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                if ($result) {
                        $tuples = $this->getRowsFromResult($query->getSource(), $result);
                }
-               
+
                return $tuples;
        }
-       
+
        /**
         * Returns an array with tuples matching the query.
         *
@@ -201,12 +201,12 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        $sql['limit'] = array();
                        $parameters = array();
                        $tuples = array();
-                       
+
                        $this->parseSource($query, $sql, $parameters);
                        $statement = 'SELECT ' . implode(',', $sql['fields']) . ' FROM ' . implode(' ', $sql['tables']);
-       
+
                        $this->parseConstraint($query->getConstraint(), $sql, $parameters, $query->getBoundVariableValues());
-       
+
                        if (!empty($sql['where'])) {
                                $statement .= ' WHERE ' . implode('', $sql['where']);
                                if (!empty($sql['enableFields'])) {
@@ -215,19 +215,19 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        } elseif (!empty($sql['enableFields'])) {
                                $statement .= ' WHERE ' . implode(' AND ', $sql['enableFields']);
                        }
-       
+
                        $this->parseOrderings($query->getOrderings(), $sql, $parameters, $query->getBoundVariableValues());
                        if (!empty($sql['orderings'])) {
                                $statement .= ' ORDER BY ' . implode(', ', $sql['orderings']);
                        }
-       
+
                        $this->parseLimitAndOffset($query->getLimit(), $query->getOffset(), $sql, $parameters, $query->getBoundVariableValues());
                        if (!empty($sql['limit'])) {
                                $statement .= ' LIMIT ' . $sql['limit'];
                        }
-       
+
                        $this->replacePlaceholders($statement, $parameters);
-                       
+
                }
 
                return $statement;
@@ -485,7 +485,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                        $offset = $markPosition + strlen($parameter);
                }
        }
-       
+
        /**
         * Builds the enable fields statement
         *
@@ -515,9 +515,9 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
         */
        protected function addPageIdStatement($selectorName, array &$sql) {
                // TODO We have to call the appropriate API method if we are in TYPO3BE mode
-               $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
                if (is_array($GLOBALS['TCA'][$selectorName]['ctrl'])) {
-                       $sql['enableFields'][] = $selectorName . '.pid=' . intval($extbaseSettings['storagePid']);
+                       $extbaseSettings = Tx_Extbase_Dispatcher::getSettings();
+                       $sql['enableFields'][] = $selectorName . '.pid IN (' . implode(', ', t3lib_div::intExplode(',', $extbaseSettings['storagePid'])) . ')';
                }
        }
 
@@ -570,7 +570,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        /**
         * Transforms a Resource from a database query to an array of rows. Performs the language and
         * workspace overlay before.
-        * 
+        *
         * @param Tx_Extbase_Persistence_QOM_SourceInterface $source The source (selector od join)
         *
         * @return array The result as an array of rows (tuples)
@@ -635,10 +635,10 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
                // TODO Skip if empty languageoverlay (languagevisibility)
                return $row;
        }
-       
+
        /**
         * Checks if there are SQL errors in the last query, and if yes, throw an exception.
-        * 
+        *
         * @return void
         * @throws Tx_Extbase_Persistence_Storage_Exception_SqlError
         */
@@ -652,7 +652,7 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
        /**
         * Clear the TYPO3 page cache for the given record.
         * Much of this functionality is taken from t3lib_tcemain::clear_cache() which unfortunately only works with logged-in BE user.
-        * 
+        *
         * @param $tableName Table name of the record
         * @param $uid UID of the record
         * @return void
@@ -662,9 +662,9 @@ class Tx_Extbase_Persistence_Storage_Typo3DbBackend implements Tx_Extbase_Persis
 
                $pageCache = $GLOBALS['typo3CacheManager']->getCache('cache_pages');
                $pageSectionCache = $GLOBALS['typo3CacheManager']->getCache('cache_pagesection');
-       
+
                $result = $this->databaseHandle->exec_SELECTquery('pid', $tableName, 'uid='.intval($uid));
-       
+
                $pageIdsToClear = array();
                if ($row = $this->databaseHandle->sql_fetch_assoc($result))     {
                        $storagePage = $row['pid'];