[TASK] Speedup typolink root-line handling 23/26823/2
authorSteffen Ritter <info@rs-websystems.de>
Mon, 13 Jan 2014 18:06:53 +0000 (19:06 +0100)
committerHelmut Hummel <helmut.hummel@typo3.org>
Tue, 14 Jan 2014 17:50:12 +0000 (18:50 +0100)
The link generation via typolink needs the domain record as well
as the rootline to generate the links correctly. To save
superfluous database queries some local caches are introduced.

Furthermore the rootline cache does not use all information which
is present after the database query. This information is unpacked
here, too. As a result less requests to the CacheFrontend need to
be done.

Resolves: #54959
Releases: 6.2, 6.1
Change-Id: Iea7fff4c6c624a03b75523a7352b5f9736f2d57e
Reviewed-on: https://review.typo3.org/26823
Reviewed-by: Helmut Hummel
Tested-by: Helmut Hummel
typo3/sysext/core/Classes/Utility/RootlineUtility.php
typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php

index f191ef8..605e173 100644 (file)
@@ -109,6 +109,11 @@ class RootlineUtility {
        protected $pageContext;
 
        /**
+        * @var string
+        */
+       protected $cacheIdentifier;
+
+       /**
         * @var array
         */
        static protected $pageRecordCache = array();
@@ -162,6 +167,8 @@ class RootlineUtility {
                self::$rootlineFields = array_merge(self::$rootlineFields, \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields'], TRUE));
                self::$rootlineFields = array_unique(self::$rootlineFields);
                $this->databaseConnection = $GLOBALS['TYPO3_DB'];
+
+               $this->cacheIdentifier = $this->getCacheIdentifier();
        }
 
        /**
@@ -186,16 +193,31 @@ class RootlineUtility {
         * @return array
         */
        public function get() {
-               $cacheIdentifier = $this->getCacheIdentifier();
-               if (!isset(self::$localCache[$cacheIdentifier])) {
-                       $entry = self::$cache->get($cacheIdentifier);
+               if (!isset(static::$localCache[$this->cacheIdentifier])) {
+                       $entry = static::$cache->get($this->cacheIdentifier);
                        if (!$entry) {
                                $this->generateRootlineCache();
                        } else {
-                               self::$localCache[$cacheIdentifier] = $entry;
+                               static::$localCache[$this->cacheIdentifier] = $entry;
+                               $depth = count($entry);
+                               // Populate the root-lines for parent pages as well
+                               // since they are part of the current root-line
+                               while ($depth > 1) {
+                                       --$depth;
+                                       $parentCacheIdentifier = $this->getCacheIdentifier($entry[$depth - 1]['uid']);
+                                       // Abort if the root-line of the parent page is
+                                       // already in the local cache data
+                                       if (isset(static::$localCache[$parentCacheIdentifier])) {
+                                               break;
+                                       }
+                                       // Behaves similar to array_shift(), but preserves
+                                       // the array keys - which contain the page ids here
+                                       $entry = array_slice($entry, 1, NULL, TRUE);
+                                       static::$localCache[$parentCacheIdentifier] = $entry;
+                               }
                        }
                }
-               return self::$localCache[$cacheIdentifier];
+               return static::$localCache[$this->cacheIdentifier];
        }
 
        /**
@@ -206,7 +228,8 @@ class RootlineUtility {
         * @return array
         */
        protected function getRecordArray($uid) {
-               if (!isset(self::$pageRecordCache[$this->getCacheIdentifier($uid)])) {
+               $currentCacheIdentifier = $this->getCacheIdentifier($uid);
+               if (!isset(self::$pageRecordCache[$currentCacheIdentifier])) {
                        $row = $this->databaseConnection->exec_SELECTgetSingleRow(implode(',', self::$rootlineFields), 'pages', 'uid = ' . intval($uid) . ' AND pages.deleted = 0 AND pages.doktype <> ' . \TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_RECYCLER);
                        if (empty($row)) {
                                throw new \RuntimeException('Could not fetch page data for uid ' . $uid . '.', 1343589451);
@@ -218,13 +241,13 @@ class RootlineUtility {
                                        $row = $this->pageContext->getPageOverlay($row, $this->languageUid);
                                }
                                $row = $this->enrichWithRelationFields(isset($row['_PAGES_OVERLAY_UID']) ? $row['_PAGES_OVERLAY_UID'] : $uid, $row);
-                               self::$pageRecordCache[$this->getCacheIdentifier($uid)] = $row;
+                               self::$pageRecordCache[$currentCacheIdentifier] = $row;
                        }
                }
-               if (!is_array(self::$pageRecordCache[$this->getCacheIdentifier($uid)])) {
+               if (!is_array(self::$pageRecordCache[$currentCacheIdentifier])) {
                        throw new \RuntimeException('Broken rootline. Could not resolve page with uid ' . $uid . '.', 1343464101);
                }
-               return self::$pageRecordCache[$this->getCacheIdentifier($uid)];
+               return self::$pageRecordCache[$currentCacheIdentifier];
        }
 
        /**
@@ -334,8 +357,8 @@ class RootlineUtility {
                }
                array_push($rootline, $page);
                krsort($rootline);
-               self::$cache->set($this->getCacheIdentifier(), $rootline, $cacheTags);
-               self::$localCache[$this->getCacheIdentifier()] = $rootline;
+               static::$cache->set($this->cacheIdentifier, $rootline, $cacheTags);
+               static::$localCache[$this->cacheIdentifier] = $rootline;
        }
 
        /**
@@ -395,4 +418,4 @@ class RootlineUtility {
 }
 
 
-?>
\ No newline at end of file
+?>
index a08910a..0948c9e 100644 (file)
@@ -748,6 +748,13 @@ class TypoScriptFrontendController {
        protected $cacheHash;
 
        /**
+        * Runtime cache of domains per processed page ids.
+        *
+        * @var array
+        */
+       protected $domainDataCache = array();
+
+       /**
         * Class constructor
         * Takes a number of GET/POST input variable as arguments and stores them internally.
         * The processing of these variables goes on later in this class.
@@ -4886,19 +4893,25 @@ if (version == "n3") {
         * @return mixed Return domain data or NULL
        */
        public function getDomainDataForPid($targetPid) {
-               $result = NULL;
-
-               $sysDomainData = $this->getSysDomainCache();
-               $rootline = $this->sys_page->getRootLine($targetPid);
-               // walk the rootline downwards from the target page to the root, until a domain record is found
-               foreach ($rootline as $pageInRootline) {
-                       $pidInRootline = $pageInRootline['uid'];
-                       if (isset($sysDomainData[$pidInRootline])) {
-                               $result = $sysDomainData[$pidInRootline];
-                               break;
+               // Using array_key_exists() here, nice $result can be NULL
+               // (happens, if there's no domain records defined)
+               if (!array_key_exists($targetPid, $this->domainDataCache)) {
+                       $result = NULL;
+                       $sysDomainData = $this->getSysDomainCache();
+                       $rootline = $this->sys_page->getRootLine($targetPid);
+                       // walk the rootline downwards from the target page
+                       // to the root page, until a domain record is found
+                       foreach ($rootline as $pageInRootline) {
+                               $pidInRootline = $pageInRootline['uid'];
+                               if (isset($sysDomainData[$pidInRootline])) {
+                                       $result = $sysDomainData[$pidInRootline];
+                                       break;
+                               }
                        }
+                       $this->domainDataCache[$targetPid] = $result;
                }
-               return $result;
+
+               return $this->domainDataCache[$targetPid];
        }
 
        /**