[BUGFIX] Make category TCA changes cacheable 24/29424/3
authorHelmut Hummel <helmut.hummel@typo3.org>
Sun, 13 Apr 2014 16:56:34 +0000 (18:56 +0200)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Tue, 15 Apr 2014 07:17:31 +0000 (09:17 +0200)
Currently TCA changes of the category API are applied on every request
after the extTables files is included. This makes it impossible to
override the changes by third party extensions and also we do not
benefit from caching.

Instead we now use the introduced signal and apply the changes
right before caching.

With this change we also have a clear separation of
registering category field additions (in ext_localconf.php) and
applying the TCA changes while building the TCA cache.

Resolves: #57881
Releases: 6.2
Change-Id: I385c894fe13eb4cd4f8f2b4c82a9513b05308daa
Reviewed-on: https://review.typo3.org/29424
Reviewed-by: Frans Saris
Tested-by: Frans Saris
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
typo3/sysext/core/Classes/Category/CategoryRegistry.php
typo3/sysext/core/Classes/Core/Bootstrap.php
typo3/sysext/core/Classes/Utility/ExtensionManagementUtility.php
typo3/sysext/core/Tests/Unit/Category/CategoryRegistryTest.php
typo3/sysext/core/Tests/Unit/Utility/ExtensionManagementUtilityTest.php
typo3/sysext/core/ext_localconf.php

index cf80f37..323140d 100644 (file)
@@ -221,7 +221,7 @@ class CategoryRegistry implements \TYPO3\CMS\Core\SingletonInterface {
         *
         * @return void
         */
-       public function applyTca() {
+       protected function applyTca() {
 
                $this->registerDefaultCategorizedTables();
 
@@ -236,6 +236,18 @@ class CategoryRegistry implements \TYPO3\CMS\Core\SingletonInterface {
        }
 
        /**
+        * Slot that is registered for tcaIsBeingBuilt
+        * TCA changes are applied and then cached in ExtensionManagementUtility
+        *
+        * @param array $tca
+        * @return array
+        */
+       public function addCategoryRegistryTcaChanges(array $tca) {
+               $this->applyTca();
+               return array($GLOBALS['TCA']);
+       }
+
+       /**
         * Add default categorized tables to the registry
         *
         * @return void
index 056eac6..729bbb7 100644 (file)
@@ -946,9 +946,6 @@ 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();
        }
 
        /**
index 35d74de..3170a47 100644 (file)
@@ -1924,6 +1924,7 @@ tt_content.' . $key . $prefix . ' {
 
        /**
         * Makes a table categorizable by adding value into the category registry.
+        * FOR USE IN ext_localconf.php FILES.
         *
         * @param string $extensionKey Extension key to be used
         * @param string $tableName Name of the table to be categorized
index 51dff1e..b6943d7 100644 (file)
@@ -35,7 +35,7 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
        /**
         * @var \TYPO3\CMS\Core\Category\CategoryRegistry
         */
-       protected $fixture;
+       protected $subject;
 
        /**
         * @var array
@@ -46,7 +46,7 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * Sets up this test suite.
         */
        protected function setUp() {
-               $this->fixture = new \TYPO3\CMS\Core\Category\CategoryRegistry();
+               $this->subject = new \TYPO3\CMS\Core\Category\CategoryRegistry();
                $this->tables = array(
                        'first' => uniqid('first'),
                        'second' => uniqid('second')
@@ -66,7 +66,7 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function doesAddReturnTrueOnDefinedTable() {
-               $this->assertTrue($this->fixture->add('test_extension_a', $this->tables['first'], 'categories'));
+               $this->assertTrue($this->subject->add('test_extension_a', $this->tables['first'], 'categories'));
        }
 
        /**
@@ -75,65 +75,78 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @expectedExceptionCode 1369122038
         */
        public function doesAddThrowExceptionOnEmptyTablename() {
-               $this->fixture->add('test_extension_a', '', 'categories');
+               $this->subject->add('test_extension_a', '', 'categories');
+       }
+
+       /**
+        * @test
+        */
+       public function addCategoryRegistryTcaChangesReturnsGlobalTcaArray() {
+               $GLOBALS['TCA'] = array(
+                       'foo' => array(
+                               'bar' => 'baz'
+                       )
+               );
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges($GLOBALS['TCA']);
+               $this->assertSame($tca, $GLOBALS['TCA']);
        }
 
        /**
         * @test
         */
        public function areMultipleElementsOfSameExtensionRegistered() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
-               $this->fixture->add('test_extension_a', $this->tables['second'], 'categories');
-               $this->fixture->applyTca();
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->subject->add('test_extension_a', $this->tables['second'], 'categories');
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['first']]['columns']);
-               $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['second']]['columns']);
+               $this->assertArrayHasKey('categories', $tca[$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories', $tca[$this->tables['second']]['columns']);
        }
 
        /**
         * @test
         */
        public function areElementsOfDifferentExtensionsRegistered() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
-               $this->fixture->add('test_extension_b', $this->tables['second'], 'categories');
-               $this->fixture->applyTca();
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['first']]['columns']);
-               $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['second']]['columns']);
+               $this->assertArrayHasKey('categories', $tca[$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories', $tca[$this->tables['second']]['columns']);
        }
 
        /**
         * @test
         */
        public function areElementsOfDifferentExtensionsOnSameTableRegistered() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories1');
-               $this->fixture->add('test_extension_b', $this->tables['first'], 'categories2');
-               $this->fixture->applyTca();
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories1');
+               $this->subject->add('test_extension_b', $this->tables['first'], 'categories2');
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               $this->assertArrayHasKey('categories1', $GLOBALS['TCA'][$this->tables['first']]['columns']);
-               $this->assertArrayHasKey('categories2', $GLOBALS['TCA'][$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories1', $tca[$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories2', $tca[$this->tables['first']]['columns']);
        }
 
        /**
         * @test
         */
        public function areElementsOfSameExtensionOnSameTableRegistered() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories1');
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories2');
-               $this->fixture->applyTca();
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories1');
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories2');
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               $this->assertArrayHasKey('categories1', $GLOBALS['TCA'][$this->tables['first']]['columns']);
-               $this->assertArrayHasKey('categories2', $GLOBALS['TCA'][$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories1', $tca[$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories2', $tca[$this->tables['first']]['columns']);
        }
 
        /**
         * @test
         */
        public function areDatabaseDefinitionsOfAllElementsAvailable() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
-               $this->fixture->add('test_extension_b', $this->tables['second'], 'categories');
-               $this->fixture->add('test_extension_c', $this->tables['first'], 'categories');
-               $definitions = $this->fixture->getDatabaseTableDefinitions();
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
+               $this->subject->add('test_extension_c', $this->tables['first'], 'categories');
+               $definitions = $this->subject->getDatabaseTableDefinitions();
                $matches = array();
                preg_match_all('#CREATE TABLE\\s*([^ (]+)\\s*\\(\\s*([^ )]+)\\s+int\\(11\\)[^)]+\\);#mis', $definitions, $matches);
                $this->assertEquals(2, count($matches[0]));
@@ -147,9 +160,9 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function areDatabaseDefinitionsOfParticularExtensionAvailable() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
-               $this->fixture->add('test_extension_b', $this->tables['second'], 'categories');
-               $definitions = $this->fixture->getDatabaseTableDefinition('test_extension_a');
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
+               $definitions = $this->subject->getDatabaseTableDefinition('test_extension_a');
                $matches = array();
                preg_match_all('#CREATE TABLE\\s*([^ (]+)\\s*\\(\\s*([^ )]+)\\s+int\\(11\\)[^)]+\\);#mis', $definitions, $matches);
                $this->assertEquals(1, count($matches[0]));
@@ -162,49 +175,49 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         */
        public function areDefaultCategorizedTablesLoaded() {
                $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultCategorizedTables'] = $this->tables['first'] . ',' . $this->tables['second'];
-               $this->fixture->applyTca();
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['first']]['columns']);
-               $this->assertArrayHasKey('categories', $GLOBALS['TCA'][$this->tables['second']]['columns']);
+               $this->assertArrayHasKey('categories', $tca[$this->tables['first']]['columns']);
+               $this->assertArrayHasKey('categories', $tca[$this->tables['second']]['columns']);
        }
 
        /**
         * @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();
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->subject->add('test_extension_b', $this->tables['second'], 'categories');
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               $this->assertNotEmpty($GLOBALS['TCA'][$this->tables['first']]['columns']['categories']);
-               $this->assertNotEmpty($GLOBALS['TCA'][$this->tables['second']]['columns']['categories']);
+               $this->assertNotEmpty($tca[$this->tables['first']]['columns']['categories']);
+               $this->assertNotEmpty($tca[$this->tables['second']]['columns']['categories']);
        }
 
        /**
         * @test
         */
        public function isRegisteredReturnsTrueIfElementIsAlreadyRegistered() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
-               $this->assertTrue($this->fixture->isRegistered($this->tables['first'], 'categories'));
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->assertTrue($this->subject->isRegistered($this->tables['first'], 'categories'));
        }
 
        /**
         * @test
         */
        public function isRegisteredReturnsFalseIfElementIsNotRegistered() {
-               $this->fixture->add('test_extension_a', $this->tables['first'], 'categories');
-               $this->assertFalse($this->fixture->isRegistered($this->tables['first'], '_not_registered'));
-               $this->assertFalse($this->fixture->isRegistered($this->tables['second'], 'categories'));
+               $this->subject->add('test_extension_a', $this->tables['first'], 'categories');
+               $this->assertFalse($this->subject->isRegistered($this->tables['first'], '_not_registered'));
+               $this->assertFalse($this->subject->isRegistered($this->tables['second'], 'categories'));
        }
 
        /**
         * @test
         */
        public function tabIsAddedForElement() {
-               $this->fixture->add('text_extension_a', $this->tables['first']);
-               $this->fixture->applyTca();
+               $this->subject->add('text_extension_a', $this->tables['first']);
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               foreach($GLOBALS['TCA'][$this->tables['first']]['types'] as $typeConfig) {
+               foreach($tca[$this->tables['first']]['types'] as $typeConfig) {
                        $this->assertContains('--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category', $typeConfig['showitem']);
                }
        }
@@ -213,10 +226,10 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function tabIsNotAddedForElementIfFieldListIsSpecified() {
-               $this->fixture->add('text_extension_a', $this->tables['first'], 'categories', array('fieldList' => 'categories'));
-               $this->fixture->applyTca();
+               $this->subject->add('text_extension_a', $this->tables['first'], 'categories', array('fieldList' => 'categories'));
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               foreach($GLOBALS['TCA'][$this->tables['first']]['types'] as $typeConfig) {
+               foreach($tca[$this->tables['first']]['types'] as $typeConfig) {
                        $this->assertNotContains('--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category', $typeConfig['showitem']);
                }
        }
@@ -225,11 +238,11 @@ class CategoryRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
         * @test
         */
        public function tabIsAddedOnlyOncePerTable() {
-               $this->fixture->add('text_extension_a', $this->tables['first'], 'categories1');
-               $this->fixture->add('text_extension_a', $this->tables['first'], 'categories2');
-               $this->fixture->applyTca();
+               $this->subject->add('text_extension_a', $this->tables['first'], 'categories1');
+               $this->subject->add('text_extension_a', $this->tables['first'], 'categories2');
+               list($tca) = $this->subject->addCategoryRegistryTcaChanges(array());
 
-               foreach($GLOBALS['TCA'][$this->tables['first']]['types'] as $typeConfig) {
+               foreach($tca[$this->tables['first']]['types'] as $typeConfig) {
                        $this->assertSame(
                                1, substr_count($typeConfig['showitem'], '--div--;LLL:EXT:lang/locallang_tca.xlf:sys_category.tabs.category')
                        );
index 08b9d38..fc6e3bb 100644 (file)
@@ -1337,24 +1337,23 @@ class ExtensionManagementUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
        /**
         * @test
         */
-       public function isMakeCategorizableAvailableInRegistryWithDefaultField() {
+       public function doesMakeCategorizableCallsTheCategoryRegistryWithDefaultFieldName() {
                $extensionKey = uniqid('extension');
                $tableName = uniqid('table');
                $GLOBALS['TCA'][$tableName] = array(
                        'ctrl' => array(),
                        'columns' => array()
                );
-               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', array('dummy'));
+               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry');
+               $registryMock->expects($this->once())->method('add')->with($extensionKey, $tableName, 'categories', array());
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', $registryMock);
                ExtensionManagementUtility::makeCategorizable($extensionKey, $tableName);
-               $registryMock->applyTca();
-               $this->assertNotEmpty($GLOBALS['TCA'][$tableName]['columns']['categories']);
        }
 
        /**
         * @test
         */
-       public function isMakeCategorizableAvailableInRegistryWithSpecifictField() {
+       public function doesMakeCategorizableCallsTheCategoryRegistryWithFieldName() {
                $extensionKey = uniqid('extension');
                $tableName = uniqid('table');
                $fieldName = uniqid('field');
@@ -1362,11 +1361,10 @@ class ExtensionManagementUtilityTest extends \TYPO3\CMS\Core\Tests\UnitTestCase
                        'ctrl' => array(),
                        'columns' => array()
                );
-               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', array('dummy'));
+               $registryMock = $this->getMock('TYPO3\\CMS\\Core\\Category\\CategoryRegistry');
+               $registryMock->expects($this->once())->method('add')->with($extensionKey, $tableName, $fieldName, array());
                \TYPO3\CMS\Core\Utility\GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Category\\CategoryRegistry', $registryMock);
                ExtensionManagementUtility::makeCategorizable($extensionKey, $tableName, $fieldName);
-               $registryMock->applyTca();
-               $this->assertNotEmpty($GLOBALS['TCA'][$tableName]['columns'][$fieldName]);
        }
 
 }
index 60243c5..c00d7ed 100644 (file)
@@ -2,15 +2,17 @@
 if (!defined('TYPO3_MODE')) {
        die('Access denied.');
 }
+/** @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher */
+$signalSlotDispatcher = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher');
 
 if (TYPO3_MODE === 'BE' && !(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL)) {
-       \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher')->connect(
+       $signalSlotDispatcher->connect(
                'TYPO3\\CMS\\Core\\Resource\\ResourceFactory',
                \TYPO3\CMS\Core\Resource\ResourceFactoryInterface::SIGNAL_PostProcessStorage,
                'TYPO3\\CMS\\Core\\Resource\\Security\\StoragePermissionsAspect',
                'addUserPermissionsToStorage'
        );
-       \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher')->connect(
+       $signalSlotDispatcher->connect(
                'PackageManagement',
                'packagesMayHaveChanged',
                'TYPO3\\CMS\\Core\\Package\\PackageManager',
@@ -18,11 +20,20 @@ if (TYPO3_MODE === 'BE' && !(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_INSTALL)) {
        );
 }
 
-\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher')->connect(
+$signalSlotDispatcher->connect(
        'TYPO3\\CMS\\Core\\Resource\\ResourceStorage',
        \TYPO3\CMS\Core\Resource\ResourceStorageInterface::SIGNAL_PostFileDelete,
        'TYPO3\\CMS\\Core\\Resource\\Processing\\FileDeletionAspect',
        'removeFromRepository'
 );
 
+$signalSlotDispatcher->connect(
+       'TYPO3\\CMS\\Core\\Utility\\ExtensionManagementUtility',
+       'tcaIsBeingBuilt',
+       'TYPO3\\CMS\\Core\\Category\\CategoryRegistry',
+       'addCategoryRegistryTcaChanges'
+);
+
+unset($signalSlotDispatcher);
+
 $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['dumpFile'] = 'EXT:core/Resources/PHP/FileDumpEID.php';