[TASK] Improve method makeCategorizable to be used everywhere 67/20767/2
authorFabien Udriot <fabien.udriot@ecodev.ch>
Sun, 15 Jul 2012 23:25:22 +0000 (01:25 +0200)
committerFrancois Suter <francois@typo3.org>
Tue, 14 May 2013 09:06:15 +0000 (11:06 +0200)
Method makeCategorizable registers a table to be categorizable in the
BE. The current implementation has the drawback to force the call of this
method after the TCA of the table. If called before, the "categorization"
wouldn't be applied because of timing issue. The patch improve the
situation by postponing the application of the TCA responsible for
categorization.

For more details about the method refer to
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable.

In addition to 6.2, the Install Tool setting
[SYS][defaultCategorizedTables] is set to an empty string to avoid
requirering DB updates for minor releases.

Change-Id: I966cc65e50e0d6a81cfafb1238f253ed802349c6
Resolves: #38972
Releases: 6.2, 6.1
Reviewed-on: https://review.typo3.org/20767
Reviewed-by: Philipp Gampe
Tested-by: Philipp Gampe
Reviewed-by: Francois Suter
Tested-by: Francois Suter
typo3/sysext/core/Classes/Category/CategoryRegistry.php
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
typo3/sysext/core/Configuration/DefaultConfiguration.php
typo3/sysext/core/Tests/Unit/Category/CategoryRegistryTest.php
typo3/sysext/core/Tests/Unit/Utility/ExtensionMangementUtilityTest.php

index 09ac41c..d710e2f 100644 (file)
@@ -66,15 +66,22 @@ class CategoryRegistry implements \TYPO3\CMS\Core\SingletonInterface {
         * @param string $extensionKey Extension key to be used
         * @param string $tableName Name of the table to be registered
         * @param string $fieldName Name of the field to be registered
-        * @return boolean Whether fieldName of tableName is registered
+        * @param array $options Additional configuration options
+        *              + fieldList: field configuration to be added to showitems
+        *              + typesList: list of types that shall visualize the categories field
+        *              + position: insert position of the categories field
+        *              + fieldConfiguration: TCA field config array to override defaults
+        * @return bool
         */
-       public function add($extensionKey, $tableName, $fieldName) {
+       public function add($extensionKey, $tableName, $fieldName = 'categories', $options = array()) {
                $result = FALSE;
-               // Makes sure there is an existing table configuration and nothing registered yet:
-               if (!empty($GLOBALS['TCA'][$tableName])) {
-                       if (!$this->isRegistered($tableName, $fieldName)) {
-                               $this->registry[$extensionKey][$tableName] = $fieldName;
-                       }
+
+                       // Makes sure there is an existing table configuration and nothing registered yet:
+               if (!$this->isRegistered($tableName, $fieldName)) {
+                       $this->registry[$extensionKey][$tableName] = array (
+                               'fieldName' => $fieldName,
+                               'options' => $options,
+                       );
                        $result = TRUE;
                }
                return $result;
@@ -99,16 +106,31 @@ class CategoryRegistry implements \TYPO3\CMS\Core\SingletonInterface {
        }
 
        /**
+        * Gets all categorized tables
+        *
+        * @return array
+        */
+       public function getCategorizedTables() {
+               $categorizedTables = array();
+
+               foreach ($this->registry as $registry) {
+                       $categorizedTables = array_merge($categorizedTables, array_keys($registry));
+               }
+
+               return $categorizedTables;
+       }
+
+       /**
         * Tells whether a table has a category configuration in the registry.
         *
         * @param string $tableName Name of the table to be looked up
         * @param string $fieldName Name of the field to be looked up
         * @return boolean
         */
-       public function isRegistered($tableName, $fieldName) {
+       public function isRegistered($tableName, $fieldName = 'categories') {
                $isRegistered = FALSE;
                foreach ($this->registry as $configuration) {
-                       if (!empty($configuration[$tableName]) && $configuration[$tableName] === $fieldName) {
+                       if (!empty($configuration[$tableName]['fieldName']) && $configuration[$tableName]['fieldName'] === $fieldName) {
                                $isRegistered = TRUE;
                                break;
                        }
@@ -140,13 +162,159 @@ class CategoryRegistry implements \TYPO3\CMS\Core\SingletonInterface {
                        return '';
                }
                $sql = '';
-               foreach ($this->registry[$extensionKey] as $tableName => $fieldName) {
-                       $sql .= sprintf($this->template, $tableName, $fieldName);
+
+               foreach ($this->registry[$extensionKey] as $tableName => $tableInfo) {
+                       $sql .= sprintf($this->template, $tableName, $tableInfo['fieldName']);
                }
                return $sql;
        }
 
-}
+       /**
+        * Apply TCA to all registered tables
+        *
+        * @return void
+        */
+       public function applyTca() {
+
+               $this->registerDefaultCategorizedTables();
+
+               foreach ($this->registry as $registry) {
+                       foreach ($registry as $tableName => $tableInfo) {
+                               $this->addTcaColumn($tableName, $tableInfo['fieldName'], $tableInfo['options']);
+                               $this->addToAllTCAtypes($tableName, $tableInfo['fieldName'], $tableInfo['options']);
+                       }
+               }
+       }
+
+       /**
+        * Add default categorized tables to the registry
+        *
+        * @return void
+        */
+       protected function registerDefaultCategorizedTables() {
+
+               $defaultCategorizedTables = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultCategorizedTables']);
+               foreach ($defaultCategorizedTables as $defaultCategorizedTable) {
+                       if (!$this->isRegistered($defaultCategorizedTable)) {
+                               $this->add('core', $defaultCategorizedTable, 'categories');
+                       }
+               }
+       }
+
+       /**
+        * Add a new field into the TCA types -> showitem
+        *
+        * @param string $tableName Name of the table to be categorized
+        * @param string $fieldName Name of the field to be used to store categories
+        * @param array $options Additional configuration options
+        *              + fieldList: field configuration to be added to showitems
+        *              + typesList: list of types that shall visualize the categories field
+        *              + position: insert position of the categories field
+        * @return void
+        */
+       protected function addToAllTCAtypes($tableName, $fieldName, $options) {
+
+               // Makes sure to add more TCA to an existing structure
+               if (isset($GLOBALS['TCA'][$tableName]['columns'])) {
+
+                       $fieldList = '--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category, ' . $fieldName;
+                       if (!empty($options['fieldList'])) {
+                               $fieldList = $options['fieldList'];
+                       }
+
+                       $typesList = '';
+                       if (!empty($options['typesList'])) {
+                               $typesList = $options['typesList'];
+                       }
+
+                       $position = '';
+                       if (!empty($options['position'])) {
+                               $position = $options['position'];
+                       }
+
+                       // Makes the new "categories" field to be visible in TSFE.
+                       \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes($tableName, $fieldList, $typesList, $position);
+
+               }
+       }
+
+       /**
+        * Add a new TCA Column
+        *
+        * @param string $tableName Name of the table to be categorized
+        * @param string $fieldName Name of the field to be used to store categories
+        * @param array $options Additional configuration options
+        *              + fieldConfiguration: TCA field config array to override defaults
+        * @return void
+        */
+       protected function addTcaColumn($tableName, $fieldName, $options) {
+
+               // Makes sure to add more TCA to an existing structure
+               if (isset($GLOBALS['TCA'][$tableName]['columns'])) {
 
+                       // Forges a new field, default name is "categories"
+                       $fieldConfiguration = array(
+                               'type' => 'select',
+                               'foreign_table' => 'sys_category',
+                               'foreign_table_where' => ' ORDER BY sys_category.title ASC',
+                               'MM' => 'sys_category_record_mm',
+                               'MM_opposite_field' => 'items',
+                               'MM_match_fields' => array('tablenames' => $tableName),
+                               'size' => 10,
+                               'autoSizeMax' => 50,
+                               'maxitems' => 9999,
+                               'renderMode' => 'tree',
+                               'treeConfig' => array(
+                                       'parentField' => 'parent',
+                                       'appearance' => array(
+                                               'expandAll' => TRUE,
+                                               'showHeader' => TRUE,
+                                       ),
+                               ),
+                               'wizards' => array(
+                                       '_PADDING' => 1,
+                                       '_VERTICAL' => 1,
+                                       'edit' => array(
+                                               'type' => 'popup',
+                                               'title' => 'Edit',
+                                               'script' => 'wizard_edit.php',
+                                               'icon' => 'edit2.gif',
+                                               'popup_onlyOpenIfSelected' => 1,
+                                               'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1',
+                                       ),
+                                       'add' => Array(
+                                               'type' => 'script',
+                                               'title' => 'Create new',
+                                               'icon' => 'add.gif',
+                                               'params' => array(
+                                                       'table' => 'sys_category',
+                                                       'pid' => '###CURRENT_PID###',
+                                                       'setValue' => 'prepend'
+                                               ),
+                                               'script' => 'wizard_add.php',
+                                       ),
+                               ),
+                       );
+
+                       if (!empty($options['fieldConfiguration'])) {
+                               $fieldConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule(
+                                       $fieldConfiguration,
+                                       $options['fieldConfiguration']
+                               );
+                       }
+
+                       $columns = array(
+                               $fieldName => array(
+                                       'exclude' => 0,
+                                       'label' => 'LLL:EXT:lang/locallang_tca.xlf:sys_category.categories',
+                                       'config' => $fieldConfiguration,
+                               ),
+                       );
+
+                       // Adding fields to an existing table definition
+                       \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns($tableName, $columns);
+               }
+       }
+}
 
 ?>
\ No newline at end of file
index 7bf89e7..7d59ce5 100644 (file)
@@ -894,6 +894,9 @@ class Bootstrap {
                if (file_exists($extTablesFile) && is_file($extTablesFile)) {
                        include $extTablesFile;
                }
+
+               // Apply TCA onto tables to be categorized
+               \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->applyTca();
        }
 
        /**
@@ -1050,4 +1053,4 @@ class Bootstrap {
 }
 
 
-?>
\ No newline at end of file
+?>
index 92a4823..9e104cb 100644 (file)
@@ -2106,10 +2106,10 @@ tt_content.' . $key . $prefix . ' {
        }
 
        /**
-        * Makes a table categorizable by extending its TCA.
+        * Makes a table categorizable by adding value into the category registry.
         *
         * @param string $extensionKey Extension key to be used
-        * @param string $tableName Name of the table to be categoriezed
+        * @param string $tableName Name of the table to be categorized
         * @param string $fieldName Name of the field to be used to store categories
         * @param array $options Additional configuration options
         * @see addTCAcolumns
@@ -2117,82 +2117,14 @@ tt_content.' . $key . $prefix . ' {
         */
        static public function makeCategorizable($extensionKey, $tableName, $fieldName = 'categories', array $options = array()) {
                // Update the category registry
-               $result = \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->add($extensionKey, $tableName, $fieldName);
+               $result = \TYPO3\CMS\Core\Category\CategoryRegistry::getInstance()->add($extensionKey, $tableName, $fieldName, $options);
                if ($result === FALSE) {
-                       $message = '\TYPO3\CMS\Core\Category\CategoryRegistry: no category registered for table "%s". Double check if there is a TCA configured';
-                       \TYPO3\CMS\Core\Utility\GeneralUtility::devLog(sprintf($message, $tableName), 'Core', 2);
-               }
-               // Makes sure to add more TCA to an existing structure
-               if (isset($GLOBALS['TCA'][$tableName]['columns'])) {
-                       // Forges a new field, default name is "categories"
-                       $fieldConfiguration = array(
-                               'type' => 'select',
-                               'foreign_table' => 'sys_category',
-                               'foreign_table_where' => ' ORDER BY sys_category.title ASC',
-                               'MM' => 'sys_category_record_mm',
-                               'MM_opposite_field' => 'items',
-                               'MM_match_fields' => array('tablenames' => $tableName),
-                               'size' => 10,
-                               'autoSizeMax' => 50,
-                               'maxitems' => 9999,
-                               'renderMode' => 'tree',
-                               'treeConfig' => array(
-                                       'parentField' => 'parent',
-                                       'appearance' => array(
-                                               'expandAll' => TRUE,
-                                               'showHeader' => TRUE
-                                       )
-                               ),
-                               'wizards' => array(
-                                       '_PADDING' => 1,
-                                       '_VERTICAL' => 1,
-                                       'edit' => array(
-                                               'type' => 'popup',
-                                               'title' => 'Edit',
-                                               'script' => 'wizard_edit.php',
-                                               'icon' => 'edit2.gif',
-                                               'popup_onlyOpenIfSelected' => 1,
-                                               'JSopenParams' => 'height=350,width=580,status=0,menubar=0,scrollbars=1'
-                                       ),
-                                       'add' => array(
-                                               'type' => 'script',
-                                               'title' => 'Create new',
-                                               'icon' => 'add.gif',
-                                               'params' => array(
-                                                       'table' => 'sys_category',
-                                                       'pid' => '###CURRENT_PID###',
-                                                       'setValue' => 'prepend'
-                                               ),
-                                               'script' => 'wizard_add.php'
-                                       )
-                               )
+                       $message = '\TYPO3\CMS\Core\Category\CategoryRegistry: no category registered for table "%s". Key was already registered.';
+                       /** @var $logger \TYPO3\CMS\Core\Log\Logger */
+                       $logger = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Core\Log\LogManager')->getLogger(__CLASS__);
+                       $logger->warning(
+                               sprintf($message, $tableName)
                        );
-                       if (!empty($options['fieldConfiguration'])) {
-                               $fieldConfiguration = \TYPO3\CMS\Core\Utility\GeneralUtility::array_merge_recursive_overrule($fieldConfiguration, $options['fieldConfiguration']);
-                       }
-                       $columns = array(
-                               $fieldName => array(
-                                       'exclude' => 0,
-                                       'label' => 'LLL:EXT:lang/locallang_tca.xlf:sys_category.categories',
-                                       'config' => $fieldConfiguration
-                               )
-                       );
-                       // Adding fields to an existing table definition
-                       self::addTCAcolumns($tableName, $columns);
-                       $fieldList = '--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category, ' . $fieldName;
-                       if (!empty($options['fieldList'])) {
-                               $fieldList = $options['fieldList'];
-                       }
-                       $typesList = '';
-                       if (!empty($options['typesList'])) {
-                               $typesList = $options['typesList'];
-                       }
-                       $position = '';
-                       if (!empty($options['position'])) {
-                               $position = $options['position'];
-                       }
-                       // Makes the new "categories" field to be visible in TSFE.
-                       self::addToAllTCAtypes($tableName, $fieldList, $typesList, $position);
                }
        }
 
index 7a56b63..2787270 100644 (file)
@@ -177,7 +177,7 @@ return array(
                                )
                        )
                ),
-               'defaultCategorizedTables' => 'pages,tt_content', // List of comma separated tables that are categorizable by default.
+               'defaultCategorizedTables' => '', // List of comma separated tables that are categorizable by default.
                'displayErrors' => -1,          // <p>Integer (-1, 0, 1, 2). Configures whether PHP errors should be displayed.</p><dl><dt>0</dt><dd>Do not display any PHP error messages. Overrides the value of "exceptionalErrors" and sets it to 0 (= no errors are turned into exceptions), the configured "productionExceptionHandler" is used as exception handler</dd><dt>1</dt><dd>Display error messages with the registered errorhandler. The configured "debugExceptionHandler" is used as exception handler</dd><dt>2</dt><dd>Display errors only if client matches <a href="#SYS-devIPmask">[SYS][devIPmask]</a>. If devIPmask matches the users IP address  the configured "debugExceptionHandler" is used  for exceptions, if not "productionExceptionHandler" will be used</dd><dt>-1</dt><dd>Default setting. With this option, you can override the PHP setting "display_errors". If devIPmask matches the users IP address  the configured "debugExceptionHandler" is used  for exceptions, if not "productionExceptionHandler" will be used.</dd></dl>
                'productionExceptionHandler' => 'TYPO3\\CMS\\Core\\Error\\ProductionExceptionHandler',          // String: Classname to handle exceptions that might happen in the TYPO3-code. Leave empty to disable exception handling. Default: "TYPO3\\CMS\\Core\\Error\\ProductionExceptionHandler". This exception handler displays a nice error message when something went wrong. The error message is logged to the configured logs. Note: The configured "productionExceptionHandler" is used if displayErrors is set to "0" or to "-1" and devIPmask doesn't match the users IP.
                'debugExceptionHandler' => 'TYPO3\\CMS\\Core\\Error\\DebugExceptionHandler',            // String: Classname to handle exceptions that might happen in the TYPO3-code. Leave empty to disable exception handling. Default: "TYPO3\\CMS\\Core\\Error\\DebugExceptionHandler". This exception handler displays the complete stack trace of any encountered exception. The error message and the stack trace  is logged to the configured logs. Note: The configured "debugExceptionHandler" is used if displayErrors is set to "1" and if displayErrors is "-1"  or "2" and the devIPmask matches the users IP.
index dac5f40..0f248ee 100644 (file)
@@ -28,6 +28,7 @@ namespace TYPO3\CMS\Core\Tests\Unit\Category;
  * Testcase for CategoryRegistry
  *
  * @author Oliver Hader <oliver.hader@typo3.org>
+ * @author Fabien Udriot <fabien.udriot@typo3.org>
  */
 class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
 
@@ -51,7 +52,7 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                        'second' => uniqid('second')
                );
                foreach ($this->tables as $tableName) {
-                       $GLOBALS['TCA'][$tableName] = array('ctrl' => array());
+                       $GLOBALS['TCA'][$tableName] = array('ctrl' => array(), 'columns' => array());
                }
        }
 
@@ -81,7 +82,11 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function doesAddReturnFalseOnUndefinedTable() {
-               $this->assertFalse($this->fixture->add('test_extension_a', uniqid('undefined'), 'categories'));
+               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
+
+               $this->assertFalse(
+                       $this->fixture->add('test_extension_a', $this->tables['first'], 'categories')
+               );
        }
 
        /**
@@ -92,8 +97,16 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->fixture->add('test_extension_b', $this->tables['second'], 'categories');
                $registry = $this->fixture->get();
                ob_flush();
-               $this->assertEquals('categories', $registry['test_extension_a'][$this->tables['first']]);
-               $this->assertEquals('categories', $registry['test_extension_b'][$this->tables['second']]);
+
+               $this->assertEquals(
+                       'categories',
+                       $registry['test_extension_a'][$this->tables['first']]['fieldName']
+               );
+
+               $this->assertEquals(
+                       'categories',
+                       $registry['test_extension_b'][$this->tables['second']]['fieldName']
+               );
        }
 
        /**
@@ -103,8 +116,16 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
                $this->fixture->add('test_extension_b', $this->tables['second'], 'categories');
                $registry = $this->fixture->get();
-               $this->assertEquals('categories', $registry['test_extension_a'][$this->tables['first']]);
-               $this->assertEquals('categories', $registry['test_extension_b'][$this->tables['second']]);
+
+               $this->assertEquals(
+                       'categories',
+                       $registry['test_extension_a'][$this->tables['first']]['fieldName']
+               );
+
+               $this->assertEquals(
+                       'categories',
+                       $registry['test_extension_b'][$this->tables['second']]['fieldName']
+               );
        }
 
        /**
@@ -114,7 +135,11 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->fixture->add('test_extension_a', $this->tables['first'], $this->tables['first']);
                $this->fixture->add('test_extension_b', $this->tables['second'], $this->tables['second']);
                $registry = $this->fixture->get();
-               $this->assertEquals($this->tables['first'], $registry['test_extension_a'][$this->tables['first']]);
+
+               $this->assertEquals(
+                       $this->tables['first'],
+                       $registry['test_extension_a'][$this->tables['first']]['fieldName']
+               );
        }
 
        /**
@@ -148,6 +173,29 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
                $this->assertEquals($matches[2][0], 'categories');
        }
 
+       /**
+        * @test
+        */
+       public function areDefaultCategorizedTabledLoaded() {
+               $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultCategorizedTables'] = $this->tables['first'] . ',' . $this->tables['second'];
+               $this->fixture->applyTca();
+
+               $registry = $this->fixture->get();
+               $this->assertCount(2, $registry['core']);
+               $this->assertSame(key($registry['core']), $this->tables['first']);
+       }
+
+       /**
+        * @test
+        */
+       public function canApplyTca() {
+               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->fixture->add('test_extension_b', $this->tables['second'], 'categories');
+               $this->fixture->applyTca();
+               foreach ($this->tables as $table) {
+                       $this->assertNotEmpty($GLOBALS['TCA'][$table]['columns']['categories']);
+               }
+       }
 }
 
 ?>
\ No newline at end of file
index cb0d2d3..2d0e66e 100644 (file)
@@ -1416,10 +1416,10 @@ class ExtensionManagementUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
                        'ctrl' => array(),
                        'columns' => array()
                );
-               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', array('add'));
-               $registryMock->expects($this->once())->method('add')->with($extensionKey, $tableName, 'categories');
+               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', array('dummy'));
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', $registryMock);
                \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable($extensionKey, $tableName);
+               $registryMock->applyTca();
                $this->assertNotEmpty($GLOBALS['TCA'][$tableName]['columns']['categories']);
        }
 
@@ -1434,10 +1434,10 @@ class ExtensionManagementUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
                        'ctrl' => array(),
                        'columns' => array()
                );
-               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', array('add'));
-               $registryMock->expects($this->once())->method('add')->with($extensionKey, $tableName, $fieldName);
+               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', array('dummy'));
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', $registryMock);
                \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::makeCategorizable($extensionKey, $tableName, $fieldName);
+               $registryMock->applyTca();
                $this->assertNotEmpty($GLOBALS['TCA'][$tableName]['columns'][$fieldName]);
        }