[TASK] Add FileCollectionRegistry 57/27257/9
authorFrans Saris <franssaris@gmail.com>
Sun, 2 Feb 2014 10:04:44 +0000 (11:04 +0100)
committerWouter Wolters <typo3@wouterwolters.nl>
Mon, 17 Feb 2014 20:04:52 +0000 (21:04 +0100)
The classes belonging to the FileCollection types are hardwired
in ResourceFactory::createCollectionObject(), therefore you can
not use your own types.

This change introduces a Registry API that makes it possible to
register your own FileCollection type + class and has a generic
way to add the new type to TCA[sys_file_collection].

How to use:
- Register type in ext_localconf.php
  $register->registerFileCollectionClass(full_class_name, your_type);
- Add type to TCA in Configuration/TCA/sys_file_collection.php
  $register->addTypeToTCA(your_type, label, needed_fields);
  return $GLOBALS['TCA']['sys_file_collection'];

Resolves: #53910
Documentation: #56032
Releases: 6.2
Change-Id: Id6cb1c7a59f741b28fee7bdfef32890f34a072a5
Reviewed-on: https://review.typo3.org/27257
Reviewed-by: Markus Klein
Tested-by: Markus Klein
Reviewed-by: Wouter Wolters
Tested-by: Wouter Wolters
typo3/sysext/core/Classes/Resource/Collection/FileCollectionRegistry.php [new file with mode: 0644]
typo3/sysext/core/Classes/Resource/ResourceFactory.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Tests/Unit/Resource/Collection/FileCollectionRegistryTest.php [new file with mode: 0644]

diff --git a/typo3/sysext/core/Classes/Resource/Collection/FileCollectionRegistry.php b/typo3/sysext/core/Classes/Resource/Collection/FileCollectionRegistry.php
new file mode 100644 (file)
index 0000000..5a39b89
--- /dev/null
@@ -0,0 +1,146 @@
+<?php
+namespace TYPO3\CMS\Core\Resource\Collection;
+
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2013 - Frans Saris <franssaris@gmail.com>
+ * 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 text file 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!
+ ***************************************************************/
+
+/**
+ * Registry for FileCollection classes
+ */
+class FileCollectionRegistry implements \TYPO3\CMS\Core\SingletonInterface {
+
+       /**
+        * Registered FileCollection types
+        *
+        * @var array
+        */
+       protected $types = array();
+
+       /**
+        * Constructor
+        */
+       public function __construct() {
+               foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['registeredCollections'] as $type => $class) {
+                       $this->registerFileCollectionClass($class, $type);
+               }
+       }
+
+       /**
+        * Register a (new) FileCollection type
+        *
+        * @param string $className
+        * @param string $type FileCollection type max length 30 chars (db field restriction)
+        * @param bool $override existing FileCollection type
+        * @return bool TRUE if registration succeeded
+        * @throws \InvalidArgumentException
+        */
+       public function registerFileCollectionClass($className, $type, $override = FALSE) {
+
+               if (strlen($type) > 30) {
+                       throw new \InvalidArgumentException('FileCollection type can have a max string length of 30 bytes', 1391295611);
+               }
+
+               if (!class_exists($className)) {
+                       throw new \InvalidArgumentException('Class ' . $className . ' does not exist.', 1391295613);
+               }
+
+               if (!in_array('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection', class_parents($className), TRUE)) {
+                       throw new \InvalidArgumentException('FileCollection ' . $className . ' needs to extend the AbstractFileCollection.', 1391295633);
+               }
+
+               if (isset($this->types[$type])) {
+                       // Return immediately without changing configuration
+                       if ($this->types[$type] === $className) {
+                               return TRUE;
+                       } elseif (!$override) {
+                               throw new \InvalidArgumentException('FileCollections ' . $type . ' is already registered.', 1391295643);
+                       }
+               }
+
+               $this->types[$type] = $className;
+               return TRUE;
+       }
+
+       /**
+        * Add the type to the TCA of sys_file_collection
+        *
+        * @param string $type
+        * @param string $label
+        * @param string $availableFields comma separated list of fields to show
+        * @param array $additionalColumns Additional columns configuration
+        * @return array adjusted TCA for sys_file_collection
+        */
+       public function addTypeToTCA($type, $label, $availableFields, array $additionalColumns = array()) {
+
+               $GLOBALS['TCA']['sys_file_collection']['types'][$type] = array(
+                       'showitem' => 'sys_language_uid;;;;1-1-1, l10n_parent, l10n_diffsource, title;;1, type, ' . $availableFields
+               );
+
+               // search for existing type when found override label
+               $typeFound = FALSE;
+               foreach ($GLOBALS['TCA']['sys_file_collection']['columns']['type']['config']['items'] as $key => $item) {
+                       if ($item[1] === $type) {
+                               $typeFound = TRUE;
+                               $GLOBALS['TCA']['sys_file_collection']['columns']['type']['config']['items'][$key][0] = $label;
+                       }
+               }
+               if (!$typeFound) {
+                       $GLOBALS['TCA']['sys_file_collection']['columns']['type']['config']['items'][] = array(
+                               0 => $label,
+                               1 => $type
+                       );
+               }
+               if ($additionalColumns !== array()) {
+                       \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($GLOBALS['TCA']['sys_file_collection']['columns'], $additionalColumns);
+               }
+               return $GLOBALS['TCA']['sys_file_collection'];
+       }
+
+       /**
+        * Returns a class name for a given type
+        *
+        * @param string $type
+        * @return string The class name
+        * @throws \InvalidArgumentException
+        */
+       public function getFileCollectionClass($type) {
+               if (!isset($this->types[$type])) {
+                       throw new \InvalidArgumentException('Desired FileCollection type "' . $type . '" is not in the list of available FileCollections.', 1391295644);
+               }
+               return $this->types[$type];
+       }
+
+       /**
+        * Checks if the given FileCollection type exists
+        *
+        * @param string $type Type of the FileCollection
+        * @return boolean TRUE if the FileCollection exists, FALSE otherwise
+        */
+       public function fileCollectionTypeExists($type) {
+               return isset($this->types[$type]);
+       }
+
+}
\ No newline at end of file
index c75478f..0d5a1f6 100644 (file)
@@ -296,20 +296,11 @@ class ResourceFactory implements \TYPO3\CMS\Core\SingletonInterface {
         * @return Collection\AbstractFileCollection
         */
        public function createCollectionObject(array $collectionData) {
-               switch ($collectionData['type']) {
-                       case 'static':
-                               $collection = Collection\StaticFileCollection::create($collectionData);
-                               break;
-                       case 'folder':
-                               $collection = Collection\FolderBasedFileCollection::create($collectionData);
-                               break;
-                       case 'category':
-                               $collection = Collection\CategoryBasedFileCollection::create($collectionData);
-                               break;
-                       default:
-                               $collection = NULL;
-               }
-               return $collection;
+               /** @var $registry Collection\FileCollectionRegistry */
+               $registry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Collection\\FileCollectionRegistry');
+               $class = $registry->getFileCollectionClass($collectionData['type']);
+
+               return $class::create($collectionData);
        }
 
        /**
index a9b829d..49bd89b 100644 (file)
@@ -247,6 +247,11 @@ return array(
                        'processingTaskTypes' => array(
                                'Image.Preview' => 'TYPO3\\CMS\\Core\\Resource\\Processing\\ImagePreviewTask',
                                'Image.CropScaleMask' => 'TYPO3\\CMS\\Core\\Resource\\Processing\\ImageCropScaleMaskTask'
+                       ),
+                       'registeredCollections' => array(
+                               'static' => 'TYPO3\\CMS\\Core\\Resource\\Collection\\StaticFileCollection',
+                               'folder' => 'TYPO3\\CMS\\Core\\Resource\\Collection\\FolderBasedFileCollection',
+                               'category' => 'TYPO3\\CMS\\Core\\Resource\\Collection\\CategoryBasedFileCollection',
                        )
                ),
                'isInitialInstallationInProgress' => FALSE,             // Boolean: If TRUE, the installation is 'in progress'. This value is handled within the install tool step installer internally.
diff --git a/typo3/sysext/core/Tests/Unit/Resource/Collection/FileCollectionRegistryTest.php b/typo3/sysext/core/Tests/Unit/Resource/Collection/FileCollectionRegistryTest.php
new file mode 100644 (file)
index 0000000..7ccee56
--- /dev/null
@@ -0,0 +1,188 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Resource\Collection;
+
+/***************************************************************
+ * Copyright notice
+ *
+ * (c) 2013 - Frans Saris <franssaris@gmail.com>
+ * 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 text file 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!
+ ***************************************************************/
+
+/**
+ * Test cases for FileCollectionRegistry
+ */
+class FileCollectionRegistryTest extends \TYPO3\CMS\Core\Tests\Unit\Resource\BaseTestCase {
+
+       /**
+        * @var \TYPO3\CMS\Core\Resource\Collection\FileCollectionRegistry
+        */
+       protected $testSubject;
+
+       public function setUp() {
+               $this->initializeTestSubject();
+       }
+
+       protected function initializeTestSubject() {
+               $this->testSubject = new \TYPO3\CMS\Core\Resource\Collection\FileCollectionRegistry();
+       }
+
+       /**
+        * @test
+        */
+       public function registeredFileCollectionClassesCanBeRetrieved() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $this->testSubject->registerFileCollectionClass($className, 'foobar');
+               $returnedClassName = $this->testSubject->getFileCollectionClass('foobar');
+               $this->assertEquals($className, $returnedClassName);
+       }
+
+       /**
+        * @test
+        * @expectedException InvalidArgumentException
+        * @expectedExceptionCode 1391295613
+        */
+       public function registerFileCollectionClassThrowsExceptionIfClassDoesNotExist() {
+               $this->testSubject->registerFileCollectionClass(uniqid(), uniqid());
+       }
+
+       /**
+        * @test
+        * @expectedException InvalidArgumentException
+        * @expectedExceptionCode 1391295611
+        */
+       public function registerFileCollectionClassThrowsExceptionIfTypeIsTooLong() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $type = str_pad('', 40);
+               $this->testSubject->registerFileCollectionClass($className, $type);
+       }
+
+       /**
+        * @test
+        * @expectedException InvalidArgumentException
+        * @expectedExceptionCode 1391295643
+        */
+       public function registerFileCollectionClassThrowsExceptionIfTypeIsAlreadyRegistered() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $className2 = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\StaticFileCollection'));
+               $this->testSubject->registerFileCollectionClass($className, 'foobar');
+               $this->testSubject->registerFileCollectionClass($className2, 'foobar');
+       }
+
+       /**
+        * @test
+        */
+       public function registerFileCollectionClassOverridesExistingRegisteredFileCollectionClass() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $className2 = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\StaticFileCollection'));
+               $this->testSubject->registerFileCollectionClass($className, 'foobar');
+               $this->testSubject->registerFileCollectionClass($className2, 'foobar', TRUE);
+       }
+
+       /**
+        * @test
+        * @expectedException InvalidArgumentException
+        * @expectedExceptionCode 1391295644
+        */
+       public function getFileCollectionClassThrowsExceptionIfClassIsNotRegistered() {
+               $this->testSubject->getFileCollectionClass(uniqid());
+       }
+
+       /**
+        * @test
+        */
+       public function getFileCollectionClassAcceptsClassNameIfClassIsRegistered() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $this->testSubject->registerFileCollectionClass($className, 'foobar');
+               $this->assertEquals($className, $this->testSubject->getFileCollectionClass('foobar'));
+       }
+
+       /**
+        * @test
+        */
+       public function fileCollectionRegistryIsInitializedWithPreconfiguredFileCollections() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $type = uniqid();
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['registeredCollections'] = array(
+                       $type => $className
+               );
+               $this->initializeTestSubject();
+               $this->assertEquals($className, $this->testSubject->getFileCollectionClass($type));
+       }
+
+       /**
+        * @test
+        */
+       public function fileCollectionExistsReturnsTrueForAllExistingFileCollections() {
+               $className = get_class($this->getMockForAbstractClass('TYPO3\\CMS\\Core\\Resource\\Collection\\AbstractFileCollection'));
+               $type = 'foo';
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['registeredCollections'] = array(
+                       $type => $className
+               );
+               $this->initializeTestSubject();
+               $this->assertTrue($this->testSubject->fileCollectionTypeExists($type));
+               $this->assertFalse($this->testSubject->fileCollectionTypeExists('bar'));
+       }
+
+       /**
+        * @test
+        */
+       public function fileCollectionExistsReturnsFalseIfFileCollectionDoesNotExist() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['registeredFileCollections'] = array();
+               $this->initializeTestSubject();
+               $this->assertFalse($this->testSubject->fileCollectionTypeExists(uniqid()));
+       }
+
+       /**
+        * @test
+        */
+       public function addNewTypeToTCA() {
+
+               // Create a TCA fixture for sys_file_collection
+               $GLOBALS['TCA']['sys_file_collection'] = array(
+                       'types' => array(
+                               'typeB' => array('showitem' => 'fieldA, fieldB, fieldC;labelC;paletteC;specialC, fieldD'),
+                       ),
+                       'columns' => array(
+                               'type' => array(
+                                       'config' => array(
+                                               'items' => array('Type A', 'typeA'),
+                                               'items' => array('Type B', 'typeB')
+                                       )
+                               )
+                       )
+               );
+
+               $type = 'my_type';
+               $label = 'The Label';
+
+               $this->testSubject->addTypeToTCA($type, $label, 'something');
+
+               // check type
+               $this->assertEquals('sys_language_uid;;;;1-1-1, l10n_parent, l10n_diffsource, title;;1, type, something', $GLOBALS['TCA']['sys_file_collection']['types']['my_type']['showitem']);
+
+               $indexOfNewType = count($GLOBALS['TCA']['sys_file_collection']['columns']['type']['config']['items']) - 1;
+
+               // check if columns.type.item exist
+               $this->assertEquals($type, $GLOBALS['TCA']['sys_file_collection']['columns']['type']['config']['items'][$indexOfNewType][1]);
+               $this->assertEquals($label, $GLOBALS['TCA']['sys_file_collection']['columns']['type']['config']['items'][$indexOfNewType][0]);
+       }
+}
\ No newline at end of file