[TASK] Improve performance of Fluid TemplatePaths 62/53862/2
authorClaus Due <claus@namelesscoder.net>
Mon, 28 Aug 2017 20:27:26 +0000 (22:27 +0200)
committerBenni Mack <benni@typo3.org>
Fri, 1 Sep 2017 10:05:31 +0000 (12:05 +0200)
This patch improves the performance of TemplatePaths
in two ways:

* GeneralUtility::removeDotsFromTS() is called on a far
  smaller array instead of all TypoScript.
* Fallback paths are allowed to be cached in the runtime
  cache which avoids re-reading TypoScript when no
  paths are configured in TS.

Saves several thousand calls to removeDotsFromTs
which in turn saves several tens of thousands of calls
to in_array.

Change-Id: Ib8aef69dc9136d355441ac05f21fe391e524eacc
Resolves: #82232
Releases: master, 8.7
Reviewed-on: https://review.typo3.org/53862
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
typo3/sysext/fluid/Classes/View/TemplatePaths.php
typo3/sysext/fluid/Tests/Unit/View/TemplatePathsTest.php

index 274bf47..1a61b56 100644 (file)
@@ -82,10 +82,20 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths
         $cache = $this->getRuntimeCache();
         $cacheIdentifier = 'viewpaths_' . $extensionKey;
         $configuration = $cache->get($cacheIdentifier);
-        if (!empty($configuration)) {
+        if (is_array($configuration)) {
             return $configuration;
         }
 
+        $configuredPaths = [];
+        if (!empty($this->templateRootPaths) || !empty($this->partialRootPaths) || !empty($this->layoutRootPaths)) {
+            // The view was manually configured - early return to avoid caching this configuration.
+            return [
+                self::CONFIG_TEMPLATEROOTPATHS => $this->templateRootPaths,
+                self::CONFIG_PARTIALROOTPATHS => $this->partialRootPaths,
+                self::CONFIG_LAYOUTROOTPATHS => $this->layoutRootPaths,
+            ];
+        }
+
         $resources = $this->getExtensionPrivateResourcesPath($extensionKey);
         $paths = [
             self::CONFIG_TEMPLATEROOTPATHS => [$resources . 'Templates/'],
@@ -93,31 +103,17 @@ class TemplatePaths extends \TYPO3Fluid\Fluid\View\TemplatePaths
             self::CONFIG_LAYOUTROOTPATHS => [$resources . 'Layouts/']
         ];
 
-        $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(
-                    (array)$this->getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT)
-                );
-            }
-            $signature = str_replace('_', '', $extensionKey);
-            if ($this->isBackendMode() && isset($this->typoScript['module']['tx_' . $signature]['view'])) {
-                $configuredPaths = (array)$this->typoScript['module']['tx_' . $signature]['view'];
-            } elseif ($this->isFrontendMode() && isset($this->typoScript['plugin']['tx_' . $signature]['view'])) {
-                $configuredPaths = (array)$this->typoScript['plugin']['tx_' . $signature]['view'];
-            }
+        if (empty($this->typoScript)) {
+            $this->typoScript = (array)$this->getConfigurationManager()->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT);
         }
 
-        if (empty($configuredPaths)) {
-            return $paths;
+        $signature = str_replace('_', '', $extensionKey);
+        if ($this->isBackendMode() && isset($this->typoScript['module.']['tx_' . $signature . '.']['view.'])) {
+            $configuredPaths = (array)$this->typoScript['module.']['tx_' . $signature . '.']['view.'];
+        } elseif ($this->isFrontendMode() && isset($this->typoScript['plugin.']['tx_' . $signature . '.']['view.'])) {
+            $configuredPaths = (array)$this->typoScript['plugin.']['tx_' . $signature . '.']['view.'];
         }
+        $configuredPaths = GeneralUtility::removeDotsFromTS($configuredPaths);
 
         foreach ($paths as $name => $defaultPaths) {
             if (!empty($configuredPaths[$name])) {
index bfb3c2c..58a7643 100644 (file)
@@ -170,7 +170,7 @@ class TemplatePathsTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
         $configurationManager = $this->getMockBuilder(ConfigurationManagerInterface::class)->getMockForAbstractClass();
         $configurationManager->expects($this->once())->method('getConfiguration')->willReturn([
             'module.' => [
-                'tx_test.' => [
+                'tx_test2.' => [
                     'view.' => [
                         'templateRootPaths.' => [
                             '30' => 'third',
@@ -195,12 +195,12 @@ class TemplatePathsTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
         $cache->expects($this->once())->method('get')->willReturn(false);
         $cache->expects($this->once())->method('set');
         $subject = $this->getMockBuilder(TemplatePaths::class)->setMethods(['getConfigurationManager', 'getExtensionPrivateResourcesPath', 'getRuntimeCache', 'isBackendMode', 'isFrontendMode'])->getMock();
-        $subject->expects($this->once())->method('getExtensionPrivateResourcesPath')->with('test')->willReturn('test/');
+        $subject->expects($this->once())->method('getExtensionPrivateResourcesPath')->with('test2')->willReturn('test/');
         $subject->expects($this->once())->method('getConfigurationManager')->willReturn($configurationManager);
         $subject->expects($this->once())->method('getRuntimeCache')->willReturn($cache);
         $subject->expects($this->once())->method('isBackendMode')->willReturn(true);
         $subject->expects($this->never())->method('isFrontendMode');
-        $result = $this->callInaccessibleMethod($subject, 'getContextSpecificViewConfiguration', 'test');
+        $result = $this->callInaccessibleMethod($subject, 'getContextSpecificViewConfiguration', 'test2');
         $this->assertSame([
             'templateRootPaths' => [
                 'test/Templates/',
@@ -254,7 +254,7 @@ class TemplatePathsTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
         ]);
         $cache = $this->getMockBuilder(VariableFrontend::class)->setMethods(['get', 'set'])->disableOriginalConstructor()->getMock();
         $cache->expects($this->once())->method('get')->willReturn(false);
-        $cache->expects($this->never())->method('set');
+        $cache->expects($this->once())->method('set');
         $subject = $this->getMockBuilder(TemplatePaths::class)->setMethods(['getConfigurationManager', 'getExtensionPrivateResourcesPath', 'getRuntimeCache', 'isBackendMode', 'isFrontendMode'])->getMock();
         $subject->expects($this->once())->method('getExtensionPrivateResourcesPath')->with('test')->willReturn('test/');
         $subject->expects($this->once())->method('getConfigurationManager')->willReturn($configurationManager);