[FEATURE] Human readable names for special folders 77/19177/12
authorStefan Neufeind <typo3.neufeind@speedpartner.de>
Fri, 22 Mar 2013 13:10:02 +0000 (14:10 +0100)
committerAndreas Wolf <andreas.wolf@typo3.org>
Tue, 2 Apr 2013 13:26:57 +0000 (15:26 +0200)
The names of some special folders (user upload,
temporary files, recycler) were historically
converted to a human readable string. This is partly
broken in the current version, especially the sorting
gets mixed up. This commit changes the concept to
make the mapping more flexible (i.e., the driver can
decide what folder has which special role) and also
fixes the name mapping and sorting.

Change-Id: Iaf7dee74f4d9031ed91b446937361ecdede9a0b5
Resolves: #46542
Releases: 6.1
Reviewed-on: https://review.typo3.org/19177
Tested-by: Philipp Gampe
Tested-by: Andreas Wolf
Reviewed-by: Philipp Gampe
Reviewed-by: Andreas Wolf
typo3/sysext/backend/Classes/Tree/View/FolderTreeView.php
typo3/sysext/core/Classes/Resource/Driver/LocalDriver.php
typo3/sysext/core/Classes/Resource/Folder.php
typo3/sysext/core/Classes/Resource/FolderInterface.php
typo3/sysext/core/Classes/Resource/ResourceStorage.php
typo3/sysext/core/Classes/Resource/Utility/ListUtility.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Resource/ResourceStorageTest.php
typo3/sysext/filelist/Classes/FileList.php
typo3/sysext/lang/locallang_mod_file_list.xlf

index 110db2b..d2827f0 100644 (file)
@@ -328,13 +328,17 @@ class FolderTreeView extends \TYPO3\CMS\Backend\Tree\View\AbstractTreeView {
         */
        public function getFolderTree(\TYPO3\CMS\Core\Resource\Folder $folderObject, $depth = 999, $type = '') {
                $depth = intval($depth);
+
                // This generates the directory tree
+               /* array of \TYPO3\CMS\Core\Resource\Folder */
                $subFolders = $folderObject->getSubfolders();
-               sort($subFolders);
+               $subFolders = \TYPO3\CMS\Core\Resource\Utility\ListUtility::resolveSpecialFolderNames($subFolders);
+               uksort($subFolders, 'strnatcasecmp');
+
                $totalSubFolders = count($subFolders);
                $HTML = '';
                $subFolderCounter = 0;
-               foreach ($subFolders as $subFolder) {
+               foreach ($subFolders as $subFolderName => $subFolder) {
                        $subFolderCounter++;
                        // Reserve space.
                        $this->tree[] = array();
@@ -346,7 +350,7 @@ class FolderTreeView extends \TYPO3\CMS\Backend\Tree\View\AbstractTreeView {
                        $row = array(
                                'uid' => $specUID,
                                'path' => $subFolder->getCombinedIdentifier(),
-                               'title' => $subFolder->getName(),
+                               'title' => $subFolderName,
                                'folder' => $subFolder
                        );
                        // Make a recursive call to the next level
@@ -374,17 +378,16 @@ class FolderTreeView extends \TYPO3\CMS\Backend\Tree\View\AbstractTreeView {
                                } else {
                                        $icon = 'apps-filetree-folder-default';
                                }
-                               if ($subFolder->getName() == '_temp_') {
-                                       $icon = 'apps-filetree-folder-temp';
-                                       $row['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:temp', TRUE);
-                                       $row['_title'] = '<strong>' . $row['title'] . '</strong>';
+                               $role = $subFolder->getRole();
+                               if ($role !== \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_DEFAULT) {
+                                       $row['_title'] = '<strong>' . $subFolderName . '</strong>';
                                }
-                               if ($subFolder->getName() == '_recycler_') {
+                               if ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_TEMPORARY) {
+                                       $icon = 'apps-filetree-folder-temp';
+                               } elseif ($role === \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_RECYCLER) {
                                        $icon = 'apps-filetree-folder-recycler';
-                                       $row['title'] = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xml:recycler', TRUE);
-                                       $row['_title'] = '<strong>' . $row['title'] . '</strong>';
                                }
-                               $icon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon($icon, array('title' => $subFolder->getIdentifier()), $overlays);
+                               $icon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon($icon, array('title' => $subFolderName), $overlays);
                                $HTML .= $this->wrapIcon($icon, $subFolder);
                        }
                        // Finally, add the row/HTML content to the ->tree array in the reserved key.
@@ -666,4 +669,4 @@ class FolderTreeView extends \TYPO3\CMS\Backend\Tree\View\AbstractTreeView {
 }
 
 
-?>
+?>
\ No newline at end of file
index 1741e54..f0a9931 100644 (file)
@@ -5,6 +5,7 @@ namespace TYPO3\CMS\Core\Resource\Driver;
  * Copyright notice
  *
  * (c) 2011-2013 Andreas Wolf <andreas.wolf@ikt-werk.de>
+ * (c) 2013 Stefan Neufeind <info (at) speedpartner.de>
  * All rights reserved
  *
  * This script is part of the TYPO3 project. The TYPO3 project is
@@ -27,6 +28,7 @@ namespace TYPO3\CMS\Core\Resource\Driver;
  * This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use TYPO3\CMS\Core\Resource\FolderInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 
@@ -64,6 +66,13 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
         */
        protected $charsetConversion;
 
+       /** @var array */
+       protected $mappingFolderNameToRole = array(
+               '_recycler_' => FolderInterface::ROLE_RECYCLER,
+               '_temp_' => FolderInterface::ROLE_TEMPORARY,
+               'user_upload' => FolderInterface::ROLE_USERUPLOAD,
+       );
+
        /**
         * Checks if a configuration is valid for this storage.
         *
@@ -1160,7 +1169,21 @@ class LocalDriver extends \TYPO3\CMS\Core\Resource\Driver\AbstractDriver {
                return $this->charsetConversion;
        }
 
-}
 
+       /**
+        * Returns the role of an item (currently only folders; can later be extended for files as well)
+        *
+        * @param \TYPO3\CMS\Core\Resource\ResourceInterface $item
+        * @return string
+        */
+       public function getRole(\TYPO3\CMS\Core\Resource\ResourceInterface $item) {
+               $role = $this->mappingFolderNameToRole[$item->getName()];
+               if (empty($role)) {
+                       $role = FolderInterface::ROLE_DEFAULT;
+               }
+               return $role;
+       }
+
+}
 
-?>
+?>
\ No newline at end of file
index 83283f9..8f6532d 100644 (file)
@@ -232,8 +232,6 @@ class Folder implements FolderInterface {
                if (!$this->storage->hasFolderInFolder($name, $this)) {
                        throw new \InvalidArgumentException('Folder "' . $name . '" does not exist in "' . $this->identifier . '"', 1329836110);
                }
-               // TODO this will not work with non-hierarchical storages -> the identifier for subfolders is not composed of
-               // the current item's identifier for these
                /** @var $factory ResourceFactory */
                $factory = ResourceFactory::getInstance();
                $folderObject = $factory->createFolderObject($this->storage, $this->identifier . $name . '/', $name);
@@ -467,7 +465,14 @@ class Folder implements FolderInterface {
                $this->fileAndFolderNameFilters = $filters;
        }
 
+       /**
+        * Returns the role of this folder (if any). See FolderInterface::ROLE_* constants for possible values.
+        *
+        * @return integer
+        */
+       public function getRole() {
+               return $this->storage->getRole($this);
+       }
 }
 
-
-?>
+?>
\ No newline at end of file
index 06c2238..51d2210 100644 (file)
@@ -34,6 +34,15 @@ namespace TYPO3\CMS\Core\Resource;
 interface FolderInterface extends ResourceInterface
 {
        /**
+        * Roles for folders
+        */
+       const ROLE_DEFAULT = 'default';
+       const ROLE_RECYCLER = 'recycler';
+       const ROLE_PROCESSING = 'processing';
+       const ROLE_TEMPORARY = 'temporary';
+       const ROLE_USERUPLOAD = 'userupload';
+
+       /**
         * Returns a list of all subfolders
         *
         * @return Folder[]
index 39a2ed1..3151a89 100644 (file)
@@ -1988,6 +1988,26 @@ class ResourceStorage {
        }
 
        /**
+        * Gets the role of a folder
+        *
+        * @param FolderInterface $folder Folder object to get the role from
+        * @return string The role the folder has
+        */
+       public function getRole(FolderInterface $folder) {
+               $folderRole = FolderInterface::ROLE_DEFAULT;
+
+               if (method_exists($this->driver, 'getRole')) {
+                       $folderRole = $this->driver->getRole($folder);
+               }
+
+               if ($folder->getIdentifier() === $this->getProcessingFolder()->getIdentifier()) {
+                       $folderRole = FolderInterface::ROLE_PROCESSING;
+               }
+
+               return $folderRole;
+       }
+
+       /**
         * Getter function to return the folder where the files can
         * be processed. does not check for access rights here
         *
@@ -2019,4 +2039,4 @@ class ResourceStorage {
        }
 }
 
-?>
+?>
\ No newline at end of file
diff --git a/typo3/sysext/core/Classes/Resource/Utility/ListUtility.php b/typo3/sysext/core/Classes/Resource/Utility/ListUtility.php
new file mode 100644 (file)
index 0000000..e108779
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+namespace TYPO3\CMS\Core\Resource\Utility;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Stefan Neufeind <info (at) speedpartner.de>
+ *  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!
+ ***************************************************************/
+/**
+ * Utility function for working with resource-lists
+ */
+class ListUtility {
+
+       /**
+        * Resolve special folders (by their role) into localised string
+        *
+        * @param array $folders Array of \TYPO3\CMS\Core\Resource\Folder
+        * @return array Array of \TYPO3\CMS\Core\Resource\Folder; folder name or role with folder name as keys
+        */
+       static public function resolveSpecialFolderNames(array $folders) {
+               $resolvedFolders = array();
+
+               /** @var $folder \TYPO3\CMS\Core\Resource\Folder */
+               foreach ($folders as $folder) {
+                       $name = $folder->getName();
+                       $role = $folder->getRole();
+                       if ($role !== \TYPO3\CMS\Core\Resource\FolderInterface::ROLE_DEFAULT) {
+                               $tempName = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_file_list.xlf:role_folder_' . $role, TRUE);
+                               if (!empty($tempName) && ($tempName !== $name)) {
+                                       // Set new name and append original name
+                                       $name = $tempName . ' (' . $name . ')';
+                               }
+                       }
+                       $resolvedFolders[$name] = $folder;
+               }
+
+               return $resolvedFolders;
+       }
+
+}
+
+?>
\ No newline at end of file
index e0abfed..02efa45 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 namespace TYPO3\CMS\Core\Tests\Unit\Resource;
 
+use TYPO3\CMS\Core\Resource\ResourceStorage;
+
 /***************************************************************
  * Copyright notice
  *
@@ -23,7 +25,6 @@ namespace TYPO3\CMS\Core\Tests\Unit\Resource;
  *
  * This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
-
 require_once 'vfsStream/vfsStream.php';
 
 /**
@@ -647,6 +648,46 @@ class ResourceStorageTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCa
                $this->fixture->getFileList('/', 0, 0, TRUE, TRUE, TRUE);
        }
 
+       /**
+        * @test
+        */
+       public function getRoleReturnsDefaultForRegularFolders() {
+               $folderIdentifier = uniqid();
+               $this->addToMount(array(
+                       $folderIdentifier => array()
+               ));
+               $this->prepareFixture(array());
+
+               $role = $this->fixture->getRole($this->getSimpleFolderMock('/' . $folderIdentifier . '/'));
+
+               $this->assertSame(\TYPO3\CMS\Core\Resource\FolderInterface::ROLE_DEFAULT, $role);
+       }
+
+       /**
+        * @test
+        */
+       public function getRoleReturnsCorrectValueForDefaultProcessingFolder() {
+               $this->prepareFixture(array());
+
+               $role = $this->fixture->getRole($this->getSimpleFolderMock('/' . ResourceStorage::DEFAULT_ProcessingFolder . '/'));
+
+               $this->assertSame(\TYPO3\CMS\Core\Resource\FolderInterface::ROLE_PROCESSING, $role);
+       }
+
+       /**
+        * @test
+        */
+       public function getRoleReturnsCorrectValueForConfiguredProcessingFolder() {
+               $folderIdentifier = uniqid();
+               $this->addToMount(array(
+                       $folderIdentifier => array()
+               ));
+               $this->prepareFixture(array(), FALSE, NULL, array('processingfolder' => '/' . $folderIdentifier . '/'));
+
+               $role = $this->fixture->getRole($this->getSimpleFolderMock('/' . $folderIdentifier . '/'));
+
+               $this->assertSame(\TYPO3\CMS\Core\Resource\FolderInterface::ROLE_PROCESSING, $role);
+       }
 }
 
 ?>
index 280dd3a..63bbcfd 100644 (file)
@@ -27,6 +27,8 @@ namespace TYPO3\CMS\Filelist;
  *  This copyright notice MUST APPEAR in all copies of the script!
  ***************************************************************/
 
+use TYPO3\CMS\Core\Resource\FolderInterface;
+
 /**
  * Class for rendering of File>Filelist
  *
@@ -216,7 +218,7 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
                );
                // Makes the code for the foldericon in the top
                if ($folderObject) {
-                       list($title, $icon, $path) = $this->dirData($folderObject);
+                       list($_, $icon, $path) = $this->dirData($folderObject);
                        $title = htmlspecialchars($folderObject->getIdentifier());
                        // Start compiling the HTML
                        // @todo: how to fix this? $title = $GLOBALS['SOBE']->basicFF->blindPath($title);
@@ -329,6 +331,10 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
                        foreach ($folders as $folder) {
                                $folderObjects[] = $storage->getFolder($folder['identifier']);
                        }
+
+                       $folderObjects = \TYPO3\CMS\Core\Resource\Utility\ListUtility::resolveSpecialFolderNames($folderObjects);
+                       uksort($folderObjects, 'strnatcasecmp');
+
                        // Directories are added
                        $iOut = $this->formatDirList($folderObjects);
                        if ($iOut) {
@@ -408,15 +414,26 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
         */
        public function formatDirList(array $folders) {
                $out = '';
-               foreach ($folders as $folderObject) {
+               foreach ($folders as $folderName => $folderObject) {
+                       $role = $folderObject->getRole();
+                       if ($role === FolderInterface::ROLE_PROCESSING) {
+                               // don't show processing-folder
+                               continue;
+                       }
+                       if ($role !== FolderInterface::ROLE_DEFAULT) {
+                               $displayName = '<strong>' . htmlspecialchars($folderName) . '</strong>';
+                       } else {
+                               $displayName = htmlspecialchars($folderName);
+                       }
+
                        list($flag, $code) = $this->fwd_rwd_nav();
                        $out .= $code;
                        if ($flag) {
                                // Initialization
                                $this->counter++;
-                               list($title, $icon, $path) = $this->dirData($folderObject);
+                               list($_, $icon, $path) = $this->dirData($folderObject);
                                // The icon with link
-                               $theIcon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIconForFile('folder', array('title' => strip_tags($title)));
+                               $theIcon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon($icon, array('title' => $folderName));
                                if ($this->clickMenus) {
                                        $theIcon = $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($theIcon, $folderObject->getCombinedIdentifier());
                                }
@@ -439,7 +456,7 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
                                                        $theData[$field] = '-';
                                                        break;
                                                case 'file':
-                                                       $theData[$field] = $this->linkWrapDir($title, $folderObject);
+                                                       $theData[$field] = $this->linkWrapDir($displayName, $folderObject);
                                                        break;
                                                case '_CLIPBOARD_':
                                                        $temp = '';
@@ -526,11 +543,11 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
        public function dirData(\TYPO3\CMS\Core\Resource\Folder $folderObject) {
                $title = htmlspecialchars($folderObject->getName());
                $icon = 'apps-filetree-folder-default';
-               if ($title == '_temp_') {
-                       $icon = 'apps-filetree-folder-temp';
+               $role = $folderObject->getRole();
+               if ($role === FolderInterface::ROLE_TEMPORARY) {
                        $title = '<strong>' . $GLOBALS['LANG']->getLL('temp', TRUE) . '</strong>';
-               }
-               if ($title == '_recycler_') {
+                       $icon = 'apps-filetree-folder-temp';
+               } elseif ($role === FolderInterface::ROLE_RECYCLER) {
                        $icon = 'apps-filetree-folder-recycler';
                        $title = '<strong>' . $GLOBALS['LANG']->getLL('recycler', TRUE) . '</strong>';
                }
@@ -788,4 +805,4 @@ class FileList extends \TYPO3\CMS\Backend\RecordList\AbstractRecordList {
 
 }
 
-?>
+?>
\ No newline at end of file
index 6e24708..17503dc 100644 (file)
                        <trans-unit id="temp" xml:space="preserve">
                                <source>Temporary files</source>
                        </trans-unit>
+                       <trans-unit id="role_folder_temporary" xml:space="preserve">
+                               <source>Temporary files</source>
+                       </trans-unit>
+                       <trans-unit id="role_folder_recycler" xml:space="preserve">
+                               <source>Recycler</source>
+                       </trans-unit>
                        <trans-unit id="read" xml:space="preserve">
                                <source>R</source>
                        </trans-unit>
                        </trans-unit>
                </body>
        </file>
-</xliff>
+</xliff>
\ No newline at end of file