[BUGFIX] Followup Fluid Template Fallback paths 03/24903/24
authorAnja Leichsenring <aleichsenring@ab-softlab.de>
Mon, 25 Nov 2013 23:32:39 +0000 (00:32 +0100)
committerMarc Bastian Heinrichs <typo3@mbh-software.de>
Fri, 13 Dec 2013 09:10:55 +0000 (10:10 +0100)
In the previously merged patch are some glitches and a regression:
- The usage (and test for existence) of deprecated functions has been
  removed.
- The value passed by the old behaviour is now considered last place
  in the array providing the lookup paths
- The typo preventing usage setLayoutPaths() has been removed.

Intended usage:
plugin.tx_a.view.templateRootPaths {
default = <some default path>
extendedA = <some additional path>
}
The array gets reversed and the first hit will be used as template.
In case only numeric indizes are used, the entries get ordered.
See unit tests for a more specific description.

Change-Id: If4fa75347614cf9b352c6016430a928833cc62cd
Resolves: #52971
Documentation: #52761
Releases: 6.2
Reviewed-on: https://review.typo3.org/24903
Reviewed-by: Alexander Stehlik
Tested-by: Alexander Stehlik
Reviewed-by: Marc Bastian Heinrichs
Tested-by: Marc Bastian Heinrichs
typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
typo3/sysext/extbase/Classes/Utility/ArrayUtility.php
typo3/sysext/extbase/Classes/Utility/ExtensionUtility.php
typo3/sysext/extbase/Tests/Unit/Mvc/Controller/ActionControllerTest.php
typo3/sysext/extbase/Tests/Unit/Utility/ArrayUtilityTest.php
typo3/sysext/extbase/Tests/Unit/Utility/ExtensionUtilityTest.php

index 8b57ab4..ce90210 100644 (file)
@@ -124,6 +124,7 @@ class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractControl
         * method.
         *
         * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The current request
+        *
         * @return boolean TRUE if this request type is supported, otherwise FALSE
         */
        public function canProcessRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request) {
@@ -135,6 +136,7 @@ class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractControl
         *
         * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request The request object
         * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response The response, modified by this handler
+        *
         * @throws \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException
         * @return void
         */
@@ -339,7 +341,7 @@ class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractControl
                } elseif (is_string($actionResult) && strlen($actionResult) > 0) {
                        $this->response->appendContent($actionResult);
                } elseif (is_object($actionResult) && method_exists($actionResult, '__toString')) {
-                       $this->response->appendContent((string) $actionResult);
+                       $this->response->appendContent((string)$actionResult);
                }
        }
 
@@ -392,46 +394,81 @@ class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractControl
         */
        protected function setViewConfiguration(ViewInterface $view) {
                // Template Path Override
-               $extbaseFrameworkConfiguration = $this->configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
-               if (isset($extbaseFrameworkConfiguration['view']['templateRootPath'])
-                       && strlen($extbaseFrameworkConfiguration['view']['templateRootPath']) > 0
-                       && method_exists($view, 'setTemplateRootPath')
-               ) {
-                       $view->setTemplateRootPath($extbaseFrameworkConfiguration['view']['templateRootPath']);
-               } elseif (!empty($extbaseFrameworkConfiguration['view']['templateRootPaths'])
-                       && is_array($extbaseFrameworkConfiguration['view']['templateRootPaths'])
-                       && method_exists($view, 'setTemplateRootPaths')
-               ) {
-                       $paths = $extbaseFrameworkConfiguration['view']['templateRootPaths'];
-                       krsort($paths);
-                       $view->setTemplateRootPaths($paths);
+               $extbaseFrameworkConfiguration = $this->configurationManager->getConfiguration(
+                       ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK
+               );
+
+               // set TemplateRootPaths
+               $viewFunctionName = 'setTemplateRootPaths';
+               if (method_exists($view, $viewFunctionName)) {
+                       $deprecatedSetting = 'templateRootPath';
+                       $setting = 'templateRootPaths';
+                       $parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting);
+                       // no need to bother if there is nothing to set
+                       if ($parameter) {
+                               $view->$viewFunctionName($parameter);
+                       }
                }
-               if (isset($extbaseFrameworkConfiguration['view']['layoutRootPath'])
-                       && strlen($extbaseFrameworkConfiguration['view']['layoutRootPath']) > 0
-                       && method_exists($view, 'setLayoutRootPath')
-               ) {
-                       $view->setLayoutRootPath($extbaseFrameworkConfiguration['view']['layoutRootPath']);
-               } elseif (!empty($extbaseFrameworkConfiguration['view']['layoutRootPaths'])
-                       && is_array($extbaseFrameworkConfiguration['view']['layoutRootPaths'])
-                       && method_exists($view, 'layoutRootPaths')
-               ) {
-                       $paths = $extbaseFrameworkConfiguration['view']['layoutRootPaths'];
-                       krsort($paths);
-                       $view->setLayoutRootPaths($paths);
+
+               // set LayoutRootPaths
+               $viewFunctionName = 'setLayoutRootPaths';
+               if (method_exists($view, $viewFunctionName)) {
+                       $deprecatedSetting = 'layoutRootPath';
+                       $setting = 'layoutRootPaths';
+                       $parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting);
+                       // no need to bother if there is nothing to set
+                       if ($parameter) {
+                               $view->$viewFunctionName($parameter);
+                       }
+               }
+
+               // set PartialRootPaths
+               $viewFunctionName = 'setPartialRootPaths';
+               if (method_exists($view, $viewFunctionName)) {
+                       $deprecatedSetting = 'partialRootPath';
+                       $setting = 'partialRootPaths';
+                       $parameter = $this->getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting);
+                       // no need to bother if there is nothing to set
+                       if ($parameter) {
+                               $view->$viewFunctionName($parameter);
+                       }
                }
-               if (isset($extbaseFrameworkConfiguration['view']['partialRootPath'])
-                       && strlen($extbaseFrameworkConfiguration['view']['partialRootPath']) > 0
-                       && method_exists($view, 'setPartialRootPath')
+       }
+
+       /**
+        * Handles the path resolving for *rootPath(s)
+        * singular one is deprecated and will be removed two versions after 6.2
+        * if deprecated setting is found, use it as the very last fallback target
+        *
+        * numerical arrays get ordered by key ascending
+        *
+        * @param array $extbaseFrameworkConfiguration
+        * @param string $setting parameter name from TypoScript
+        * @param string $deprecatedSetting parameter name from TypoScript
+        *
+        * @return array
+        */
+       protected function getViewProperty($extbaseFrameworkConfiguration, $setting, $deprecatedSetting = '') {
+
+               $values = array();
+
+               if (
+                       !empty($extbaseFrameworkConfiguration['view'][$setting])
+                       && is_array($extbaseFrameworkConfiguration['view'][$setting])
                ) {
-                       $view->setPartialRootPath($extbaseFrameworkConfiguration['view']['partialRootPath']);
-               } elseif (!empty($extbaseFrameworkConfiguration['view']['partialRootPaths'])
-                       && is_array($extbaseFrameworkConfiguration['view']['partialRootPaths'])
-                       && method_exists($view, 'setPartialRootPaths')
+                       $values = \TYPO3\CMS\Extbase\Utility\ArrayUtility::sortArrayWithIntegerKeys($extbaseFrameworkConfiguration['view'][$setting]);
+                       $values = array_reverse($values, TRUE);
+               }
+
+               // @todo remove handling of deprecatedSetting two versions after 6.2
+               if (
+                       isset($extbaseFrameworkConfiguration['view'][$deprecatedSetting])
+                       && strlen($extbaseFrameworkConfiguration['view'][$deprecatedSetting]) > 0
                ) {
-                       $paths = $extbaseFrameworkConfiguration['view']['partialRootPaths'];
-                       krsort($paths);
-                       $view->setPartialRootPaths($paths);
+                       $values[] = $extbaseFrameworkConfiguration['view'][$deprecatedSetting];
                }
+
+               return $values;
        }
 
        /**
@@ -471,6 +508,7 @@ class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractControl
         * or prepare the view in another way before the action is called.
         *
         * @param ViewInterface $view The view to be initialized
+        *
         * @return void
         * @api
         */
@@ -612,6 +650,7 @@ class ActionController extends \TYPO3\CMS\Extbase\Mvc\Controller\AbstractControl
         * Returns a map of action method names and their parameters.
         *
         * @param \TYPO3\CMS\Extbase\Object\ObjectManagerInterface $objectManager
+        *
         * @return array Array of method parameters by action name
         */
        static public function getActionMethodParameters($objectManager) {
index 9527dac..eb44605 100644 (file)
@@ -312,4 +312,25 @@ class ArrayUtility {
                }
                return $result;
        }
+
+       /**
+        * If the array contains numerical keys only, sort it in ascending order
+        *
+        * @param array $array
+        *
+        * @return array
+        */
+       public static function sortArrayWithIntegerKeys($array) {
+               $containsNumericalKeysOnly = TRUE;
+               array_walk($array, function($value, $key) use (&$containsNumericalKeysOnly) {
+                       if (!is_integer($key)) {
+                               $containsNumericalKeysOnly = FALSE;
+                               return;
+                       }
+               });
+               if ($containsNumericalKeysOnly === TRUE) {
+                       ksort($array);
+               }
+               return $array;
+       }
 }
index 5e89bee..c371480 100644 (file)
@@ -90,9 +90,15 @@ class ExtensionUtility {
                }
        }
        view {
-               templateRootPath =
-               layoutRootPath =
-               partialRootPath =
+               templateRootPaths {
+                       #example: fooKey = EXT:bar/foo
+               }
+               layoutRootPaths {
+                       #example: fooKey = EXT:bar/foo
+               }
+               partialRootPaths {
+                       #example: fooKey = EXT:bar/foo
+               }
                 # with defaultPid you can specify the default page uid of this plugin. If you set this to the string "auto" the target page will be determined automatically. Defaults to an empty string that expects the target page to be the current page.
                defaultPid =
        }
index def6aaf..73e5427 100644 (file)
@@ -624,4 +624,405 @@ class ActionControllerTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $mockConfigurationManager->expects($this->any())->method('isFeatureEnabled')->with('rewrittenPropertyMapper')->will($this->returnValue(FALSE));
                $actionController->injectConfigurationManager($mockConfigurationManager);
        }
+
+       /**
+        * @test
+        * @dataProvider templateRootPathDataProvider
+        * @param array $configuration
+        * @param array $expected
+        */
+       public function setViewConfigurationResolvesTemplateRootPathsForTemplateRootPath($configuration, $expected) {
+               $mockController = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ActionController', array('dummy'), array(), '', FALSE);
+               $mockConfigurationManager = $this->getMock('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
+               $mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($configuration));
+               $mockController->injectConfigurationManager($mockConfigurationManager);
+               $mockController->_set('request', $this->getMock('TYPO3\\CMS\\Extbase\\Mvc\\Request'), array('getControllerExtensionKey'));
+               $view = $this->getMock('TYPO3\\CMS\\Extbase\\Mvc\\View\\ViewInterface', array('setControllerContext', 'assign', 'assignMultiple', 'canRender', 'render', 'initializeView', 'setTemplateRootPaths'));
+               $view->expects($this->once())->method('setTemplateRootPaths')->with($expected);
+               $mockController->_call('setViewConfiguration', $view);
+       }
+
+       /**
+        * @return array
+        */
+       public function templateRootPathDataProvider() {
+               return array(
+                       'old behaviour only' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPath' => 'some path'
+                                       )
+                               ),
+                               array('some path')
+                       ),
+                       'new behaviour only with text keys' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPaths' => array(
+                                                       'default' => 'some path',
+                                                       'extended' => 'some other path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       'extended' => 'some other path',
+                                       'default' => 'some path'
+                               )
+                       ),
+                       'new behaviour only with numerical keys' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       '20' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       '20' => 'some other path',
+                                       '15' => 'intermediate specific path',
+                                       '10' => 'some path'
+                               )
+                       ),
+                       'new behaviour only with mixed keys' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       'very_specific' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       '15' => 'intermediate specific path',
+                                       'very_specific' => 'some other path',
+                                       '10' => 'some path'
+                               )
+                       ),
+                       'old and new behaviour mixed with text keys' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPaths' => array(
+                                                       'default' => 'some path',
+                                                       'specific' => 'intermediate specific path',
+                                                       'very_specific' => 'some other path'
+                                               ),
+                                               'templateRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       'very_specific' => 'some other path',
+                                       'specific' => 'intermediate specific path',
+                                       'default' => 'some path',
+                                       '0' => 'old path'
+                               )
+                       ),
+                       'old and new behaviour mixed with numerical keys' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       '20' => 'intermediate specific path',
+                                                       '30' => 'some other path'
+                                               ),
+                                               'templateRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       '30' => 'some other path',
+                                       '20' => 'intermediate specific path',
+                                       '10' => 'some path',
+                                       '31' => 'old path'
+                               )
+                       ),
+                       'old and new behaviour mixed with mixed keys' => array(
+                               array(
+                                       'view' => array(
+                                               'templateRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       'very_specific' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               ),
+                                               'templateRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       '15' => 'intermediate specific path',
+                                       'very_specific' => 'some other path',
+                                       '10' => 'some path',
+                                       '16' => 'old path'
+                               )
+                       )
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider layoutRootPathDataProvider
+        *
+        * @param array $configuration
+        * @param array $expected
+        */
+       public function setViewConfigurationResolvesLayoutRootPathsForLayoutRootPath($configuration, $expected) {
+               $mockController = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ActionController', array('dummy'), array(), '', FALSE);
+               $mockConfigurationManager = $this->getMock('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
+               $mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($configuration));
+               $mockController->injectConfigurationManager($mockConfigurationManager);
+               $mockController->_set('request', $this->getMock('TYPO3\\CMS\\Extbase\\Mvc\\Request'), array('getControllerExtensionKey'));
+               $view = $this->getMock('TYPO3\\CMS\\Extbase\\Mvc\\View\\ViewInterface', array('setControllerContext', 'assign', 'assignMultiple', 'canRender', 'render', 'initializeView', 'setlayoutRootPaths'));
+               $view->expects($this->once())->method('setlayoutRootPaths')->with($expected);
+               $mockController->_call('setViewConfiguration', $view);
+       }
+
+       /**
+        * @return array
+        */
+       public function layoutRootPathDataProvider() {
+               return array(
+                       'old behaviour only' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPath' => 'some path'
+                                       )
+                               ),
+                               array('some path')
+                       ),
+                       'new behaviour only with text keys' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPaths' => array(
+                                                       'default' => 'some path',
+                                                       'extended' => 'some other path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       'extended' => 'some other path',
+                                       'default' => 'some path'
+                               )
+                       ),
+                       'new behaviour only with numerical keys' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       '20' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       '20' => 'some other path',
+                                       '15' => 'intermediate specific path',
+                                       '10' => 'some path'
+                               )
+                       ),
+                       'new behaviour only with mixed keys' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       'very_specific' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       '15' => 'intermediate specific path',
+                                       'very_specific' => 'some other path',
+                                       '10' => 'some path'
+                               )
+                       ),
+                       'old and new behaviour mixed with text keys' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPaths' => array(
+                                                       'default' => 'some path',
+                                                       'specific' => 'intermediate specific path',
+                                                       'very_specific' => 'some other path'
+                                               ),
+                                               'layoutRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       'very_specific' => 'some other path',
+                                       'specific' => 'intermediate specific path',
+                                       'default' => 'some path',
+                                       '0' => 'old path'
+                               )
+                       ),
+                       'old and new behaviour mixed with numerical keys' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       '20' => 'intermediate specific path',
+                                                       '30' => 'some other path'
+                                               ),
+                                               'layoutRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       '30' => 'some other path',
+                                       '20' => 'intermediate specific path',
+                                       '10' => 'some path',
+                                       '31' => 'old path'
+                               )
+                       ),
+                       'old and new behaviour mixed with mixed keys' => array(
+                               array(
+                                       'view' => array(
+                                               'layoutRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       'very_specific' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               ),
+                                               'layoutRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       '15' => 'intermediate specific path',
+                                       'very_specific' => 'some other path',
+                                       '10' => 'some path',
+                                       '16' => 'old path'
+                               )
+                       )
+               );
+       }
+
+       /**
+        * @test
+        * @dataProvider partialRootPathDataProvider
+        *
+        * @param array $configuration
+        * @param array $expected
+        */
+       public function setViewConfigurationResolvesPartialRootPathsForPartialRootPath($configuration, $expected) {
+               $mockController = $this->getAccessibleMock('TYPO3\\CMS\\Extbase\\Mvc\\Controller\\ActionController', array('dummy'), array(), '', FALSE);
+               $mockConfigurationManager = $this->getMock('TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManagerInterface');
+               $mockConfigurationManager->expects($this->any())->method('getConfiguration')->will($this->returnValue($configuration));
+               $mockController->injectConfigurationManager($mockConfigurationManager);
+               $mockController->_set('request', $this->getMock('TYPO3\\CMS\\Extbase\\Mvc\\Request'), array('getControllerExtensionKey'));
+               $view = $this->getMock('TYPO3\\CMS\\Extbase\\Mvc\\View\\ViewInterface', array('setControllerContext', 'assign', 'assignMultiple', 'canRender', 'render', 'initializeView', 'setpartialRootPaths'));
+               $view->expects($this->once())->method('setpartialRootPaths')->with($expected);
+               $mockController->_call('setViewConfiguration', $view);
+       }
+
+       /**
+        * @return array
+        */
+       public function partialRootPathDataProvider() {
+               return array(
+                       'old behaviour only' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPath' => 'some path'
+                                       )
+                               ),
+                               array('some path')
+                       ),
+                       'new behaviour only with text keys' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPaths' => array(
+                                                       'default' => 'some path',
+                                                       'extended' => 'some other path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       'extended' => 'some other path',
+                                       'default' => 'some path'
+                               )
+                       ),
+                       'new behaviour only with numerical keys' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       '20' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       '20' => 'some other path',
+                                       '15' => 'intermediate specific path',
+                                       '10' => 'some path'
+                               )
+                       ),
+                       'new behaviour only with mixed keys' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       'very_specific' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       '15' => 'intermediate specific path',
+                                       'very_specific' => 'some other path',
+                                       '10' => 'some path'
+                               )
+                       ),
+                       'old and new behaviour mixed with text keys' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPath' => 'old path',
+                                               'partialRootPaths' => array(
+                                                       'default' => 'some path',
+                                                       'specific' => 'intermediate specific path',
+                                                       'very_specific' => 'some other path'
+                                               )
+                                       )
+                               ),
+                               array(
+                                       'very_specific' => 'some other path',
+                                       'specific' => 'intermediate specific path',
+                                       'default' => 'some path',
+                                       '0' => 'old path'
+                               )
+                       ),
+                       'old and new behaviour mixed with numerical keys' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       '20' => 'intermediate specific path',
+                                                       '30' => 'some other path'
+                                               ),
+                                               'partialRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       '30' => 'some other path',
+                                       '20' => 'intermediate specific path',
+                                       '10' => 'some path',
+                                       '31' => 'old path'
+                               )
+                       ),
+                       'old and new behaviour mixed with mixed keys' => array(
+                               array(
+                                       'view' => array(
+                                               'partialRootPaths' => array(
+                                                       '10' => 'some path',
+                                                       'very_specific' => 'some other path',
+                                                       '15' => 'intermediate specific path'
+                                               ),
+                                               'partialRootPath' => 'old path'
+                                       )
+                               ),
+                               array(
+                                       '15' => 'intermediate specific path',
+                                       'very_specific' => 'some other path',
+                                       '10' => 'some path',
+                                       '16' => 'old path'
+                               )
+                       )
+               );
+       }
 }
index 69de2a4..ca66af3 100644 (file)
@@ -377,11 +377,13 @@ class ArrayUtilityTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
 
        /**
         * @test
+        *
         * @param array $inputArray1
         * @param array $inputArray2
         * @param boolean $dontAddNewKeys
         * @param boolean $emptyValuesOverride
         * @param array $expected
+        *
         * @dataProvider arrayMergeRecursiveOverruleData
         */
        public function arrayMergeRecursiveOverruleMergesSimpleArrays(array $inputArray1, array $inputArray2, $dontAddNewKeys, $emptyValuesOverride, array $expected) {
@@ -405,4 +407,64 @@ class ArrayUtilityTest extends \TYPO3\CMS\Extbase\Tests\Unit\BaseTestCase {
                $expected = array(1, 0, 3, 0, 5);
                $this->assertSame($expected, \TYPO3\CMS\Extbase\Utility\ArrayUtility::integerExplode(',', $inputString));
        }
+
+       /**
+        * dataProvider for sortArrayWithIntegerKeys
+        *
+        * @return array
+        */
+       public function sortArrayWithIntegerKeysDataProvider() {
+               return array(
+                       array(
+                               array(
+                                       '20' => 'test1',
+                                       '11' => 'test2',
+                                       '16' => 'test3',
+                               ),
+                               array(
+                                       '11' => 'test2',
+                                       '16' => 'test3',
+                                       '20' => 'test1',
+                               )
+                       ),
+                       array(
+                               array(
+                                       '20' => 'test1',
+                                       '16.5' => 'test2',
+                                       '16' => 'test3',
+                               ),
+                               array(
+                                       '20' => 'test1',
+                                       '16.5' => 'test2',
+                                       '16' => 'test3',
+                               )
+                       ),
+                       array(
+                               array(
+                                       '20' => 'test20',
+                                       'somestring' => 'teststring',
+                                       '16' => 'test16',
+                               ),
+                               array(
+                                       '20' => 'test20',
+                                       'somestring' => 'teststring',
+                                       '16' => 'test16',
+                               )
+                       ),
+               );
+       }
+
+       /**
+        * @test
+        *
+        * @param array $arrayToSort
+        * @param array $expectedArray
+        *
+        * @dataProvider sortArrayWithIntegerKeysDataProvider
+        */
+
+       public function sortArrayWithIntegerKeysSortsNumericArrays(array $arrayToSort, array $expectedArray) {
+               $sortedArray = \TYPO3\CMS\Extbase\Utility\ArrayUtility::sortArrayWithIntegerKeys($arrayToSort);
+               $this->assertSame($sortedArray, $expectedArray);
+       }
 }
index 1abe5be..fc2c750 100644 (file)
@@ -111,9 +111,15 @@ plugin.tx_myextension {
                }
        }
        view {
-               templateRootPath =
-               layoutRootPath =
-               partialRootPath =
+               templateRootPaths {
+                       #example: fooKey = EXT:bar/foo
+               }
+               layoutRootPaths {
+                       #example: fooKey = EXT:bar/foo
+               }
+               partialRootPaths {
+                       #example: fooKey = EXT:bar/foo
+               }
                 # with defaultPid you can specify the default page uid of this plugin. If you set this to the string "auto" the target page will be determined automatically. Defaults to an empty string that expects the target page to be the current page.
                defaultPid =
        }