[BUGFIX] Re-Establish correct Fluid path ordering 79/48279/20
authorHelmut Hummel <typo3@helhum.io>
Fri, 16 Sep 2016 23:47:55 +0000 (01:47 +0200)
committerHelmut Hummel <typo3@helhum.io>
Sat, 17 Sep 2016 18:17:01 +0000 (20:17 +0200)
Instead of sorting path arrays in various places,
put the sorting of Fluid paths into the TemplatePath
object.

This add sorting for FLUIDTEMPLATE content object again.
Additionally we can remove the sorting done in the
Extbase ActionController.

Fluid upstream fixes are inlcuded to cover all cases.

Fluid changes:
https://github.com/TYPO3Fluid/Fluid/compare/1.0.7...1.0.9

Resolves: #75862
Releases: master
Change-Id: I39a4be14a4b21092a3da7eb47ce332848c2b178b
Reviewed-on: https://review.typo3.org/48279
Reviewed-by: Sascha Egerer <sascha@sascha-egerer.de>
Tested-by: Sascha Egerer <sascha@sascha-egerer.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Tested-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Tested-by: Helmut Hummel <typo3@helhum.io>
composer.lock
typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
typo3/sysext/fluid/Classes/View/TemplatePaths.php
typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php [new file with mode: 0644]

index edce742..adc8ea5 100644 (file)
         },
         {
             "name": "typo3fluid/fluid",
-            "version": "1.0.7",
+            "version": "1.0.9",
             "source": {
                 "type": "git",
                 "url": "https://github.com/TYPO3Fluid/Fluid.git",
-                "reference": "70314b168d14fc38315e554b82238dd966744377"
+                "reference": "52861b6ba2a4d239420c2e207668f4bd96a3b6c6"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/TYPO3Fluid/Fluid/zipball/70314b168d14fc38315e554b82238dd966744377",
-                "reference": "70314b168d14fc38315e554b82238dd966744377",
+                "url": "https://api.github.com/repos/TYPO3Fluid/Fluid/zipball/52861b6ba2a4d239420c2e207668f4bd96a3b6c6",
+                "reference": "52861b6ba2a4d239420c2e207668f4bd96a3b6c6",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.5.0"
             },
             "require-dev": {
-                "mikey179/vfsstream": "*",
-                "phpunit/phpunit": "*",
-                "satooshi/php-coveralls": "*"
+                "mikey179/vfsstream": "^1.6",
+                "phpunit/phpunit": "^4.8",
+                "satooshi/php-coveralls": "^1.0"
             },
             "bin": [
                 "bin/fluid"
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "LGPL-3.0+"
+                "LGPL-3.0"
             ],
             "description": "The TYPO3 Fluid template rendering engine",
-            "time": "2016-05-09 20:32:46"
+            "time": "2016-08-30 14:04:02"
         }
     ],
     "packages-dev": [
index 9b8bb8f..dfc1942 100644 (file)
@@ -19,7 +19,6 @@ use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
 use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
-use TYPO3\CMS\Extbase\Utility\ArrayUtility;
 use TYPO3\CMS\Extbase\Validation\Validator\AbstractCompositeValidator;
 
 /**
@@ -432,8 +431,7 @@ class ActionController extends AbstractController
             !empty($extbaseFrameworkConfiguration['view'][$setting])
             && is_array($extbaseFrameworkConfiguration['view'][$setting])
         ) {
-            $values = ArrayUtility::sortArrayWithIntegerKeys($extbaseFrameworkConfiguration['view'][$setting]);
-            $values = array_reverse($values, true);
+            $values = $extbaseFrameworkConfiguration['view'][$setting];
         }
 
         return $values;
index 7418c26..ee0fa28 100644 (file)
@@ -19,6 +19,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\Utility\ArrayUtility;
 
 /**
  * Class TemplatePaths
@@ -76,27 +77,42 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths
         if (empty($extensionKey)) {
             return [];
         }
-        if (empty($this->typoScript)) {
-            $this->typoScript = GeneralUtility::removeDotsFromTS(
-                $this->getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT)
-            );
-        }
-        $signature = str_replace('_', '', $extensionKey);
+
         $resources = $this->getExtensionPrivateResourcesPath($extensionKey);
-        $configuration = [];
         $paths = [
             self::CONFIG_TEMPLATEROOTPATHS => [$resources . 'Templates/'],
             self::CONFIG_PARTIALROOTPATHS => [$resources . 'Partials/'],
             self::CONFIG_LAYOUTROOTPATHS => [$resources . 'Layouts/']
         ];
-        if (TYPO3_MODE === 'BE' && isset($this->typoScript['module']['tx_' . $signature]['view'])) {
-            $configuration = (array) $this->typoScript['module']['tx_' . $signature]['view'];
-        } elseif (TYPO3_MODE === 'FE' && isset($this->typoScript['plugin']['tx_' . $signature]['view'])) {
-            $configuration = (array) $this->typoScript['plugin']['tx_' . $signature]['view'];
+
+        $configuredPaths = [];
+        if (!empty($this->templateRootPaths) || !empty($this->partialRootPaths) || !empty($this->layoutRootPaths)) {
+            // The view was configured already
+            $configuredPaths = [
+                self::CONFIG_TEMPLATEROOTPATHS => $this->templateRootPaths,
+                self::CONFIG_PARTIALROOTPATHS => $this->partialRootPaths,
+                self::CONFIG_LAYOUTROOTPATHS => $this->layoutRootPaths,
+            ];
+        } else {
+            if (empty($this->typoScript)) {
+                $this->typoScript = GeneralUtility::removeDotsFromTS(
+                    $this->getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT)
+                );
+            }
+            $signature = str_replace('_', '', $extensionKey);
+            if (TYPO3_MODE === 'BE' && isset($this->typoScript['module']['tx_' . $signature]['view'])) {
+                $configuredPaths = (array)$this->typoScript['module']['tx_' . $signature]['view'];
+            } elseif (TYPO3_MODE === 'FE' && isset($this->typoScript['plugin']['tx_' . $signature]['view'])) {
+                $configuredPaths = (array)$this->typoScript['plugin']['tx_' . $signature]['view'];
+            }
         }
-        foreach ($paths as $name => $values) {
-            $paths[$name] = (array)$configuration[$name] + $values;
+
+        foreach ($paths as $name => $defaultPaths) {
+            if (!empty($configuredPaths[$name])) {
+                $paths[$name] = (array)$configuredPaths[$name] + $defaultPaths;
+            }
         }
+
         return $paths;
     }
 
@@ -153,4 +169,43 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths
     {
         $this->fillFromConfigurationArray($this->getContextSpecificViewConfiguration($packageName));
     }
+
+    /**
+     * Overridden setter with enforced sorting behavior
+     *
+     * @param array $templateRootPaths
+     * @return void
+     */
+    public function setTemplateRootPaths(array $templateRootPaths)
+    {
+        parent::setTemplateRootPaths(
+            ArrayUtility::sortArrayWithIntegerKeys($templateRootPaths)
+        );
+    }
+
+    /**
+     * Overridden setter with enforced sorting behavior
+     *
+     * @param array $layoutRootPaths
+     * @return void
+     */
+    public function setLayoutRootPaths(array $layoutRootPaths)
+    {
+        parent::setLayoutRootPaths(
+            ArrayUtility::sortArrayWithIntegerKeys($layoutRootPaths)
+        );
+    }
+
+    /**
+     * Overridden setter with enforced sorting behavior
+     *
+     * @param array $partialRootPaths
+     * @return void
+     */
+    public function setPartialRootPaths(array $partialRootPaths)
+    {
+        parent::setPartialRootPaths(
+            ArrayUtility::sortArrayWithIntegerKeys($partialRootPaths)
+        );
+    }
 }
diff --git a/typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php b/typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php
new file mode 100644 (file)
index 0000000..403a6e8
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+namespace TYPO3\CMS\Fluid\Tests\Unit\View;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Tests\UnitTestCase;
+use TYPO3\CMS\Fluid\View\TemplatePaths;
+
+/**
+ * Test case
+ */
+class TemplatePathsTest extends UnitTestCase
+{
+    /**
+     * @return array
+     */
+    public function getPathSetterMethodTestValues()
+    {
+        $generator = function ($method, $indexType = 'numeric') {
+            switch ($indexType) {
+                default:
+                case 'numeric':
+                    $set = [
+                        20 => 'bar',
+                        0 => 'baz',
+                        100 => 'boz',
+                        10 => 'foo',
+                    ];
+                    $expected = [
+                        0 => 'baz',
+                        10 => 'foo',
+                        20 => 'bar',
+                        100 => 'boz',
+                    ];
+                    break;
+                case 'alpha':
+                    $set = [
+                        'bcd' => 'bar',
+                        'abc' => 'foo',
+                    ];
+                    $expected = [
+                        'bcd' => 'bar',
+                        'abc' => 'foo',
+                    ];
+                    break;
+                case 'alphanumeric':
+                    $set = [
+                        0 => 'baz',
+                        'bcd' => 'bar',
+                        15 => 'boz',
+                        'abc' => 'foo',
+                    ];
+                    $expected = [
+                        0 => 'baz',
+                        'bcd' => 'bar',
+                        15 => 'boz',
+                        'abc' => 'foo',
+                    ];
+                    break;
+            }
+            return [$method, $set, $expected];
+        };
+        return [
+            'simple numeric index, template' => $generator(TemplatePaths::CONFIG_TEMPLATEROOTPATHS, 'numeric'),
+            'alpha index, template' => $generator(TemplatePaths::CONFIG_TEMPLATEROOTPATHS, 'alpha'),
+            'alpha-numeric index, template' => $generator(TemplatePaths::CONFIG_TEMPLATEROOTPATHS, 'alphanumeric'),
+            'simple numeric index, partial' => $generator(TemplatePaths::CONFIG_PARTIALROOTPATHS, 'numeric'),
+            'alpha index, partial' => $generator(TemplatePaths::CONFIG_PARTIALROOTPATHS, 'alpha'),
+            'alpha-numeric index, partial' => $generator(TemplatePaths::CONFIG_PARTIALROOTPATHS, 'alphanumeric'),
+            'simple numeric index, layout' => $generator(TemplatePaths::CONFIG_LAYOUTROOTPATHS, 'numeric'),
+            'alpha index, layout' => $generator(TemplatePaths::CONFIG_LAYOUTROOTPATHS, 'alpha'),
+            'alpha-numeric index, layout' => $generator(TemplatePaths::CONFIG_LAYOUTROOTPATHS, 'alphanumeric'),
+        ];
+    }
+
+    /**
+     * @test
+     * @dataProvider getPathSetterMethodTestValues
+     * @param string $method
+     * @param array $paths
+     * @param array $expected
+     */
+    public function pathSetterMethodSortsPathsByKeyDescending($method, array $paths, array $expected)
+    {
+        $setter = 'set' . ucfirst($method);
+        $subject = $this->getMockBuilder(TemplatePaths::class)->setMethods(['sanitizePath'])->getMock();
+        $subject->expects($this->any())->method('sanitizePath')->willReturnArgument(0);
+        $subject->$setter($paths);
+        $this->assertAttributeSame($expected, $method, $subject);
+    }
+}