[TASK] FAL-Drivers: Make getFileInfo more versatile and performant 64/23464/8
authorSteffen Ritter <info@rs-websystems.de>
Thu, 29 Aug 2013 13:15:54 +0000 (15:15 +0200)
committerOliver Hader <oliver.hader@typo3.org>
Fri, 11 Oct 2013 13:13:48 +0000 (15:13 +0200)
If a storage needs information about a file, it always has
to retrieve all information about the file from the driver.
This can be very expensive - especially if only the modification
timestamp would be relevant, but sha1 content hash as well
as creation time, access time, size, mimetype ... are detected.
This patch extends the interface with a possibility to only
retrieve a subset of these information. As drivers are only
accessible through an ResourceStorage and the new parameters
are optional this patch does not change behaviour or break
backwards compatiblity.

Releases: 6.2
Resolves: #51515
Change-Id: I45dec41e3f6cfa2d6c8902b795dc224c729296f8
Reviewed-on: https://review.typo3.org/23464
Tested-by: Oliver Hader
Reviewed-by: Oliver Hader
typo3/sysext/core/Classes/Resource/Driver/AbstractDriver.php
typo3/sysext/core/Classes/Resource/Driver/LocalDriver.php
typo3/sysext/core/Tests/Unit/Resource/Driver/LocalDriverTest.php

index 0ff8079..62819e1 100644 (file)
@@ -376,9 +376,10 @@ abstract class AbstractDriver {
         * Returns information about a file for a given file identifier.
         *
         * @param string $identifier The (relative) path to the file.
+        * @param array $propertiesToExtract Array of properties which should be extracted, if empty all will be extracted
         * @return array
         */
-       abstract public function getFileInfoByIdentifier($identifier);
+       abstract public function getFileInfoByIdentifier($identifier, array $propertiesToExtract = array());
 
        /**
         * Basic implementation of the method that does directly return the
@@ -396,16 +397,18 @@ abstract class AbstractDriver {
         * Returns information about a file for a given file object.
         *
         * @param \TYPO3\CMS\Core\Resource\FileInterface $file
+        * @param array $propertiesToExtract Array of properties which should be extracted, if empty all will be extracted
         * @return array
         */
-       public function getFileInfo(\TYPO3\CMS\Core\Resource\FileInterface $file) {
-               return $this->getFileInfoByIdentifier($file->getIdentifier());
+       public function getFileInfo(\TYPO3\CMS\Core\Resource\FileInterface $file, array $propertiesToExtract = array()) {
+               return $this->getFileInfoByIdentifier($file->getIdentifier(), $propertiesToExtract);
        }
 
        /**
         * Returns a file object by its identifier.
         *
         * @param string $identifier
+        * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
         * @return \TYPO3\CMS\Core\Resource\FileInterface
         */
        public function getFile($identifier) {
@@ -459,6 +462,7 @@ abstract class AbstractDriver {
         * @param string $itemIdentifier
         * @param string $parentIdentifier
         * @param array $additionalInformation Additional information about the inspected item
+        * @throws \RuntimeException
         * @return boolean
         */
        protected function applyFilterMethodsToDirectoryItem(array $filterMethods, $itemName, $itemIdentifier, $parentIdentifier, array $additionalInformation = array()) {
index a2cf8e0..57d78e1 100644 (file)
@@ -217,9 +217,11 @@ class LocalDriver extends AbstractHierarchicalFilesystemDriver {
         * Returns information about a file.
         *
         * @param string $fileIdentifier In the case of the LocalDriver, this is the (relative) path to the file.
+        * @param array $propertiesToExtract Array of properties which should be extracted, if empty all will be extracted
         * @return array
+        * @throws \InvalidArgumentException
         */
-       public function getFileInfoByIdentifier($fileIdentifier) {
+       public function getFileInfoByIdentifier($fileIdentifier, array $propertiesToExtract = array()) {
                // Makes sure the Path given as parameter is valid
                $fileIdentifier = $this->canonicalizeAndCheckFilePath($fileIdentifier);
                $dirPath = PathUtility::dirname($fileIdentifier);
@@ -234,7 +236,7 @@ class LocalDriver extends AbstractHierarchicalFilesystemDriver {
                if (!file_exists($absoluteFilePath)) {
                        throw new \InvalidArgumentException('File ' . $fileIdentifier . ' does not exist.', 1314516809);
                }
-               return $this->extractFileInformation($absoluteFilePath, $dirPath);
+               return $this->extractFileInformation($absoluteFilePath, $dirPath, $propertiesToExtract);
        }
 
 
@@ -463,24 +465,54 @@ class LocalDriver extends AbstractHierarchicalFilesystemDriver {
         *
         * @param string $filePath The absolute path to the file
         * @param string $containerPath The relative path to the file's container
+        * @param array $propertiesToExtract array of properties which should be returned, if empty all will be extracted
         * @return array
         */
-       protected function extractFileInformation($filePath, $containerPath) {
-               $fileName = PathUtility::basename($filePath);
-               $fileInformation = array(
-                       'size' => filesize($filePath),
-                       'atime' => fileatime($filePath),
-                       'mtime' => filemtime($filePath),
-                       'ctime' => filectime($filePath),
-                       'mimetype' => $this->getMimeTypeOfFile($filePath),
-                       'name' => $fileName,
-                       'identifier' => $containerPath . $fileName,
-                       'storage' => $this->storage->getUid()
-               );
+       protected function extractFileInformation($filePath, $containerPath, array $propertiesToExtract = array()) {
+               if (count($propertiesToExtract) === 0) {
+                       $propertiesToExtract = array('size', 'atime', 'atime', 'mtime', 'ctime', 'mimetype', 'name', 'identifier', 'storage');
+               }
+               $fileInformation = array();
+               foreach ($propertiesToExtract as $property) {
+                       $fileInformation[$property] = $this->getSpecificFileInformation($filePath, $containerPath, $property);
+               }
                return $fileInformation;
        }
 
        /**
+        * Extracts a specific FileInformation from the FileSystems.
+        *
+        * @param string $filePath
+        * @param string $containerPath
+        * @param string $property
+        *
+        * @return bool|int|string
+        * @throws \InvalidArgumentException
+        */
+       public function getSpecificFileInformation($filePath, $containerPath, $property) {
+               switch ($property) {
+                       case 'size':
+                               return filesize($filePath);
+                       case 'atime':
+                               return fileatime($filePath);
+                       case 'mtime':
+                               return filemtime($filePath);
+                       case 'ctime':
+                               return filectime($filePath);
+                       case 'name':
+                               return PathUtility::basename($filePath);
+                       case 'mimetype':
+                               return $this->getMimeTypeOfFile($filePath);
+                       case 'identifier':
+                               return $containerPath . PathUtility::basename($filePath);
+                       case 'storage':
+                               return $this->storage->getUid();
+                       default:
+                               throw new \InvalidArgumentException(sprintf('The information "%s" is not available.', $property));
+               }
+       }
+
+       /**
         * Extracts information about a folder from the filesystem.
         *
         * @param string $folderPath The absolute path to the folder
@@ -529,32 +561,6 @@ class LocalDriver extends AbstractHierarchicalFilesystemDriver {
        }
 
        /**
-        * Returns metadata of a file (size, times, mimetype)
-        *
-        * @param \TYPO3\CMS\Core\Resource\FileInterface $file
-        * @return array
-        */
-       public function getLowLevelFileInfo(\TYPO3\CMS\Core\Resource\FileInterface $file) {
-               // TODO define which data should be returned
-               // TODO write unit test
-               // TODO cache this info. Registry?
-               // TODO merge with extractFolderInformation() above?!
-               $filePath = $this->getAbsolutePath($file);
-               $fileStat = stat($filePath);
-               $mimeType = $this->getMimeTypeOfFile($filePath);
-               $stat = array(
-                       'size' => filesize($filePath),
-                       'atime' => $fileStat['atime'],
-                       'mtime' => $fileStat['mtime'],
-                       'ctime' => $fileStat['ctime'],
-                       'nlink' => $fileStat['nlink'],
-                       'type' => $mimeType,
-                       'mimetype' => $mimeType
-               );
-               return $stat;
-       }
-
-       /**
         * Get MIME type of file.
         *
         * @param string $absoluteFilePath Absolute path to file
index b22de4f..e1787fc 100644 (file)
@@ -292,91 +292,6 @@ class LocalDriverTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
        /**
         * @test
         */
-       public function getLowLevelFileInfoReturnsCorrectFileSize() {
-               $contents = uniqid('foo');
-               $this->addToMount(array('file1.ext' => $contents));
-               $mockedFile = $this->getSimpleFileMock('file1.ext');
-               $fixture = $this->createDriverFixture(
-                       array('basePath' => $this->getMountRootUrl()),
-                       NULL,
-                               // Mocked because finfo() can not deal with vfs streams and throws warnings
-                       array('getMimeTypeOfFile')
-               );
-               $stat = $fixture->getLowLevelFileInfo($mockedFile);
-               $this->assertEquals(strlen($contents), $stat['size']);
-       }
-
-       /**
-        * @test
-        */
-       public function getLowLevelFileInfoReturnsCorrectFileCtime() {
-               $contents = uniqid('foo');
-               $this->addToMount(array('file1.ext' => $contents));
-               $mockedFile = $this->getSimpleFileMock('file1.ext');
-               $fixture = $this->createDriverFixture(
-                       array('basePath' => $this->getMountRootUrl()),
-                       NULL,
-                               // Mocked because finfo() can not deal with vfs streams and throws warnings
-                       array('getMimeTypeOfFile')
-               );
-               $path = $fixture->getAbsolutePath($mockedFile);
-               $stat = $fixture->getLowLevelFileInfo($mockedFile);
-               $this->assertEquals(filectime($path), $stat['ctime']);
-       }
-
-       /**
-        * @test
-        */
-       public function getLowLevelFileInfoReturnsCorrectFileMtime() {
-               $contents = uniqid('foo');
-               $this->addToMount(array('file1.ext' => $contents));
-               $mockedFile = $this->getSimpleFileMock('file1.ext');
-               $fixture = $this->createDriverFixture(
-                       array('basePath' => $this->getMountRootUrl()),
-                       NULL,
-                               // Mocked because finfo() can not deal with vfs streams and throws warnings
-                       array('getMimeTypeOfFile')
-               );
-               $path = $fixture->getAbsolutePath($mockedFile);
-               $stat = $fixture->getLowLevelFileInfo($mockedFile);
-               $this->assertEquals(fileatime($path), $stat['mtime']);
-       }
-
-       /**
-        * @test
-        */
-       public function getLowLevelFileInfoReturnsCorrectFileAtime() {
-               $contents = uniqid('foo');
-               $this->addToMount(array('file1.ext' => $contents));
-               $mockedFile = $this->getSimpleFileMock('file1.ext');
-               $fixture = $this->createDriverFixture(
-                       array('basePath' => $this->getMountRootUrl()),
-                       NULL,
-                               // Mocked because finfo() can not deal with vfs streams and throws warnings
-                       array('getMimeTypeOfFile')
-               );
-               $path = $fixture->getAbsolutePath($mockedFile);
-               $stat = $fixture->getLowLevelFileInfo($mockedFile);
-               $this->assertEquals(filemtime($path), $stat['atime']);
-       }
-
-       /**
-        * @test
-        */
-       public function getLowLevelFileInfoReturnsCorrectFileMimeType() {
-               $baseDir = $this->createRealTestdir();
-               /** @var $driverFixture \TYPO3\CMS\Core\Resource\Driver\LocalDriver */
-               $driverFixture = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Driver\\LocalDriver', array('getAbsolutePath'), array());
-               $fileMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\FileInterface');
-               copy(__DIR__ . '/Fixtures/Dummy.html', $baseDir . '/Dummy.html');
-               $driverFixture->expects($this->once())->method('getAbsolutePath')->will($this->returnValue($baseDir . '/Dummy.html'));
-               $stats = $driverFixture->getLowLevelFileInfo($fileMock);
-               $this->assertEquals('text/html', $stats['mimetype']);
-       }
-
-       /**
-        * @test
-        */
        public function addFileMovesFileToCorrectLocation() {
                $mockedFolder = $this->getSimpleFolderMock('/targetFolder/');
                $this->addToMount(array('targetFolder' => array()));