[BUGFIX] Cache results of explodeSoftRefParserList() 90/35190/12
authorStephan Großberndt <stephan@grossberndt.de>
Tue, 9 Dec 2014 13:33:57 +0000 (14:33 +0100)
committerXavier Perseguers <xavier@typo3.org>
Mon, 13 Apr 2015 14:58:38 +0000 (16:58 +0200)
BackendUtility::explodeSoftRefParserList() is called with a very
limited set of input parameters, but processing is rather expensive.

Introduce a runtime cache to avoid processing the softrefs over
and over.
This especially speeds up calls from ReferenceIndex::getRelations(),
which is called many times.

Resolves: #63675
Releases: master, 6.2
Change-Id: I34a4392533828667c1b63b1ecb4ca12580e05e06
Reviewed-on: http://review.typo3.org/35190
Reviewed-by: Nicole Cordes <typo3@cordes.co>
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
Reviewed-by: Andreas Fernandez <andreas.fernandez@aspedia.de>
Reviewed-by: Xavier Perseguers <xavier@typo3.org>
Tested-by: Xavier Perseguers <xavier@typo3.org>
typo3/sysext/backend/Classes/Utility/BackendUtility.php
typo3/sysext/core/Classes/Database/ReferenceIndex.php
typo3/sysext/core/Classes/Database/SoftReferenceIndex.php
typo3/sysext/linkvalidator/Classes/LinkAnalyzer.php

index 35ba394..f0fa4f6 100644 (file)
@@ -3737,21 +3737,39 @@ class BackendUtility {
        }
 
        /**
+        * Gets an instance of the runtime cache.
+        *
+        * @return VariableFrontend
+        */
+       static protected function getRuntimeCache() {
+               return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
+       }
+
+       /**
         * Returns array of soft parser references
         *
         * @param string $parserList softRef parser list
-        * @return array Array where the parser key is the key and the value is the parameter string
+        * @return array|bool Array where the parser key is the key and the value is the parameter string, FALSE if no parsers were found
         */
        static public function explodeSoftRefParserList($parserList) {
+               $runtimeCache = self::getRuntimeCache();
+               $cacheId = 'backend-softRefList-' . $parserList;
+               if ($runtimeCache->has($cacheId)) {
+                       return $runtimeCache->get($cacheId);
+               }
+
                // Looking for global parsers:
                if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL']) && !empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) {
                        GeneralUtility::deprecationLog('The hook softRefParser_GL is deprecated since TYPO3 CMS 7 and will be removed in TYPO3 CMS 8');
                        $parserList = implode(',', array_keys($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['softRefParser_GL'])) . ',' . $parserList;
                }
+
                // Return immediately if list is blank:
                if ($parserList === '') {
+                       $runtimeCache->set($cacheId, FALSE);
                        return FALSE;
                }
+
                // Otherwise parse the list:
                $keyList = GeneralUtility::trimExplode(',', $parserList, TRUE);
                $output = array();
@@ -3763,6 +3781,7 @@ class BackendUtility {
                                $output[$val] = '';
                        }
                }
+               $runtimeCache->set($cacheId, $output);
                return $output;
        }
 
index d5af9bb..e18a1b1 100644 (file)
@@ -535,21 +535,24 @@ class ReferenceIndex {
                                        }
                                }
                                // Soft References:
-                               if ((string)$value !== '' && ($softRefs = BackendUtility::explodeSoftRefParserList($conf['softref']))) {
+                               if ((string)$value !== '') {
                                        $softRefValue = $value;
-                                       foreach ($softRefs as $spKey => $spParams) {
-                                               $softRefObj = BackendUtility::softRefParserObj($spKey);
-                                               if (is_object($softRefObj)) {
-                                                       $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
-                                                       if (is_array($resultArray)) {
-                                                               $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements'];
-                                                               if ((string)$resultArray['content'] !== '') {
-                                                                       $softRefValue = $resultArray['content'];
+                                       $softRefs = BackendUtility::explodeSoftRefParserList($conf['softref']);
+                                       if ($softRefs !== FALSE) {
+                                               foreach ($softRefs as $spKey => $spParams) {
+                                                       $softRefObj = BackendUtility::softRefParserObj($spKey);
+                                                       if (is_object($softRefObj)) {
+                                                               $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams);
+                                                               if (is_array($resultArray)) {
+                                                                       $outRow[$field]['softrefs']['keys'][$spKey] = $resultArray['elements'];
+                                                                       if ((string)$resultArray['content'] !== '') {
+                                                                               $softRefValue = $resultArray['content'];
+                                                                       }
                                                                }
                                                        }
                                                }
                                        }
-                                       if (is_array($outRow[$field]['softrefs']) && count($outRow[$field]['softrefs']) && (string)$value !== (string)$softRefValue && strstr($softRefValue, '{softref:')) {
+                                       if (!empty($outRow[$field]['softrefs']) && (string)$value !== (string)$softRefValue && strpos($softRefValue, '{softref:') !== FALSE) {
                                                $outRow[$field]['softrefs']['tokenizedContent'] = $softRefValue;
                                        }
                                }
@@ -613,21 +616,24 @@ class ReferenceIndex {
                        $this->temp_flexRelations['db'][$structurePath] = $resultsFromDatabase;
                }
                // Soft References:
-               if ((is_array($dataValue) || (string)$dataValue !== '') && $softRefs = BackendUtility::explodeSoftRefParserList($dsConf['softref'])) {
+               if (is_array($dataValue) || (string)$dataValue !== '') {
                        $softRefValue = $dataValue;
-                       foreach ($softRefs as $spKey => $spParams) {
-                               $softRefObj = BackendUtility::softRefParserObj($spKey);
-                               if (is_object($softRefObj)) {
-                                       $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
-                                       if (is_array($resultArray) && is_array($resultArray['elements'])) {
-                                               $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements'];
-                                               if ((string)$resultArray['content'] !== '') {
-                                                       $softRefValue = $resultArray['content'];
+                       $softRefs = BackendUtility::explodeSoftRefParserList($dsConf['softref']);
+                       if ($softRefs !== FALSE) {
+                               foreach ($softRefs as $spKey => $spParams) {
+                                       $softRefObj = BackendUtility::softRefParserObj($spKey);
+                                       if (is_object($softRefObj)) {
+                                               $resultArray = $softRefObj->findRef($table, $field, $uid, $softRefValue, $spKey, $spParams, $structurePath);
+                                               if (is_array($resultArray) && is_array($resultArray['elements'])) {
+                                                       $this->temp_flexRelations['softrefs'][$structurePath]['keys'][$spKey] = $resultArray['elements'];
+                                                       if ((string)$resultArray['content'] !== '') {
+                                                               $softRefValue = $resultArray['content'];
+                                                       }
                                                }
                                        }
                                }
                        }
-                       if (count($this->temp_flexRelations['softrefs']) && (string)$dataValue !== (string)$softRefValue) {
+                       if (!empty($this->temp_flexRelations['softrefs']) && (string)$dataValue !== (string)$softRefValue) {
                                $this->temp_flexRelations['softrefs'][$structurePath]['tokenizedContent'] = $softRefValue;
                        }
                }
index b9d0b5b..6068013 100644 (file)
@@ -29,6 +29,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  * Soft References:
  * if ($conf['softref'] && (strong)$value !== ''))     {       // Check if a TCA configured field has softreferences defined (see TYPO3 Core API document)
  * $softRefs = \TYPO3\CMS\Backend\Utility\BackendUtility::explodeSoftRefParserList($conf['softref']);          // Explode the list of softreferences/parameters
+ * if ($softRefs !== FALSE) { // If there are soft references
  * foreach($softRefs as $spKey => $spParams)   {       // Traverse soft references
  * $softRefObj = &\TYPO3\CMS\Backend\Utility\BackendUtility::softRefParserObj($spKey); // create / get object
  * if (is_object($softRefObj)) {       // If there was an object returned...:
index 31d2e28..8362f79 100644 (file)
@@ -241,19 +241,21 @@ class LinkAnalyzer {
                        if ($conf['softref'] && (string)$valueField !== '') {
                                // Explode the list of soft references/parameters
                                $softRefs = BackendUtility::explodeSoftRefParserList($conf['softref']);
-                               // Traverse soft references
-                               foreach ($softRefs as $spKey => $spParams) {
-                                       /** @var $softRefObj \TYPO3\CMS\Core\Database\SoftReferenceIndex */
-                                       $softRefObj = BackendUtility::softRefParserObj($spKey);
-                                       // If there is an object returned...
-                                       if (is_object($softRefObj)) {
-                                               // Do processing
-                                               $resultArray = $softRefObj->findRef($table, $field, $idRecord, $valueField, $spKey, $spParams);
-                                               if (!empty($resultArray['elements'])) {
-                                                       if ($spKey == 'typolink_tag') {
-                                                               $this->analyseTypoLinks($resultArray, $results, $htmlParser, $record, $field, $table);
-                                                       } else {
-                                                               $this->analyseLinks($resultArray, $results, $record, $field, $table);
+                               if ($softRefs !== FALSE) {
+                                       // Traverse soft references
+                                       foreach ($softRefs as $spKey => $spParams) {
+                                               /** @var $softRefObj \TYPO3\CMS\Core\Database\SoftReferenceIndex */
+                                               $softRefObj = BackendUtility::softRefParserObj($spKey);
+                                               // If there is an object returned...
+                                               if (is_object($softRefObj)) {
+                                                       // Do processing
+                                                       $resultArray = $softRefObj->findRef($table, $field, $idRecord, $valueField, $spKey, $spParams);
+                                                       if (!empty($resultArray['elements'])) {
+                                                               if ($spKey == 'typolink_tag') {
+                                                                       $this->analyseTypoLinks($resultArray, $results, $htmlParser, $record, $field, $table);
+                                                               } else {
+                                                                       $this->analyseLinks($resultArray, $results, $record, $field, $table);
+                                                               }
                                                        }
                                                }
                                        }