[TASK] Clean-up responsibilities of FAL classes 39/23839/14
authorSteffen Ritter <info@rs-websystems.de>
Sun, 15 Sep 2013 13:40:17 +0000 (15:40 +0200)
committerSteffen Ritter <info@rs-websystems.de>
Sat, 12 Oct 2013 08:59:23 +0000 (10:59 +0200)
The FileRepository, ResourceStorage and ResourceFactory all somehow
take care of creating files, managing files and their data.  Getting a
file from ResourceStorage->getFile never involves the index-Records and
even if index records exists the driver always needs to query all file
information out of the filesystem to create FileObject.

As we always expect the index-record to be up to date we can rely on
that and must not query the file-system for every bit of information.
In addition creating objects without looking for the record first
renders the FAL API useless. This patch introduces a
FileIndexRepository which only deals with these kind of records and
deprecates the methods within the FileRepository.

In addition it moves around the "file-object creation logic" so this is
dealt with at a central place: The Resource Factory. Finally the
ResourceFactory always uses to get an IndexRecord from the newly
introduced Repository. If the FileInfo is not present, it queries the
Storage for the fileInfo (from the Driver).

Releases: 6.2
Resolves: #51528
Change-Id: I6ceeb8db4dd4e470e7c72dcfbc2121093411da75
Reviewed-on: https://review.typo3.org/23839
Reviewed-by: Ernesto Baschny
Tested-by: Ernesto Baschny
Reviewed-by: Frans Saris
Tested-by: Frans Saris
Reviewed-by: Markus Klein
Tested-by: Markus Klein
Reviewed-by: Steffen Ritter
Tested-by: Steffen Ritter
typo3/sysext/core/Classes/Resource/File.php
typo3/sysext/core/Classes/Resource/FileRepository.php
typo3/sysext/core/Classes/Resource/Index/FileIndexRepository.php [new file with mode: 0644]
typo3/sysext/core/Classes/Resource/ResourceFactory.php
typo3/sysext/core/Classes/Resource/ResourceStorage.php
typo3/sysext/core/Classes/Resource/Service/IndexerService.php
typo3/sysext/core/Classes/Utility/File/ExtendedFileUtility.php
typo3/sysext/core/Tests/Unit/Resource/ResourceFactoryTest.php
typo3/sysext/install/Classes/Updates/TtContentUploadsUpdateWizard.php

index aa6f431..da3f392 100644 (file)
@@ -64,6 +64,11 @@ class File extends AbstractFile {
         */
        protected $updatedProperties = array();
 
+       /**
+        * @var Service\IndexerService
+        */
+       protected $indexerService = NULL;
+
        /*********************************************
         * GENERIC FILE TYPES
         * these are generic filetypes or -groups,
@@ -168,10 +173,11 @@ class File extends AbstractFile {
                }
                /** @var $repo FileRepository */
                $repo = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
-               $indexRecord = $repo->getFileIndexRecord($this);
+
+               $indexRecord = Index\FileIndexRepository::getInstance()->findOneByFileObject($this);
                if ($indexRecord === FALSE && $indexIfNotIndexed) {
                        $this->indexingInProgress = TRUE;
-                       $indexRecord = $repo->addToIndex($this);
+                       $indexRecord = $this->getIndexerService()->indexFile($this, FALSE);
                        $this->mergeIndexRecord($indexRecord);
                        $this->indexed = TRUE;
                        $this->indexingInProgress = FALSE;
@@ -374,4 +380,16 @@ class File extends AbstractFile {
                }
        }
 
+       /**
+        * Internal function to retrieve the indexer service,
+        * if it does not exist, an instance will be created
+        *
+        * @return Service\IndexerService
+        */
+       protected function getIndexerService() {
+               if ($this->indexerService === NULL) {
+                       $this->indexerService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService');
+               }
+               return $this->indexerService;
+       }
 }
index a852574..60fcd10 100644 (file)
@@ -26,6 +26,10 @@ namespace TYPO3\CMS\Core\Resource;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+
+use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
 /**
  * Repository for accessing files
  * it also serves as the public API for the indexing part of files in general
@@ -65,7 +69,7 @@ class FileRepository extends AbstractRepository {
         */
        protected function getIndexerService() {
                if ($this->indexerService === NULL) {
-                       $this->indexerService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService');
+                       $this->indexerService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService');
                }
                return $this->indexerService;
        }
@@ -83,12 +87,12 @@ class FileRepository extends AbstractRepository {
        /**
         * Index a file object given as parameter
         *
-        * @TODO : Check if the indexing functions really belong into the repository and shouldn't be part of an
-        * @TODO : indexing service, right now it's fine that way as this function will serve as the public API
         * @param File $fileObject
         * @return array The indexed file data
+        * @deprecated since TYPO3 6.2, will be removed two versions later - indexing should be handled transparently, not only upon request
         */
        public function addToIndex(File $fileObject) {
+               GeneralUtility::logDeprecatedFunction();
                return $this->getIndexerService()->indexFile($fileObject, FALSE);
        }
 
@@ -96,47 +100,28 @@ class FileRepository extends AbstractRepository {
         * Checks the index status of a file and returns FALSE if the file is not
         * indexed, the uid otherwise.
         *
-        * @TODO : Check if the indexing functions really belong into the repository and shouldn't be part of an
-        * @TODO : indexing service, right now it's fine that way as this function will serve as the public API
-        * @TODO : throw an exception if nothing found, for consistent handling as in AbstractRepository?
         * @param File $fileObject
         * @return boolean|integer
+        * @deprecated since TYPO3 6.2, will be removed two versions later - use FileIndexRepository::isIndexed
         */
        public function getFileIndexStatus(File $fileObject) {
+               GeneralUtility::logDeprecatedFunction();
                $storageUid = $fileObject->getStorage()->getUid();
                $identifier = $fileObject->getIdentifier();
-               $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
-                       'uid,storage,identifier',
-                       $this->table,
-                       sprintf('storage=%u AND identifier=%s', $storageUid, $GLOBALS['TYPO3_DB']->fullQuoteStr($identifier, $this->table))
-               );
-               if (!is_array($row)) {
-                       return FALSE;
-               } else {
-                       return $row['uid'];
-               }
+               $row = $this->getFileIndexRepository()->findOneByStorageUidAndIdentifier($storageUid, $identifier);
+               return is_array($row) ? $row['uid'] : FALSE;
        }
 
        /**
         * Returns an index record of a file, or FALSE if the file is not indexed.
         *
-        * @TODO : throw an exception if nothing found, for consistent handling as in AbstractRepository?
         * @param File $fileObject
         * @return bool|array
+        * @deprecated since TYPO3 6.2, will be removed two versions later - use FileIndexRepository instead
         */
        public function getFileIndexRecord(File $fileObject) {
-               $storageUid = $fileObject->getStorage()->getUid();
-               $identifier = $fileObject->getIdentifier();
-               $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
-                       '*',
-                       $this->table,
-                       sprintf('storage=%u AND identifier=%s', $storageUid, $GLOBALS['TYPO3_DB']->fullQuoteStr($identifier, $this->table))
-               );
-               if (!is_array($row)) {
-                       return FALSE;
-               } else {
-                       return $row;
-               }
+               GeneralUtility::logDeprecatedFunction();
+               return $this->getFileIndexRepository()->findOneByFileObject($fileObject);
        }
 
        /**
@@ -170,16 +155,12 @@ class FileRepository extends AbstractRepository {
         *
         * @param string $hash A SHA1 hash of a file
         * @return array
+        * @deprecated since TYPO3 6.2, will be removed two versions later - use FileIndexRepository::findByContentHash
         */
        public function findBySha1Hash($hash) {
-               if (preg_match('/[^a-f0-9]*/i', $hash)) {
+               GeneralUtility::logDeprecatedFunction();
+               $resultRows = $this->getFileIndexRepository()->findByContentHash($hash);
 
-               }
-               $resultRows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
-                       '*',
-                       $this->table,
-                       'sha1=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, $this->table)
-               );
                $objects = array();
                foreach ($resultRows as $row) {
                        $objects[] = $this->createDomainObject($row);
@@ -250,17 +231,13 @@ class FileRepository extends AbstractRepository {
         *
         * @param AbstractFile $modifiedObject
         * @return void
+        * @deprecated since TYPO3 6.2 LTS, will be removed two versions later - use FileIndexRepository::update
         */
        public function update($modifiedObject) {
-               // TODO check if $modifiedObject is an instance of AbstractFile
-               // TODO check if $modifiedObject is indexed
-               $changedProperties = $modifiedObject->getUpdatedProperties();
-               $properties = $modifiedObject->getProperties();
-               $updateFields = array();
-               foreach ($changedProperties as $propertyName) {
-                       $updateFields[$propertyName] = $properties[$propertyName];
+               GeneralUtility::logDeprecatedFunction();
+               if ($modifiedObject instanceof File) {
+                       $this->getFileIndexRepository()->update($modifiedObject);
                }
-               $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_file', 'uid=' . $modifiedObject->getUid(), $updateFields);
        }
 
        /**
@@ -273,4 +250,13 @@ class FileRepository extends AbstractRepository {
                return $this->factory->getFileReferenceObject($databaseRow['uid'], $databaseRow);
        }
 
+       /**
+        * Return a file index repository
+        *
+        * @return FileIndexRepository
+        */
+       protected function getFileIndexRepository() {
+               return FileIndexRepository::getInstance();
+       }
+
 }
diff --git a/typo3/sysext/core/Classes/Resource/Index/FileIndexRepository.php b/typo3/sysext/core/Classes/Resource/Index/FileIndexRepository.php
new file mode 100644 (file)
index 0000000..d61cc97
--- /dev/null
@@ -0,0 +1,216 @@
+<?php
+
+namespace TYPO3\CMS\Core\Resource\Index;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Steffen Ritter <steffen.ritter@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *  A copy is found in the textfile GPL.txt and important notices to the license
+ *  from the author is found in LICENSE.txt distributed with these scripts.
+ *
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\SingletonInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Core\Resource\File;
+
+/**
+ * Repository Class as an abstraction layer to sys_file
+ *
+ * Every access to table sys_file_metadata which is not handled by TCEmain
+ * has to use this Repository class.
+ *
+ * This is meant for FAL internal use only!.
+ */
+class FileIndexRepository implements SingletonInterface {
+
+       /**
+        * @var string
+        */
+       protected $table = 'sys_file';
+
+       /**
+        * A list of properties which are to be persisted
+        *
+        * @var array
+        */
+       protected $fields = array(
+               'uid', 'pid',   'missing', 'type', 'storage', 'identifier',
+               'extension', 'mime_type', 'name', 'title', 'sha1', 'size', 'creation_date',
+               'modification_date', 'width', 'height', 'description', 'alternative'
+       );
+
+       /**
+        * @var FileIndexRepository
+        */
+       protected static $instance = NULL;
+
+
+       /**
+        * Gets database instance
+        *
+        * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+        */
+       protected function getDatabase() {
+               return $GLOBALS['TYPO3_DB'];
+       }
+
+       /**
+        * Returns an Instance of the Repository
+        *
+        * @return FileIndexRepository
+        */
+       public static function getInstance() {
+               if (static::$instance === NULL) {
+                       static::$instance = GeneralUtility::makeInstance('TYPO3\CMS\Core\Resource\Index\FileIndexRepository');
+               }
+               return static::$instance;
+       }
+
+       /**
+        * Retrieves Index record for a given $combinedIdentifier
+        *
+        * @param string $combinedIdentifier
+        * @return array|bool
+        */
+       public function findOneByCombinedIdentifier($combinedIdentifier) {
+               list($storageUid, $identifier) = GeneralUtility::trimExplode(':', $combinedIdentifier, FALSE, 2);
+               return $this->findOneByStorageUidAndIdentifier($storageUid, $identifier);
+       }
+
+       /**
+        * Retrieves Index record for a given $fileUid
+        *
+        * @param int $fileUid
+        * @return array|bool
+        */
+       public function findOneByUid($fileUid) {
+               $row = $this->getDatabase()->exec_SELECTgetSingleRow(
+                       '*',
+                       $this->table,
+                       'uid=' . intval($fileUid)
+               );
+               return is_array($row) ? $row : FALSE;
+       }
+
+       /**
+        * Retrieves Index record for a given $storageUid and $identifier
+        *
+        * @param int $storageUid
+        * @param string $identifier
+        * @return array|bool
+        *
+        * @internal only for use from FileRepository
+        */
+       public function findOneByStorageUidAndIdentifier($storageUid, $identifier) {
+               $row = $this->getDatabase()->exec_SELECTgetSingleRow(
+                       '*',
+                       $this->table,
+                       sprintf('storage=%u AND identifier=%s', intval($storageUid), $this->getDatabase()->fullQuoteStr($identifier, $this->table))
+               );
+               return is_array($row) ? $row : FALSE;
+       }
+
+       /**
+        * Retrieves Index record for a given $fileObject
+        *
+        * @param \TYPO3\CMS\Core\Resource\FileInterface $fileObject
+        * @return array|bool
+        *
+        * @internal only for use from FileRepository
+        */
+       public function findOneByFileObject(\TYPO3\CMS\Core\Resource\FileInterface $fileObject) {
+               $storageUid = $fileObject->getStorage()->getUid();
+               $identifier = $fileObject->getIdentifier();
+               return $this->findOneByStorageUidAndIdentifier($storageUid, $identifier);
+       }
+
+       /**
+        * Returns all indexed files which match the content hash
+        * Used by the indexer to detect already present files
+        *
+        * @param string $hash
+        * @return mixed
+        */
+       public function findByContentHash($hash) {
+               if (!preg_match('/^[0-9a-f]{40}$/i', $hash)) {
+                       return array();
+               }
+               $resultRows = $this->getDatabase()->exec_SELECTgetRows(
+                       '*',
+                       $this->table,
+                       'sha1=' . $this->getDatabase()->fullQuoteStr($hash, $this->table)
+               );
+               return $resultRows;
+       }
+
+       /**
+        * Adds a file to the index
+        *
+        * @param File $file
+        */
+       public function add(File $file) {
+               if ($this->hasIndexRecord($file)) {
+                       $this->update($file);
+               } else {
+                       $data = array_intersect_key($file->getProperties(), array_flip($this->fields));
+                       $this->getDatabase()->exec_INSERTquery($this->table, $data);
+                       $file->updateProperties(array('uid' => $this->getDatabase()->sql_insert_id()));
+               }
+       }
+
+       /**
+        * Checks if a file is indexed
+        *
+        * @param File $file
+        * @return bool
+        */
+       public function hasIndexRecord(File $file) {
+               if (intval($file->getUid()) > 0) {
+                       $where = 'uid=' . intval($file->getUid());
+
+               } else {
+                       $where = sprintf(
+                               'storage=%u AND identifier=%s',
+                               intval($file->getStorage()->getUid()),
+                               $this->getDatabase()->fullQuoteStr($file->getIdentifier(), $this->table)
+                       );
+               }
+               return $this->getDatabase()->exec_SELECTcountRows('uid', $this->table, $where) === 1;
+       }
+
+       /**
+        * Updates the index record in the database
+        *
+        * @param File $file
+        */
+       public function update(File $file) {
+               $updatedProperties = array_intersect($this->fields, $file->getUpdatedProperties());
+               $updateRow = array();
+               foreach ($updatedProperties as $key) {
+                       $updateRow[$key] = $file->getProperty($key);
+               }
+               if (count($updateRow) > 0) {
+                       $updateRow['tstamp'] = time();
+                       $this->getDatabase()->exec_UPDATEquery($this->table, 'uid=' . intval($file->getUid()), $updateRow);
+               }
+       }
+}
index 424f832..840f466 100644 (file)
@@ -27,6 +27,7 @@ namespace TYPO3\CMS\Core\Resource;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 
@@ -340,17 +341,12 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
                if (!$this->fileInstances[$uid]) {
                        // Fetches data in case $fileData is empty
                        if (empty($fileData)) {
-                               /** @var FileRepository $fileRepository */
-                               $fileRepository = GeneralUtility::makeInstance('TYPO3\CMS\Core\Resource\FileRepository');
-                               $fileObject = $fileRepository->findByUid($uid);
-                               if (!is_object($fileObject)) {
+                               $fileData = $this->getFileIndexRepository()->findOneByUid($uid);
+                               if ($fileData === FALSE) {
                                        throw new \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException('No file found for given UID.', 1317178604);
-                               } else {
-                                       $this->fileInstances[$uid] = $fileObject;
                                }
-                       } else {
-                               $this->fileInstances[$uid] = $this->createFileObject($fileData);
                        }
+                       $this->fileInstances[$uid] = $this->createFileObject($fileData);
                }
                return $this->fileInstances[$uid];
        }
@@ -371,14 +367,35 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
                        // use virtual Storage (uid=0)
                        $storageUid = 0;
                        $fileIdentifier = $parts[0];
-
-                       // please note that getStorageObject() might modify $fileIdentifier when
-                       // auto-detecting the best-matching storage to use
                }
-               return $this->getStorageObject($storageUid, array(), $fileIdentifier)->getFile($fileIdentifier);
+
+               // please note that getStorageObject() might modify $fileIdentifier when
+               // auto-detecting the best-matching storage to use
+               return $this->getFileObjectByStorageAndIdentifier($storageUid, $fileIdentifier);
        }
 
        /**
+        * @param int $storageUid
+        * @param string $fileIdentifier
+        *
+        * @return File
+        */
+       public function getFileObjectByStorageAndIdentifier($storageUid, &$fileIdentifier) {
+               $storage = $this->getStorageObject($storageUid, array(), $fileIdentifier);
+               $fileData = $this->getFileIndexRepository()->findOneByStorageUidAndIdentifier($storage->getUid(), $fileIdentifier);
+               if ($fileData !== FALSE) {
+                       $fileObject = $this->getFileObject($fileData['uid'], $fileData);
+               } else {
+                       $fileData = $storage->getFileInfoByIdentifier($fileIdentifier);
+                       $fileObject = $this->createFileObject($fileData);
+                       if (!array_key_exists('uid', $fileData)) {
+                               $this->getFileIndexRepository()->add($fileObject);
+                       }
+                       $this->fileInstances[$fileObject->getUid()] = $fileObject;
+               }
+               return $fileObject;
+       }
+       /**
         * Bulk function, can be used for anything to get a file or folder
         *
         * 1. It's a UID
@@ -417,6 +434,8 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
                                $input = GeneralUtility::getFileAbsFileName($input);
                                $input = PathUtility::getRelativePath(PATH_site, dirname($input)) . basename($input);
                                return $this->getFileObjectFromCombinedIdentifier($input);
+                       } else {
+                               return NULL;
                        }
                // this is a backwards-compatible way to access "0-storage" files or folders
                } elseif (@is_file(PATH_site . $input)) {
@@ -464,10 +483,7 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
         */
        public function getStorageObjectFromCombinedIdentifier($identifier) {
                $parts = GeneralUtility::trimExplode(':', $identifier);
-               if (count($parts) === 2) {
-                       $storageUid = $parts[0];
-               }
-
+               $storageUid = count($parts) === 2 ? $parts[0] : NULL;
                return $this->getStorageObject($storageUid);
        }
 
@@ -556,4 +572,13 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
                $fileReferenceObject = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileReference', $fileReferenceData);
                return $fileReferenceObject;
        }
+
+       /**
+        * Returns an instance of the FileIndexRepository
+        *
+        * @return FileIndexRepository
+        */
+       protected function getFileIndexRepository() {
+               return FileIndexRepository::getInstance();
+       }
 }
index e61afe3..1d455c5 100644 (file)
@@ -27,8 +27,10 @@ namespace TYPO3\CMS\Core\Resource;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
+use TYPO3\CMS\Core\Resource\File;
 
 /**
  * A "mount point" inside the TYPO3 file handling.
@@ -613,7 +615,7 @@ class ResourceStorage {
                }
 
                $isMissing = FALSE;
-               if (!$isProcessedFile) {
+               if (!$isProcessedFile && $file instanceof File) {
                        $isMissing = $file->isMissing();
                }
 
@@ -899,10 +901,9 @@ class ResourceStorage {
         * Checks for permissions to move a file.
         *
         * @throws \RuntimeException
-        * @throws Exception\InsufficientFileReadPermissionsException
-        * @throws Exception\InsufficientFileWritePermissionsException
         * @throws Exception\InsufficientFolderAccessPermissionsException
         * @throws Exception\InsufficientUserPermissionsException
+        * @throws Exception\IllegalFileExtensionException
         * @param FileInterface $file
         * @param Folder $targetFolder
         * @param string $targetFileName
@@ -1103,7 +1104,9 @@ class ResourceStorage {
                        throw new \InvalidArgumentException('File "' . $localFilePath . '" does not exist.', 1319552745);
                }
                $file = $this->driver->addFile($localFilePath, $this->getProcessingFolder(), $processedFile->getName());
-               $file->setIndexable(FALSE);
+               if ($file instanceof File) {
+                       $file->setIndexable(FALSE);
+               }
                return $file;
        }
 
@@ -1182,7 +1185,11 @@ class ResourceStorage {
         * @return FileInterface
         */
        public function getFile($identifier) {
-               return $this->driver->getFile($identifier);
+               $file =  $this->getFileFactory()->getFileObjectByStorageAndIdentifier($this->getUid(), $identifier);
+               if (!$this->driver->fileExists($identifier)) {
+                       $file->setMissing(TRUE);
+               }
+               return $file;
        }
 
        /**
@@ -1200,11 +1207,11 @@ class ResourceStorage {
         *
         * @param string $identifier
         *
-        * @throws \BadMethodCallException
         * @return array
+        * @internal
         */
        public function getFileInfoByIdentifier($identifier) {
-               throw new \BadMethodCallException('The method ResourceStorage::getFileInfoByIdentifier() has been deprecated. Please fix your method call and use getFileInfo with the file object instead.', 1346577887);
+               return $this->driver->getFileInfoByIdentifier($identifier);
        }
 
        /**
@@ -1370,7 +1377,9 @@ class ResourceStorage {
                        throw new Exception\FileOperationErrorException('Deleting the file "' . $fileObject->getIdentifier() . '\' failed.', 1329831691);
                }
                // Mark the file object as deleted
-               $fileObject->setDeleted();
+               if ($fileObject instanceof File) {
+                       $fileObject->setDeleted();
+               }
 
                $this->emitPostFileDeleteSignal($fileObject);
 
@@ -1494,7 +1503,7 @@ class ResourceStorage {
                        $newProperties['storage'] = $storage->getUid();
                }
                $file->updateProperties($newProperties);
-               $this->getFileRepository()->update($file);
+               $this->getFileIndexRepository()->update($file);
        }
 
        /**
@@ -1522,7 +1531,6 @@ class ResourceStorage {
                try {
                        $newIdentifier = $this->driver->renameFile($file, $targetFileName);
                        $this->updateFile($file, $newIdentifier);
-                       $this->getFileRepository()->update($file);
                } catch (\RuntimeException $e) {
 
                }
@@ -1635,7 +1643,7 @@ class ResourceStorage {
                foreach ($fileObjects as $oldIdentifier => $fileObject) {
                        $newIdentifier = $fileMappings[$oldIdentifier];
                        $fileObject->updateProperties(array('storage' => $this, 'identifier' => $newIdentifier));
-                       $this->getFileRepository()->update($fileObject);
+                       $this->getFileIndexRepository()->update($fileObject);
                }
                $returnObject = $this->getFolder($fileMappings[$folderToMove->getIdentifier()]);
                $this->emitPostFolderMoveSignal($folderToMove, $targetParentFolder, $newFolderName);
@@ -1731,7 +1739,7 @@ class ResourceStorage {
                foreach ($fileObjects as $oldIdentifier => $fileObject) {
                        $newIdentifier = $fileMappings[$oldIdentifier];
                        $fileObject->updateProperties(array('identifier' => $newIdentifier));
-                       $this->getFileRepository()->update($fileObject);
+                       $this->getFileIndexRepository()->update($fileObject);
                }
                $returnObject = $this->getFolder($fileMappings[$folderObject->getIdentifier()]);
 
@@ -2251,6 +2259,13 @@ class ResourceStorage {
        }
 
        /**
+        * @return \TYPO3\CMS\Core\Resource\Index\FileIndexRepository
+        */
+       protected function getFileIndexRepository() {
+               return FileIndexRepository::getInstance();
+       }
+
+       /**
         * @return Service\FileProcessingService
         */
        protected function getFileProcessingService() {
index 7a48458..b5a9a19 100644 (file)
@@ -26,6 +26,9 @@ namespace TYPO3\CMS\Core\Resource\Service;
  *
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
+use TYPO3\CMS\Core\Resource\File;
+use TYPO3\CMS\Core\Resource\Index\FileIndexRepository;
+
 /**
  * Indexer for the virtual file system
  * should only be accessed through the FileRepository for now
@@ -65,6 +68,14 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
        }
 
        /**
+        * @return \TYPO3\CMS\Core\Resource\Index\FileIndexRepository
+        */
+       protected function getFileIndexRepository() {
+               return FileIndexRepository::getInstance();
+       }
+
+
+       /**
         * Setter function for the fileFactory
         * returns the object itself for chaining purposes
         *
@@ -79,11 +90,12 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
        /**
         * Creates or updates a file index entry from a file object.
         *
-        * @param \TYPO3\CMS\Core\Resource\File $fileObject
+        * @param File $fileObject
         * @param bool $updateObject Set this to FALSE to get the indexed values. You have to take care of updating the object yourself then!
-        * @return \TYPO3\CMS\Core\Resource\File|array the indexed $fileObject or an array of indexed properties.
+        * @return File|array the indexed $fileObject or an array of indexed properties.
+        * @throws \RuntimeException
         */
-       public function indexFile(\TYPO3\CMS\Core\Resource\File $fileObject, $updateObject = TRUE) {
+       public function indexFile(File $fileObject, $updateObject = TRUE) {
                // Get the file information of this object
                $fileInfo = $this->gatherFileInformation($fileObject);
                // Signal slot BEFORE the file was indexed
@@ -102,16 +114,21 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
                } else {
                        // Check if a file has been moved outside of FAL -- we have some
                        // orphaned index record in this case we could update
-                       $otherFiles = $this->getRepository()->findBySha1Hash($fileInfo['sha1']);
+                       $resultRows = $this->getFileIndexRepository()->findByContentHash($fileInfo['sha1']);
+                       $otherFiles = array();
+                       foreach ($resultRows as $row) {
+                               $otherFiles[] = $this->factory->getFileObject($row['uid'], $row);
+                       }
+
                        $movedFile = FALSE;
-                       /** @var $otherFile \TYPO3\CMS\Core\Resource\File */
+                       /** @var $otherFile File */
                        foreach ($otherFiles as $otherFile) {
                                if (!$otherFile->exists()) {
                                        // @todo: create a log entry
                                        $movedFile = TRUE;
                                        $fileInfo['missing'] = 0;
                                        $otherFile->updateProperties($fileInfo);
-                                       $this->getRepository()->update($otherFile);
+                                       $this->getFileIndexRepository()->update($otherFile);
                                        $fileInfo['uid'] = $otherFile->getUid();
                                        $fileObject = $otherFile;
                                        // Skip the rest of the files here as we might have more files that are missing, but we can only
@@ -156,7 +173,7 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
         * Indexes an array of file objects
         * currently this is done in a simple way, however could be changed to be more performant
         *
-        * @param \TYPO3\CMS\Core\Resource\File[] $fileObjects
+        * @param File[] $fileObjects
         * @return void
         */
        public function indexFiles(array $fileObjects) {
@@ -194,10 +211,10 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
                // check for deleted files (file not found during indexing are marked as missing)
                foreach ($this->getRepository()->getFileIndexRecordsForFolder($folder) as $file) {
                        if (!in_array($file['identifier'], $fileIdentifiers)) {
-                               /** @var $fileObject \TYPO3\CMS\Core\Resource\File */
+                               /** @var $fileObject File */
                                $fileObject = $this->getRepository()->findByIdentifier($file['uid']);
                                $fileObject->setMissing(TRUE);
-                               $this->getRepository()->update($fileObject);
+                               $this->getFileIndexRepository()->update($fileObject);
                        }
                }
 
@@ -222,10 +239,10 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
         * this function shouldn't be used, if someone needs to fetch the file information
         * from a file object, should be done by getProperties etc
         *
-        * @param \TYPO3\CMS\Core\Resource\File $file the file to fetch the information from
+        * @param File $file the file to fetch the information from
         * @return array the file information as an array
         */
-       protected function gatherFileInformation(\TYPO3\CMS\Core\Resource\File $file) {
+       protected function gatherFileInformation(File $file) {
                $fileInfo = new \ArrayObject(array());
                $gatherDefaultInformation = new \stdClass();
                $gatherDefaultInformation->getDefaultFileInfo = 1;
@@ -262,24 +279,24 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
         * Signal that is called before the file information is fetched
         * helpful if somebody wants to preprocess the record information
         *
-        * @param \TYPO3\CMS\Core\Resource\File $fileObject
+        * @param File $fileObject
         * @param array $fileInfo
         * @param boolean $gatherDefaultInformation
         * @signal
         */
-       protected function emitPreGatherFileInformationSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo, $gatherDefaultInformation) {
+       protected function emitPreGatherFileInformationSignal(File $fileObject, $fileInfo, $gatherDefaultInformation) {
                $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'preGatherFileInformation', array($fileObject, $fileInfo, $gatherDefaultInformation));
        }
 
        /**
         * Signal that is called after a file object was indexed
         *
-        * @param \TYPO3\CMS\Core\Resource\File $fileObject
+        * @param File $fileObject
         * @param array $fileInfo
         * @param boolean $hasGatheredDefaultInformation
         * @signal
         */
-       protected function emitPostGatherFileInformationSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo, $hasGatheredDefaultInformation) {
+       protected function emitPostGatherFileInformationSignal(File $fileObject, $fileInfo, $hasGatheredDefaultInformation) {
                $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'postGatherFileInformation', array($fileObject, $fileInfo, $hasGatheredDefaultInformation));
        }
 
@@ -306,22 +323,22 @@ class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
        /**
         * Signal that is called before a file object was indexed
         *
-        * @param \TYPO3\CMS\Core\Resource\File $fileObject
+        * @param File $fileObject
         * @param array $fileInfo
         * @signal
         */
-       protected function emitPreFileIndexSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo) {
+       protected function emitPreFileIndexSignal(File $fileObject, $fileInfo) {
                $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'preFileIndex', array($fileObject, $fileInfo));
        }
 
        /**
         * Signal that is called after a file object was indexed
         *
-        * @param \TYPO3\CMS\Core\Resource\File $fileObject
+        * @param File $fileObject
         * @param array $fileInfo
         * @signal
         */
-       protected function emitPostFileIndexSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo) {
+       protected function emitPostFileIndexSignal(File $fileObject, $fileInfo) {
                $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'postFileIndex', array($fileObject, $fileInfo));
        }
 
index 0143aa5..92e7d43 100644 (file)
@@ -75,6 +75,11 @@ class ExtendedFileUtility extends \TYPO3\CMS\Core\Utility\File\BasicFileUtility
         */
        public $dontCheckForUnique = 0;
 
+       /**
+        * @var \TYPO3\CMS\Core\Resource\Service\IndexerService
+        */
+       protected $indexerService = NULL;
+
        // This array is self-explaining (look in the class below).
        // It grants access to the functions. This could be set from outside in order to enabled functions to users.
        // See also the function init_actionPerms() which takes input directly from the user-record
@@ -934,7 +939,7 @@ class ExtendedFileUtility extends \TYPO3\CMS\Core\Utility\File\BasicFileUtility
                                }
                                /** @var $fileObject File */
                                $fileObject = $targetFolderObject->addUploadedFile($fileInfo, $conflictMode);
-                               $this->fileRepository->addToIndex($fileObject);
+                               $this->getIndexerService()->indexFile($fileObject, FALSE);
                                $resultObjects[] = $fileObject;
                                $this->writelog(1, 0, 1, 'Uploading file "%s" to "%s"', array($fileInfo['name'], $targetFolderObject->getIdentifier()));
                        } catch (\TYPO3\CMS\Core\Resource\Exception\UploadException $e) {
@@ -1042,4 +1047,17 @@ class ExtendedFileUtility extends \TYPO3\CMS\Core\Utility\File\BasicFileUtility
        protected function getBackendUser() {
                return $GLOBALS['BE_USER'];
        }
+
+       /**
+        * Internal function to retrieve the indexer service,
+        * if it does not exist, an instance will be created
+        *
+        * @return \TYPO3\CMS\Core\Resource\Service\IndexerService
+        */
+       protected function getIndexerService() {
+               if ($this->indexerService === NULL) {
+                       $this->indexerService = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService');
+               }
+               return $this->indexerService;
+       }
 }
index f9967b6..8dd4cee 100644 (file)
@@ -126,10 +126,11 @@ class FactoryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         */
        public function retrieveFileOrFolderObjectReturnsFileIfPathIsGiven() {
                $filename = 'typo3temp/4711.txt';
-               $storage = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('getFile', 'getFolder'), array(), '', FALSE);
+               $storage = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array('getFileInfoByIdentifier', 'getFolder'), array(), '', FALSE);
                $storage->expects($this->once())
-                       ->method('getFile')
-                       ->with($filename);
+                       ->method('getFileInfoByIdentifier')
+                       ->with($filename)
+                       ->will($this->returnValue(array('uid' => 4811)));
                $this->fixture->_set('storageInstances', array(0 => $storage));
                // Create and prepare test file
                \TYPO3\CMS\Core\Utility\GeneralUtility::writeFileToTypo3tempDir(PATH_site . $filename, '42');
index 84deacc..0c6292e 100644 (file)
@@ -50,9 +50,9 @@ class TtContentUploadsUpdateWizard extends AbstractUpdate {
        protected $fileFactory;
 
        /**
-        * @var \TYPO3\CMS\Core\Resource\FileRepository
+        * @var \TYPO3\CMS\Core\Resource\Index\FileIndexRepository
         */
-       protected $fileRepository;
+       protected $fileIndexRepository;
 
        /**
         * @var \TYPO3\CMS\Core\Resource\ResourceStorage
@@ -83,7 +83,7 @@ class TtContentUploadsUpdateWizard extends AbstractUpdate {
                        throw new \RuntimeException('Local default storage could not be initialized - might be due to missing sys_file* tables.');
                }
                $this->fileFactory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory');
-               $this->fileRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
+               $this->fileIndexRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Index\\FileIndexRepository');
                $this->targetDirectory = PATH_site . $fileadminDirectory . self::FOLDER_ContentUploads . '/';
        }
 
@@ -165,7 +165,7 @@ class TtContentUploadsUpdateWizard extends AbstractUpdate {
                        if (file_exists(PATH_site . 'uploads/media/' . $file)) {
                                \TYPO3\CMS\Core\Utility\GeneralUtility::upload_copy_move(PATH_site . 'uploads/media/' . $file, $this->targetDirectory . $file);
                                $fileObject = $this->storage->getFile(self::FOLDER_ContentUploads . '/' . $file);
-                               $this->fileRepository->addToIndex($fileObject);
+                               $this->fileIndexRepository->add($fileObject);
                                $dataArray = array(
                                        'uid_local' => $fileObject->getUid(),
                                        'tablenames' => 'tt_content',