[FEATURE] Recursive starting point/storage pid via TypoScript
authorStefan Neufeind <typo3.neufeind@speedpartner.de>
Fri, 10 Jun 2011 19:30:06 +0000 (21:30 +0200)
committerStefan Neufeind <typo3.neufeind@speedpartner.de>
Mon, 10 Dec 2012 13:45:39 +0000 (14:45 +0100)
Change-Id: I47840230c1aa094c13bafb1b94c3f09ecadd6a33
Resolves: #6944
Releases: 6.0, 6.1
Reviewed-on: https://review.typo3.org/2636
Reviewed-by: Anja Leichsenring
Tested-by: Anja Leichsenring
Reviewed-by: Stefan Neufeind
Tested-by: Stefan Neufeind
typo3/sysext/extbase/Classes/Configuration/AbstractConfigurationManager.php
typo3/sysext/extbase/Classes/Configuration/BackendConfigurationManager.php
typo3/sysext/extbase/Classes/Configuration/FrontendConfigurationManager.php
typo3/sysext/extbase/Tests/Unit/Configuration/AbstractConfigurationManagerTest.php
typo3/sysext/extbase/Tests/Unit/Configuration/BackendConfigurationManagerTest.php
typo3/sysext/extbase/Tests/Unit/Configuration/FrontendConfigurationManagerTest.php

index b9f1942..99b1e57 100755 (executable)
@@ -165,17 +165,26 @@ abstract class AbstractConfigurationManager implements \TYPO3\CMS\Core\Singleton
                if ($extensionName === NULL || $extensionName === $this->extensionName && $pluginName === $this->pluginName) {
                        $frameworkConfiguration = $this->getContextSpecificFrameworkConfiguration($frameworkConfiguration);
                }
-               if (!empty($frameworkConfiguration['persistence']['storagePid']) && is_array($frameworkConfiguration['persistence']['storagePid'])) {
-                       /** We simulate the frontend to enable the use of cObjects in
-                       stdWrap. Than we convert the configuration to normal TypoScript
-                       and apply the stdWrap to the storagePid */
-                       if (TYPO3_MODE !== 'FE') {
-                               \TYPO3\CMS\Extbase\Utility\FrontendSimulatorUtility::simulateFrontendEnvironment($this->getContentObject());
+
+               if (!empty($frameworkConfiguration['persistence']['storagePid'])) {
+                       if (is_array($frameworkConfiguration['persistence']['storagePid'])) {
+                                       /**
+                                       * We simulate the frontend to enable the use of cObjects in
+                                       * stdWrap. Than we convert the configuration to normal TypoScript
+                                       * and apply the stdWrap to the storagePid
+                                       */
+                               if (TYPO3_MODE !== 'FE') {
+                                       Tx_Extbase_Utility_FrontendSimulator::simulateFrontendEnvironment($this->getContentObject());
+                               }
+                               $conf = $this->typoScriptService->convertPlainArrayToTypoScriptArray($frameworkConfiguration['persistence']);
+                               $frameworkConfiguration['persistence']['storagePid'] = $GLOBALS['TSFE']->cObj->stdWrap($conf['storagePid'], $conf['storagePid.']);
+                               if (TYPO3_MODE !== 'FE') {
+                                       Tx_Extbase_Utility_FrontendSimulator::resetFrontendEnvironment();
+                               }
                        }
-                       $configuration = $this->typoScriptService->convertPlainArrayToTypoScriptArray($frameworkConfiguration['persistence']);
-                       $frameworkConfiguration['persistence']['storagePid'] = $GLOBALS['TSFE']->cObj->stdWrap($configuration['storagePid'], $configuration['storagePid.']);
-                       if (TYPO3_MODE !== 'FE') {
-                               \TYPO3\CMS\Extbase\Utility\FrontendSimulatorUtility::resetFrontendEnvironment();
+
+                       if (!empty($frameworkConfiguration['persistence']['recursive'])) {
+                               $frameworkConfiguration['persistence']['storagePid'] = $this->getRecursiveStoragePids($frameworkConfiguration['persistence']['storagePid'], (int) $frameworkConfiguration['persistence']['recursive']);
                        }
                }
                // 1st level cache
@@ -274,6 +283,17 @@ abstract class AbstractConfigurationManager implements \TYPO3\CMS\Core\Singleton
         * @return array
         */
        abstract protected function getSwitchableControllerActions($extensionName, $pluginName);
+
+       /**
+        * The implementation of the methods to return a list of storagePid that are below a certain
+        * storage pid.
+        *
+        * @param string $storagePid Storage PID to start at; multiple PIDs possible as comma-separated list
+        * @param integer $recursionDepth Maximum number of levels to search, 0 to disable recursive lookup
+        * @return string storage PIDs
+        */
+       abstract protected function getRecursiveStoragePids($storagePid, $recursionDepth = 0);
+
 }
 
 ?>
\ No newline at end of file
index d8d5f1e..12315ae 100644 (file)
@@ -32,6 +32,22 @@ namespace TYPO3\CMS\Extbase\Configuration;
 class BackendConfigurationManager extends \TYPO3\CMS\Extbase\Configuration\AbstractConfigurationManager {
 
        /**
+        * t3lib_queryGenerator is needed to recursively fetch a page tree
+        *
+        * @var \TYPO3\CMS\Core\Database\QueryGenerator
+        */
+       protected $queryGenerator;
+
+       /**
+        * Inject query generator
+        *
+        * @param \TYPO3\CMS\Core\Database\QueryGenerator $queryGenerator
+        */
+       public function injectQueryGenerator(\TYPO3\CMS\Core\Database\QueryGenerator $queryGenerator) {
+               $this->queryGenerator = $queryGenerator;
+       }
+
+       /**
         * @var array
         */
        protected $typoScriptSetupCache = array();
@@ -158,6 +174,33 @@ class BackendConfigurationManager extends \TYPO3\CMS\Extbase\Configuration\Abstr
                }
                return $frameworkConfiguration;
        }
+
+
+       /**
+        * Returns a comma separated list of storagePid that are below a certain storage pid.
+        *
+        *
+        * @param string $storagePid Storage PID to start at; multiple PIDs possible as comma-separated list
+        * @param integer $recursionDepth Maximum number of levels to search, 0 to disable recursive lookup
+        * @return string storage PIDs
+        */
+       protected function getRecursiveStoragePids($storagePid, $recursionDepth = 0) {
+               if ($recursionDepth <= 0) {
+                       return $storagePid;
+               }
+
+               $recursiveStoragePids = '';
+               $storagePids = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $storagePid);
+               foreach ($storagePids as $startPid) {
+                       $pids = $this->queryGenerator->getTreeList($startPid, $recursionDepth, 0, 1);
+                       if (strlen($pids) > 0) {
+                               $recursiveStoragePids .= $pids . ',';
+                       }
+               }
+
+               return rtrim($recursiveStoragePids, ',');
+       }
+
 }
 
 ?>
\ No newline at end of file
index a611625..d850685 100644 (file)
@@ -221,6 +221,29 @@ class FrontendConfigurationManager extends \TYPO3\CMS\Extbase\Configuration\Abst
                }
                return $frameworkConfiguration;
        }
+
+       /**
+        * Returns a comma separated list of storagePid that are below a certain storage pid.
+        *
+        * @param string $storagePid Storage PID to start at; multiple PIDs possible as comma-separated list
+        * @param integer $recursionDepth Maximum number of levels to search, 0 to disable recursive lookup
+        * @return string storage PIDs
+        */
+       protected function getRecursiveStoragePids($storagePid, $recursionDepth = 0) {
+               if ($recursionDepth <= 0) {
+                       return $storagePid;
+               }
+
+               $recursiveStoragePids = '';
+               $storagePids = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $storagePid);
+               foreach ($storagePids as $startPid) {
+                       $pids = $this->getContentObject()->getTreeList($startPid, $recursionDepth, 0);
+                       if (strlen($pids) > 0) {
+                               $recursiveStoragePids .= $pids . ',';
+                       }
+               }
+               return rtrim($recursiveStoragePids, ',');
+       }
 }
 
 ?>
\ No newline at end of file
index 527373a..be6eb42 100644 (file)
@@ -119,7 +119,7 @@ class AbstractConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Bas
         * Sets up this testcase
         */
        public function setUp() {
-               $this->abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               $this->abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions', 'getRecursiveStoragePids'));
                $this->mockTypoScriptService = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Service\\TypoScriptService');
                $this->abstractConfigurationManager->injectTypoScriptService($this->mockTypoScriptService);
        }
@@ -315,7 +315,7 @@ class AbstractConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Bas
         */
        public function switchableControllerActionsAreNotOverriddenIfPluginNameIsSpecified() {
                /** @var \TYPO3\CMS\Extbase\Configuration\AbstractConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface */
-               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions', 'getRecursiveStoragePids'));
                $abstractConfigurationManager->injectTypoScriptService($this->mockTypoScriptService);
                $abstractConfigurationManager->setConfiguration(array('switchableControllerActions' => array('overriddenSwitchableControllerActions')));
                $abstractConfigurationManager->expects($this->any())->method('getPluginConfiguration')->will($this->returnValue(array()));
@@ -329,7 +329,7 @@ class AbstractConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Bas
        public function switchableControllerActionsAreOverriddenIfSpecifiedPluginIsTheCurrentPlugin() {
                /** @var \TYPO3\CMS\Extbase\Configuration\AbstractConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface */
                $configuration = array('extensionName' => 'CurrentExtensionName', 'pluginName' => 'CurrentPluginName', 'switchableControllerActions' => array('overriddenSwitchableControllerActions'));
-               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions', 'getRecursiveStoragePids'));
                $this->mockTypoScriptService->expects($this->any())->method('convertTypoScriptArrayToPlainArray')->with($configuration)->will($this->returnValue($configuration));
                $abstractConfigurationManager->injectTypoScriptService($this->mockTypoScriptService);
                $abstractConfigurationManager->setConfiguration($configuration);
@@ -344,7 +344,7 @@ class AbstractConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Bas
        public function switchableControllerActionsAreOverriddenIfPluginNameIsNotSpecified() {
                /** @var \TYPO3\CMS\Extbase\Configuration\AbstractConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Tests\AccessibleObjectInterface */
                $configuration = array('switchableControllerActions' => array('overriddenSwitchableControllerActions'));
-               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions', 'getRecursiveStoragePids'));
                $this->mockTypoScriptService->expects($this->any())->method('convertTypoScriptArrayToPlainArray')->with($configuration)->will($this->returnValue($configuration));
                $abstractConfigurationManager->injectTypoScriptService($this->mockTypoScriptService);
                $abstractConfigurationManager->setConfiguration($configuration);
@@ -478,7 +478,7 @@ class AbstractConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Bas
                $pluginConfiguration = ($pluginConfigurationConverted = $this->testPluginConfiguration);
                $pluginConfiguration['persistence']['storagePid'] = $storagePidSettings;
                $pluginConfigurationConverted['persistence']['storagePid'] = $storagePidSettingsConverted;
-               $abstractConfigurationManager = $this->getMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('getSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration'));
+               $abstractConfigurationManager = $this->getMock('TYPO3\\CMS\\Extbase\\Configuration\\AbstractConfigurationManager', array('getSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getRecursiveStoragePids'));
                $this->mockTypoScriptService->expects($this->any())->method('convertPlainArrayToTypoScriptArray')->with($storagePidSettings)->will($this->returnValue($storagePidSettingsConverted));
                $this->mockTypoScriptService->expects($this->atLeastOnce())->method('convertTypoScriptArrayToPlainArray')->with($this->testTypoScriptSetup['config.']['tx_extbase.'])->will($this->returnValue($this->testTypoScriptSetupConverted['config']['tx_extbase']));
                $abstractConfigurationManager->injectTypoScriptService($this->mockTypoScriptService);
index cfb8ea0..fa19d9f 100644 (file)
@@ -345,6 +345,60 @@ class BackendConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Base
                $actualResult = $this->backendConfigurationManager->_call('getContextSpecificFrameworkConfiguration', $frameworkConfiguration);
                $this->assertEquals($expectedResult, $actualResult);
        }
+
+       /**
+        * @test
+        */
+       public function storagePidsAreExtendedIfRecursiveSearchIsConfigured() {
+               $storagePid = '1,2,3';
+               $recursive = 99;
+               /** @var $abstractConfigurationManager \TYPO3\CMS\Extbase\Configuration\BackendConfigurationManager */
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\CMS\\Extbase\\Configuration\\BackendConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               $queryGenerator = $this->getMock('TYPO3\\CMS\\Core\\Database\\QueryGenerator');
+               $queryGenerator->expects($this->any())
+                       ->method('getTreeList')
+                       ->will($this->onConsecutiveCalls('1,4', '2', '3,5,6'));
+               $abstractConfigurationManager->injectQueryGenerator($queryGenerator);
+
+               $expectedResult = '1,4,2,3,5,6';
+               $actualResult = $abstractConfigurationManager->_call('getRecursiveStoragePids', $storagePid, $recursive);
+               $this->assertEquals($expectedResult, $actualResult);
+       }
+
+       /**
+        * @test
+        */
+       public function storagePidsAreNotExtendedIfRecursiveSearchIsNotConfigured() {
+               $storagePid = '1,2,3';
+
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\BackendConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+
+               $queryGenerator = $this->getMock('TYPO3\\CMS\\Core\\Database\\QueryGenerator');
+               $queryGenerator->expects($this->never())->method('getTreeList');
+               $abstractConfigurationManager->injectQueryGenerator($queryGenerator);
+
+               $expectedResult = '1,2,3';
+               $actualResult = $abstractConfigurationManager->_call('getRecursiveStoragePids', $storagePid);
+               $this->assertEquals($expectedResult, $actualResult);
+       }
+
+       /**
+        * @test
+        */
+       public function storagePidsAreNotExtendedIfRecursiveSearchIsConfiguredForZeroLevels() {
+               $storagePid = '1,2,3';
+               $recursive = 0;
+
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\BackendConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+
+               $queryGenerator = $this->getMock('TYPO3\\CMS\\Core\\Database\\QueryGenerator');
+               $queryGenerator->expects($this->never())->method('getTreeList');
+               $abstractConfigurationManager->injectQueryGenerator($queryGenerator);
+
+               $expectedResult = '1,2,3';
+               $actualResult = $abstractConfigurationManager->_call('getRecursiveStoragePids', $storagePid, $recursive);
+               $this->assertEquals($expectedResult, $actualResult);
+       }
 }
 
 ?>
\ No newline at end of file
index 92a6e65..4976b0a 100644 (file)
@@ -333,6 +333,63 @@ class FrontendConfigurationManagerTest extends \TYPO3\CMS\Extbase\Tests\Unit\Bas
                $actualResult = $frontendConfigurationManager->_call('getContextSpecificFrameworkConfiguration', $frameworkConfiguration);
                $this->assertEquals($expectedResult, $actualResult);
        }
+
+       /**
+        * @test
+        */
+       public function storagePidsAreExtendedIfRecursiveSearchIsConfigured() {
+               $storagePid = '3,5,9';
+               $recursive = 99;
+               /** @var $abstractConfigurationManager \TYPO3\CMS\Extbase\Configuration\FrontendConfigurationManager */
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\FrontendConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               /** @var $cObjectMock \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
+               $cObjectMock = $this->getMock('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
+               $cObjectMock->expects($this->any())
+                       ->method('getTreeList')
+                       ->will($this->onConsecutiveCalls('3,4', '5', '9,898,12'));
+               $abstractConfigurationManager->setContentObject($cObjectMock);
+
+               $expectedResult = '3,4,5,9,898,12';
+               $actualResult = $abstractConfigurationManager->_call('getRecursiveStoragePids', $storagePid, $recursive);
+               $this->assertEquals($expectedResult, $actualResult);
+       }
+
+       /**
+        * @test
+        */
+       public function storagePidsAreNotExtendedIfRecursiveSearchIsNotConfigured() {
+               $storagePid = '1,2,3';
+
+               /** @var $abstractConfigurationManager \TYPO3\CMS\Extbase\Configuration\FrontendConfigurationManager */
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\FrontendConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+               /** @var $cObjectMock \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
+               $cObjectMock = $this->getMock('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
+               $cObjectMock->expects($this->never())->method('getTreeList');
+               $abstractConfigurationManager->setContentObject($cObjectMock);
+
+               $expectedResult = '1,2,3';
+               $actualResult = $abstractConfigurationManager->_call('getRecursiveStoragePids', $storagePid);
+               $this->assertEquals($expectedResult, $actualResult);
+       }
+
+       /**
+        * @test
+        */
+       public function storagePidsAreNotExtendedIfRecursiveSearchIsConfiguredForZeroLevels() {
+               $storagePid = '1,2,3';
+               $recursive = 0;
+
+               $abstractConfigurationManager = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Configuration\\FrontendConfigurationManager', array('overrideSwitchableControllerActions', 'getContextSpecificFrameworkConfiguration', 'getTypoScriptSetup', 'getPluginConfiguration', 'getSwitchableControllerActions'));
+
+               /** @var $cObjectMock \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
+               $cObjectMock = $this->getMock('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
+               $cObjectMock->expects($this->never())->method('getTreeList');
+               $abstractConfigurationManager->setContentObject($cObjectMock);
+
+               $expectedResult = '1,2,3';
+               $actualResult = $abstractConfigurationManager->_call('getRecursiveStoragePids', $storagePid, $recursive);
+               $this->assertEquals($expectedResult, $actualResult);
+       }
 }
 
 ?>
\ No newline at end of file