[BUGFIX] Folder: File list filtering does not work
authorAndreas Wolf <andreas.wolf@typo3.org>
Mon, 8 Oct 2012 14:36:27 +0000 (16:36 +0200)
committerSteffen Ritter <info@rs-websystems.de>
Thu, 1 Nov 2012 13:21:13 +0000 (14:21 +0100)
To filter a file list for certain file extensions, the
FileExtensionFilter class should be used. However, the element browser
currently tries to directly call getFiles() with a file extension list.

This commit adds filter handling methods to Folder and changes the EBs
behaviour to use them. The public interface of Folder::getFiles() and
Folder::getSubfolders() is extended, but in a backwards-compatible way,
so this is no breaking change.

Change-Id: Ib45d5f0a99c038841193ed568d7ebf8289f629d3
Resolves: #41725
Releases: 6.0
Reviewed-on: http://review.typo3.org/15405
Reviewed-by: Dominik Mathern
Tested-by: Dominik Mathern
Reviewed-by: Steffen Ritter
Tested-by: Steffen Ritter
typo3/sysext/core/Classes/Resource/Folder.php
typo3/sysext/core/Tests/Functional/Resource/BaseTestCase.php [new file with mode: 0644]
typo3/sysext/core/Tests/Functional/Resource/FolderTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Resource/FolderTest.php

index dde72cd..0140774 100644 (file)
@@ -69,6 +69,24 @@ class Folder implements \TYPO3\CMS\Core\Resource\FolderInterface {
        protected $name;
 
        /**
+        * The filters this folder should use for a file list.
+        *
+        * @var callable[]
+        */
+       protected $fileAndFolderNameFilters = array();
+
+       /**
+        * Modes for filter usage in getFiles()/getFolders()
+        */
+       const FILTER_MODE_NO_FILTERS = 0;
+       // Merge local filters into storage's filters
+       const FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS = 1;
+       // Only use the filters provided by the storage
+       const FILTER_MODE_USE_STORAGE_FILTERS = 2;
+       // Only use the filters provided by the current class
+       const FILTER_MODE_USE_OWN_FILTERS = 3;
+
+       /**
         * Initialization of the folder
         *
         * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storage
@@ -151,23 +169,38 @@ class Folder implements \TYPO3\CMS\Core\Resource\FolderInterface {
        }
 
        /**
-        * Returns a list of files in this folder, optionally filtered by the given pattern.
-        * For performance reasons the returned items can be limited to a given range
+        * Returns a list of files in this folder, optionally filtered. There are several filter modes available, see the
+        * FILTER_MODE_* constants for more information.
+        *
+        * For performance reasons the returned items can also be limited to a given range
         *
         * @param integer $start The item to start at
         * @param integer $numberOfItems The number of items to return
-        * @param boolean $useFilters
+        * @param integer $filterMode The filter mode to use for the file list.
         * @return \TYPO3\CMS\Core\Resource\File[]
         */
-       public function getFiles($start = 0, $numberOfItems = 0, $useFilters = TRUE) {
-               // TODO fetch
+       public function getFiles($start = 0, $numberOfItems = 0, $filterMode = self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS) {
+               $useFilters = TRUE;
+
+               // Fallback for compatibility with the old method signature variable $useFilters that was used instead of $filterMode
+               if ($filterMode === TRUE) {
+                       $filterMode = self::FILTER_MODE_USE_STORAGE_FILTERS;
+               } elseif ($filterMode === FALSE) {
+                       $useFilters = FALSE;
+               } else {
+                       list($backedUpFilters, $useFilters) = $this->prepareFiltersInStorage($filterMode);
+               }
+
                /** @var $factory \TYPO3\CMS\Core\Resource\ResourceFactory */
                $factory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory');
                $fileArray = $this->storage->getFileList($this->identifier, $start, $numberOfItems, $useFilters);
                $fileObjects = array();
                foreach ($fileArray as $fileInfo) {
-                       $fileObjects[] = $factory->createFileObject($fileInfo);
+                       $fileObjects[$fileInfo['name']] = $factory->createFileObject($fileInfo);
                }
+
+               $this->restoreBackedUpFiltersInStorage($backedUpFilters);
+
                return $fileObjects;
        }
 
@@ -202,15 +235,18 @@ class Folder implements \TYPO3\CMS\Core\Resource\FolderInterface {
        }
 
        /**
-        * Returns a list of all subfolders
+        * Returns a list of subfolders
         *
         * @param integer $start The item to start at
         * @param integer $numberOfItems The number of items to return
+        * @param integer $filterMode The filter mode to use for the file list.
         * @return \TYPO3\CMS\Core\Resource\Folder[]
         */
-       public function getSubfolders($start = 0, $numberOfItems = 0) {
+       public function getSubfolders($start = 0, $numberOfItems = 0, $filterMode = self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS) {
+               list($backedUpFilters, $useFilters) = $this->prepareFiltersInStorage($filterMode);
+
                $folderObjects = array();
-               $folderArray = $this->storage->getFolderList($this->identifier, $start, $numberOfItems);
+               $folderArray = $this->storage->getFolderList($this->identifier, $start, $numberOfItems, $useFilters);
                if (count($folderArray) > 0) {
                        /** @var $factory \TYPO3\CMS\Core\Resource\ResourceFactory */
                        $factory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\ResourceFactory');
@@ -221,6 +257,9 @@ class Folder implements \TYPO3\CMS\Core\Resource\FolderInterface {
                                $folderObjects[$folder['name']] = $factory->createFolderObject($this->storage, $this->identifier . $folder['name'] . '/', $folder['name']);
                        }
                }
+
+               $this->restoreBackedUpFiltersInStorage($backedUpFilters);
+
                return $folderObjects;
        }
 
@@ -362,6 +401,69 @@ class Folder implements \TYPO3\CMS\Core\Resource\FolderInterface {
                }
        }
 
+       /**
+        * Prepares the filters in this folder's storage according to a set filter mode.
+        *
+        * @param integer $filterMode The filter mode to use; one of the FILTER_MODE_* constants
+        * @return array The backed up filters as an array (NULL if filters were not backed up) and whether to use filters or not (boolean)
+        */
+       protected function prepareFiltersInStorage($filterMode) {
+               $backedUpFilters = NULL;
+               $useFilters = TRUE;
+
+               switch ($filterMode) {
+                       case self::FILTER_MODE_USE_OWN_FILTERS:
+                               $backedUpFilters = $this->storage->getFileAndFolderNameFilters();
+                               $this->storage->setFileAndFolderNameFilters($this->fileAndFolderNameFilters);
+
+                               break;
+
+                       case self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS:
+                               if (count($this->fileAndFolderNameFilters) > 0) {
+                                       $backedUpFilters = $this->storage->getFileAndFolderNameFilters();
+                                       foreach ($this->fileAndFolderNameFilters as $filter) {
+                                               $this->storage->addFileAndFolderNameFilter($filter);
+                                       }
+                               }
+
+                               break;
+
+                       case self::FILTER_MODE_USE_STORAGE_FILTERS:
+                               // nothing to do here
+
+                               break;
+
+                       case self::FILTER_MODE_NO_FILTERS:
+                               $useFilters = FALSE;
+
+                               break;
+               }
+               return array($backedUpFilters, $useFilters);
+       }
+
+       /**
+        * Restores the filters of a storage.
+        *
+        * @param array $backedUpFilters The filters to restore; might be NULL if no filters have been backed up, in
+        *                               which case this method does nothing.
+        * @see prepareFiltersInStorage()
+        */
+       protected function restoreBackedUpFiltersInStorage($backedUpFilters) {
+               if ($backedUpFilters !== NULL) {
+                       $this->storage->setFileAndFolderNameFilters($backedUpFilters);
+               }
+       }
+
+       /**
+        * Sets the filters to use when listing files. These are only used if the filter mode is one of
+        * FILTER_MODE_USE_OWN_FILTERS and FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
+        *
+        * @param array $filters
+        */
+       public function setFileAndFolderNameFilters(array $filters) {
+               $this->fileAndFolderNameFilters = $filters;
+       }
+
 }
 
 
diff --git a/typo3/sysext/core/Tests/Functional/Resource/BaseTestCase.php b/typo3/sysext/core/Tests/Functional/Resource/BaseTestCase.php
new file mode 100644 (file)
index 0000000..0769370
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\Resource;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Andreas Wolf <andreas.wolf@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!
+ ***************************************************************/
+
+require_once 'vfsStream/vfsStream.php';
+
+/**
+ * Basic functional test class for the File Abstraction Layer (FAL).
+ *
+ * @author Andreas Wolf <andreas.wolf@typo3.org>
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class BaseTestCase extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
+       public function getStorageObject() {
+               $this->initializeVfs();
+               $resourceFactory = new \TYPO3\CMS\Core\Resource\ResourceFactory();
+               return $resourceFactory->createStorageObject(array(
+                       'driver' => 'Local'
+               ), array('basePath' => $this->getMountRootUrl()));
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Functional/Resource/FolderTest.php b/typo3/sysext/core/Tests/Functional/Resource/FolderTest.php
new file mode 100644 (file)
index 0000000..ba6569f
--- /dev/null
@@ -0,0 +1,215 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Functional\Resource;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Andreas Wolf <andreas.wolf@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\Resource;
+
+require_once 'vfsStream/vfsStream.php';
+
+/**
+ * Functional test case for the FAL folder class.
+ *
+ * @author Andreas Wolf <andreas.wolf@typo3.org>
+ * @package TYPO3
+ */
+class FolderTest extends BaseTestCase {
+
+       /**
+        * Helper method for testing restore of filters in the storage
+        *
+        * @param $filterMode
+        * @param callable $listCallback
+        */
+       protected function _testFileAndFoldernameFilterRestoreAfterList($filterMode, callable $listCallback) {
+               $storageFilter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $storageFilter->setAllowedFileExtensions('jpg,png');
+               $folderFilter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $folderFilter->setAllowedFileExtensions('png');
+
+               $storageObject = $this->getStorageObject();
+               $storageObject->setFileAndFolderNameFilters(array(array($storageFilter, 'filterFileList')));
+               $folder = $storageObject->getRootLevelFolder();
+               $folder->setFileAndFolderNameFilters(array(array($storageFilter, 'filterFileList')));
+
+               $filtersBackup = $storageObject->getFileAndFolderNameFilters();
+               $listCallback($folder, $filterMode);
+
+               $this->assertEquals($filtersBackup, $storageObject->getFileAndFolderNameFilters());
+       }
+
+
+       /***********************
+        * Tests for getFiles()
+        ***********************/
+
+       /**
+        * @test
+        */
+       public function getFilesRestoresFileAndFoldernameFiltersOfStorageAfterFetchingFileListIfFilterModeIsUseOwnFilters() {
+               $this->_testFileAndFoldernameFilterRestoreAfterList(\TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_FILTERS,
+                       function(Resource\Folder $folder, $filterMode) {
+                               $folder->getFiles(0, 0, $filterMode);
+                       }
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function getFilesRestoresFileAndFoldernameFiltersOfStorageAfterFetchingFileListIfFilterModeIsUseOwnAndStorageFiltersAndFiltersHaveBeenSetInFolder() {
+               $this->_testFileAndFoldernameFilterRestoreAfterList(\TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS,
+                       function(Resource\Folder $folder, $filterMode) {
+                               $folder->getFiles(0, 0, $filterMode);
+                       }
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function getFilesRespectsSetFileAndFoldernameFiltersIfFilterModeIsUseOwnFilters() {
+               $filter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $filter->setAllowedFileExtensions('jpg,png');
+
+               $this->addToMount(array('somefile.png' => '', 'somefile.jpg' => '', 'somefile.exe' => ''));
+               $storageObject = $this->getStorageObject();
+               $folder = $storageObject->getRootLevelFolder();
+               $folder->setFileAndFolderNameFilters(array(array($filter, 'filterFileList')));
+
+               $fileList = $folder->getFiles(0, 0, \TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_FILTERS);
+
+               $this->assertArrayNotHasKey('somefile.exe', $fileList);
+               $this->assertCount(2, $fileList);
+       }
+
+       /**
+        * @test
+        */
+       public function getFilesMergesSetFileAndFoldernameFiltersIntoStoragesFiltersIfFilterModeIsUseOwnAndStorageFilters() {
+               $foldersFilter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $foldersFilter->setAllowedFileExtensions('jpg,png');
+               $storagesFilter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $storagesFilter->setDisallowedFileExtensions('png');
+
+               $this->addToMount(array('somefile.png' => '', 'somefile.jpg' => '', 'somefile.exe' => ''));
+               $storageObject = $this->getStorageObject();
+               $storageObject->setFileAndFolderNameFilters(array(array($storagesFilter, 'filterFileList')));
+               $folder = $storageObject->getRootLevelFolder();
+               $folder->setFileAndFolderNameFilters(array(array($foldersFilter, 'filterFileList')));
+
+               $fileList = $folder->getFiles(0, 0, \TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS);
+
+               $this->assertArrayNotHasKey('somefile.exe', $fileList);
+               $this->assertArrayNotHasKey('somefile.png', $fileList);
+               $this->assertCount(1, $fileList);
+       }
+
+       /**
+        * @test
+        */
+       public function getFilesUsesOnlyFileAndFoldernameFiltersOfStorageIfNoFiltersAreSetAndFilterModeIsUseOwnAndStorageFilters() {
+               $filter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $filter->setAllowedFileExtensions('jpg,png');
+
+               $this->addToMount(array('somefile.png' => '', 'somefile.jpg' => '', 'somefile.exe' => ''));
+               $storageObject = $this->getStorageObject();
+               $folder = $storageObject->getRootLevelFolder();
+               $storageObject->setFileAndFolderNameFilters(array(array($filter, 'filterFileList')));
+
+               $fileList = $folder->getFiles(0, 0, \TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS);
+
+               $this->assertArrayNotHasKey('somefile.exe', $fileList);
+               $this->assertCount(2, $fileList);
+       }
+
+       /**
+        * @test
+        */
+       public function getFilesIgnoresSetFileAndFoldernameFiltersIfFilterModeIsSetToUseStorageFilters() {
+               $filter = new \TYPO3\CMS\Core\Resource\Filter\FileExtensionFilter();
+               $filter->setAllowedFileExtensions('jpg,png');
+
+               $this->addToMount(array('somefile.png' => '', 'somefile.jpg' => '', 'somefile.exe' => ''));
+               $storageObject = $this->getStorageObject();
+               $folder = $storageObject->getRootLevelFolder();
+               $folder->setFileAndFolderNameFilters(array(array($filter, 'filterFileList')));
+
+               $fileList = $folder->getFiles(0, 0, \TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_STORAGE_FILTERS);
+
+               $this->assertCount(3, $fileList);
+       }
+
+
+       /****************************
+        * Tests for getSubfolders()
+        ****************************/
+
+       /**
+        * @test
+        */
+       public function getSubfoldersRestoresFileAndFoldernameFiltersOfStorageAfterFetchingFolderListIfFilterModeIsUseOwnFilters() {
+               $this->_testFileAndFoldernameFilterRestoreAfterList(\TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_FILTERS,
+                       function(Resource\Folder $folder, $filterMode) {
+                               $folder->getSubfolders(0, 0, $filterMode);
+                       }
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function getSubfoldersRestoresFileAndFoldernameFiltersOfStorageAfterFetchingFolderListIfFilterModeIsUseOwnAndStorageFiltersAndFiltersHaveBeenSetInFolder() {
+               $this->_testFileAndFoldernameFilterRestoreAfterList(\TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS,
+                       function(Resource\Folder $folder, $filterMode) {
+                               $folder->getSubfolders(0, 0, $filterMode);
+                       }
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function getSubfoldersRespectsSetFileAndFoldernameFiltersIfFilterModeIsUseOwnFilters() {
+               \TYPO3\CMS\Core\Resource\Filter\FileNameFilter::setShowHiddenFilesAndFolders(FALSE);
+
+               $this->addToMount(array('.hiddenFolder' => array(), 'someFolder' => array(), 'anotherFolder' => array()));
+               $storageObject = $this->getStorageObject();
+               $storageObject->setFileAndFolderNameFilters(array());
+               $folder = $storageObject->getRootLevelFolder();
+               $folder->setFileAndFolderNameFilters(array(array('TYPO3\\CMS\\Core\\Resource\\Filter\\FileNameFilter', 'filterHiddenFilesAndFolders')));
+
+               $folderList = $folder->getSubfolders(0, 0, \TYPO3\CMS\Core\Resource\Folder::FILTER_MODE_USE_OWN_FILTERS);
+
+               $this->assertArrayNotHasKey('.hiddenFolder', $folderList);
+               $this->assertCount(2, $folderList);
+       }
+
+       // TODO implement the other tests from getFiles
+}
+
+?>
\ No newline at end of file
index 17d8e7a..ee81d72 100644 (file)
@@ -96,6 +96,27 @@ class FolderTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        /**
         * @test
         */
+       public function getFilesReturnsArrayWithFilenamesAsKeys() {
+               $mockedStorage = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array(), array(), '', FALSE);
+               $mockedStorage->expects($this->once())->method('getFileList')->will($this->returnValue(array(
+                               'somefile.png' => array(
+                                       'name' => 'somefile.png'
+                               ),
+                               'somefile.jpg' => array(
+                                       'name' => 'somefile.jpg'
+                               )
+                       )
+               ));
+               $fixture = $this->createFolderFixture('/somePath', 'someName', $mockedStorage);
+
+               $fileList = $fixture->getFiles();
+
+               $this->assertEquals(array('somefile.png', 'somefile.jpg'), array_keys($fileList));
+       }
+
+       /**
+        * @test
+        */
        public function getSubfolderCallsFactoryWithCorrectArguments() {
                $mockedStorage = $this->getMock('TYPO3\\CMS\\Core\\Resource\\ResourceStorage', array(), array(), '', FALSE);
                $mockedStorage->expects($this->once())->method('hasFolderInFolder')->with($this->equalTo('someSubfolder'))->will($this->returnValue(TRUE));