[TASK] Refactor t3lib_pageSelect::getRootline
authorSteffen Ritter <info@rs-websystems.de>
Sat, 28 Jul 2012 19:43:09 +0000 (21:43 +0200)
committerSteffen Gebert <steffen.gebert@typo3.org>
Sun, 19 Aug 2012 18:58:43 +0000 (20:58 +0200)
t3lib_pageSelect::getRootline is a function called many
times during frontend rendering and link generation.
The complete levelfield logic (incl. levelmedia) is based
on the result of this function.

The function itself has very fuzzy code, hard to read
conditions an in its current implementation a n² complexity.
Furthermore the current structure allows only very basic
caching, which does not fulfill todays needs.

The refactoring moves the "Rootline" to its own class and
splits the logic in many small chunks and helper functions.
Additionally the get(), and generateRootline() use the
CachingFramework to Cache the rootline.
Ancient "Failure Messages" in Rootline have been migrated
to useful RuntimeExceptions.
In addition as a new feature/bugfix levelfields resolve
relations so that levelmedia works with FAL again.

Change-Id: Ief215400c6552480603038966207fa29a26fe5b1
Releases: 6.0
Resolves: #39352
Reviewed-on: http://review.typo3.org/13322
Reviewed-by: Philipp Gampe
Tested-by: Philipp Gampe
Tested-by: Marcel Burkhalter
Reviewed-by: Steffen Gebert
Tested-by: Steffen Gebert
t3lib/class.t3lib_page.php
t3lib/class.t3lib_rootline.php [new file with mode: 0644]
t3lib/class.t3lib_tcemain.php
t3lib/core_autoload.php
t3lib/stddb/DefaultConfiguration.php
tests/Unit/t3lib/class.t3lib_rootlineTest.php [new file with mode: 0644]
tests/Unit/t3lib/fixtures/AccessibleRootline.php [new file with mode: 0644]

index 333ed21..1450327 100644 (file)
@@ -579,133 +579,20 @@ class t3lib_pageSelect {
         * @see tslib_fe::getPageAndRootline()
         */
        function getRootLine($uid, $MP = '', $ignoreMPerrors = FALSE) {
-               $cacheUid = $uid = intval($uid);
-               $cacheIgnoreMPerrors = ($ignoreMPerrors ? 1 : 0);
-
-               if (is_array($this->cache_getRootLine[$cacheUid][$this->sys_language_uid][$MP][$cacheIgnoreMPerrors])) {
-                       return $this->cache_getRootLine[$cacheUid][$this->sys_language_uid][$MP][$cacheIgnoreMPerrors];
-               }
-
-                       // Initialize:
-               $selFields = t3lib_div::uniqueList('pid,uid,t3ver_oid,t3ver_wsid,t3ver_state,title,alias,nav_title,media,layout,hidden,starttime,endtime,fe_group,extendToSubpages,doktype,TSconfig,storage_pid,is_siteroot,mount_pid,mount_pid_ol,fe_login_mode,backend_layout_next_level,' . $GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields']);
-               $this->error_getRootLine = '';
-               $this->error_getRootLine_failPid = 0;
-
-                       // Splitting the $MP parameters if present
-               $MPA = array();
-               if ($MP) {
-                       $MPA = explode(',', $MP);
-                       foreach ($MPA as $MPAk => $v) {
-                               $MPA[$MPAk] = explode('-', $MPA[$MPAk]);
-                       }
-               }
-
-               $loopCheck = 0;
-               $theRowArray = array();
-
-                       // Max 99 levels in the page tree.
-               while ($uid != 0 && $loopCheck < 99) {
-                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid=' . intval($uid) . ' AND pages.deleted=0 AND pages.doktype<>255');
-                       $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-                       $GLOBALS['TYPO3_DB']->sql_free_result($res);
-                       if ($row) {
-                               $this->versionOL('pages', $row, FALSE, TRUE);
-                               $this->fixVersioningPid('pages', $row);
-
-                               if (is_array($row)) {
-                                               // Mount Point page types are allowed ONLY a) if they are the outermost record in rootline and b) if the overlay flag is not set:
-                                       if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] && $row['doktype'] == self::DOKTYPE_MOUNTPOINT && !$ignoreMPerrors) {
-                                               $mount_info = $this->getMountPointInfo($row['uid'], $row);
-                                               if ($loopCheck > 0 || $mount_info['overlay']) {
-                                                       $this->error_getRootLine = 'Illegal Mount Point found in rootline';
-                                                       return array();
-                                               }
-                                       }
-
-                                               // Next uid
-                                       $uid = $row['pid'];
-
-                                       if (count($MPA) && $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
-                                               $curMP = end($MPA);
-                                               if (!strcmp($row['uid'], $curMP[0])) {
-
-                                                       array_pop($MPA);
-                                                       $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($selFields, 'pages', 'uid=' . intval($curMP[1]) . ' AND pages.deleted=0 AND pages.doktype<>255');
-                                                       $mp_row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
-                                                       $GLOBALS['TYPO3_DB']->sql_free_result($res);
-
-                                                       $this->versionOL('pages', $mp_row, FALSE, TRUE);
-                                                       $this->fixVersioningPid('pages', $mp_row);
-
-                                                       if (is_array($mp_row)) {
-                                                               $mount_info = $this->getMountPointInfo($mp_row['uid'], $mp_row);
-                                                               if (is_array($mount_info) && $mount_info['mount_pid'] == $curMP[0]) {
-                                                                               // Setting next uid
-                                                                       $uid = $mp_row['pid'];
-
-                                                                               // Symlink style: Keep mount point (current row).
-                                                                       if ($mount_info['overlay']) {
-                                                                                       // Set overlay mode:
-                                                                               $row['_MOUNT_OL'] = TRUE;
-                                                                               $row['_MOUNT_PAGE'] = array(
-                                                                                       'uid' => $mp_row['uid'],
-                                                                                       'pid' => $mp_row['pid'],
-                                                                                       'title' => $mp_row['title'],
-                                                                               );
-                                                                       } else { // Normal operation: Insert the mount page row in rootline instead mount point.
-                                                                               if ($loopCheck > 0) {
-                                                                                       $row = $mp_row;
-                                                                               } else {
-                                                                                       $this->error_getRootLine = 'Current Page Id is a mounted page of the overlay type and cannot be accessed directly!';
-                                                                                               // Matching the page id (first run, $loopCheck = 0) with the MPvar is ONLY allowed if the mount point is the "overlay" type (otherwise it could be forged!)
-                                                                                       return array();
-                                                                               }
-                                                                       }
-
-                                                                       $row['_MOUNTED_FROM'] = $curMP[0];
-                                                                       $row['_MP_PARAM'] = $mount_info['MPvar'];
-                                                               } else {
-                                                                       $this->error_getRootLine = 'MP var was corrupted';
-                                                                               // The MP variables did NOT connect proper mount points:
-                                                                       return array();
-                                                               }
-                                                       } else {
-                                                               $this->error_getRootLine = 'No moint point record found according to PID in MP var';
-                                                                       // The second PID in MP var was NOT a valid page.
-                                                               return array();
-                                                       }
-                                               }
-                                       }
+               $rootline = t3lib_div::makeInstance('t3lib_rootline', $uid, $MP, $this);
+               if ($ignoreMPerrors) {
+                       try {
+                               return $rootline->get();
+                       } catch (Exception $e) {
+                               $this->error_getRootLine = $e->getMessage();
+                               if (substr($e->getMessage(), -7) == 'uid -1.') {
+                                       $this->error_getRootLine_failPid = -1;
                                }
-                                       // Add row to rootline with language overlaid:
-                               $theRowArray[] = $this->getPageOverlay($row);
-                       } else {
-                               $this->error_getRootLine = 'Broken rootline (failed on page with uid ' . $uid . ')';
-                               $this->error_getRootLine_failPid = $uid;
-                                       // Broken rootline.
                                return array();
                        }
-
-                       $loopCheck++;
-               }
-
-                       // If the MPA array is NOT empty, we have to return an error; All MP elements were not resolved!
-               if (count($MPA)) {
-                       $this->error_getRootLine = 'MP value remain!';
-                       return array();
-               }
-
-                       // Create output array (with reversed order of numeric keys):
-               $output = Array();
-               $c = count($theRowArray);
-               foreach ($theRowArray as $key => $val) {
-                       $c--;
-                       $output[$c] = $val;
+               } else {
+                       return $rootline->get();
                }
-
-                       // Note: rootline errors are not cached
-               $this->cache_getRootLine[$cacheUid][$this->sys_language_uid][$MP][$cacheIgnoreMPerrors] = $output;
-               return $output;
        }
 
        /**
diff --git a/t3lib/class.t3lib_rootline.php b/t3lib/class.t3lib_rootline.php
new file mode 100644 (file)
index 0000000..962bc30
--- /dev/null
@@ -0,0 +1,432 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Steffen Ritter <steffen.ritter@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * A utility resolving and Caching the Rootline generation
+ *
+ * @author Steffen Ritter <steffen.ritter@typo3.org>
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_rootline {
+
+       /**
+        * @var integer
+        */
+       protected $pageUid;
+
+       /**
+        * @var string
+        */
+       protected $mountPointParameter;
+
+       /**
+        * @var array
+        */
+       protected $parsedMountPointParameters = array();
+
+       /**
+        * @var integer
+        */
+       protected $languageUid = 0;
+
+       /**
+        * @var integer
+        */
+       protected $workspaceUid = 0;
+
+       /**
+        * @var boolean
+        */
+       protected $versionPreview = FALSE;
+
+       /**
+        * @var t3lib_cache_frontend_Frontend
+        */
+       protected static $cache = NULL;
+
+       /**
+        * @var array
+        */
+       protected static $localCache = array();
+
+       /**
+        * Fields to fetch when populating rootline data
+        *
+        * @var array
+        */
+       protected static $rootlineFields = array(
+               'pid',
+               'uid',
+               't3ver_oid',
+               't3ver_wsid',
+               't3ver_state',
+               'title',
+               'alias',
+               'nav_title',
+               'media',
+               'layout',
+               'hidden',
+               'starttime',
+               'endtime',
+               'fe_group',
+               'extendToSubpages',
+               'doktype',
+               'TSconfig',
+               'storage_pid',
+               'is_siteroot',
+               'mount_pid',
+               'mount_pid_ol',
+               'fe_login_mode',
+               'backend_layout_next_level'
+       );
+
+       /**
+        * Rootline Context
+        *
+        * @var t3lib_pageSelect
+        */
+       protected $pageContext;
+
+       /**
+        * @var array
+        */
+       protected static $pageRecordCache = array();
+
+       /**
+        * @param int $uid
+        * @param string $mountPointParameter
+        * @param t3lib_pageSelect $context
+        * @throws RuntimeException
+        */
+       public function __construct($uid, $mountPointParameter = '', t3lib_pageSelect $context = NULL) {
+               $this->pageUid = intval($uid);
+               $this->mountPointParameter = trim($mountPointParameter);
+
+               if ($context === NULL) {
+                       if ($GLOBALS['TSFE']->sys_page !== NULL) {
+                               $this->pageContext = $GLOBALS['TSFE']->sys_page;
+                       } else {
+                               $this->pageContext = t3lib_div::makeInstance('t3lib_pageSelect');
+                       }
+               } else {
+                       $this->pageContext = $context;
+               }
+               $this->initializeObject();
+       }
+
+       /**
+        * Initialize a state to work with
+        *
+        * @throws RuntimeException
+        * @return void
+        */
+       protected function initializeObject() {
+
+               $this->languageUid = intval($this->pageContext->sys_language_uid);
+               $this->workspaceUid = intval($this->pageContext->versioningWorkspaceId);
+               $this->versionPreview = $this->pageContext->versioningPreview;
+
+               if ($this->mountPointParameter !== '') {
+                       if (!$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
+                               throw new RuntimeException('Mount-Point Pages are disabled for this installation. Cannot resolve a Rootline for a page with Mount-Points', 1343462896);
+                       } else {
+                               $this->parseMountPointParameter();
+                       }
+               }
+
+               if (self::$cache === NULL) {
+                       self::$cache = $GLOBALS['typo3CacheManager']->getCache('cache_rootline');
+               }
+
+               self::$rootlineFields = array_merge(
+                       self::$rootlineFields,
+                       t3lib_div::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['addRootLineFields'], TRUE)
+               );
+               array_unique(self::$rootlineFields);
+       }
+
+       /**
+        * Constructs the cache Identifier
+        *
+        * @param integer $otherUid
+        * @return string
+        */
+       public function getCacheIdentifier($otherUid = NULL) {
+               return implode('_', array(
+                       $otherUid !== NULL ? intval($otherUid) : $this->pageUid,
+                       $this->mountPointParameter,
+                       $this->languageUid,
+                       $this->workspaceUid,
+                       $this->versionPreview ? 1 : 0
+               ));
+       }
+
+       /**
+        * Returns the actual rootline
+        * @return array
+        */
+       public function get() {
+               $cacheIdentifier = $this->getCacheIdentifier();
+               if (!isset(self::$localCache[$cacheIdentifier])) {
+                       if (!self::$cache->has($cacheIdentifier)) {
+                               $this->generateRootlineCache();
+                       } else {
+                               self::$localCache[$cacheIdentifier] = self::$cache->get($cacheIdentifier);
+                       }
+               }
+               return self::$localCache[$cacheIdentifier];
+       }
+
+       /**
+        * Queries the database for the page record and returns it.
+        *
+        * @param integer $uid Page id
+        * @throws RuntimeException
+        * @return array
+        */
+       protected function getRecordArray($uid) {
+               if (!isset(self::$pageRecordCache[$this->getCacheIdentifier($uid)])) {
+
+                       if (!is_array($GLOBALS['TCA']['pages']['columns'])) {
+                               if (isset($GLOBALS['TSFE'])) {
+                                       $GLOBALS['TSFE']->includeTCA($GLOBALS['TSFE']->TCAloaded);
+                               }
+                               t3lib_div::loadTCA('pages');
+                       }
+
+                       $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
+                               implode(',', self::$rootlineFields),
+                               'pages',
+                               'uid = ' . intval($uid) . ' AND pages.deleted = 0 AND pages.doktype <> ' . t3lib_pageSelect::DOKTYPE_RECYCLER
+                       );
+
+                       if (empty($row)) {
+                               throw new RuntimeException('Could not fetch page data for uid ' . $uid . '.', 1343589451);
+                       }
+
+                       $this->pageContext->versionOL('pages', $row, FALSE, TRUE);
+                       $this->pageContext->fixVersioningPid('pages', $row);
+
+                       if (is_array($row)) {
+                               $row = $this->enrichWithRelationFields($uid, $row);
+                               $this->pageContext->getPageOverlay($row, $this->languageUid);
+                               self::$pageRecordCache[$this->getCacheIdentifier($uid)] = $row;
+                       }
+               }
+
+               if (!is_array(self::$pageRecordCache[$this->getCacheIdentifier($uid)])) {
+                       throw new RuntimeException('Broken rootline. Could not resolve page with uid ' . $uid . '.', 1343464101);
+               }
+
+               return self::$pageRecordCache[$this->getCacheIdentifier($uid)];
+       }
+
+       /**
+        * Resolve relations as defined in TCA and add them to the provided $pageRecord array.
+        *
+        * @param integer $uid Page id
+        * @param array $pageRecord Array with page data to add relation data to.
+        * @throws RuntimeException
+        * @return array $pageRecord with additional relations
+        */
+       protected function enrichWithRelationFields($uid, array $pageRecord) {
+               foreach ($GLOBALS['TCA']['pages']['columns'] as $column => $configuration) {
+                       if ($this->columnHasRelationToResolve($configuration)) {
+                               $configuration = $configuration['config'];
+                               if ($configuration['MM']) {
+                                       /** @var $loadDBGroup t3lib_loadDBGroup */
+                                       $loadDBGroup = t3lib_div::makeInstance('t3lib_loadDBGroup');
+                                       $loadDBGroup->start(
+                                               $pageRecord[$column],
+                                               $configuration['foreign_table'],
+                                               $configuration['MM'],
+                                               $uid,
+                                               'pages',
+                                               $configuration
+                                       );
+                                       $relatedUids = $loadDBGroup->tableArray[$configuration['foreign_table']];
+                               } elseif ($configuration['foreign_field']) {
+                                       $table = $configuration['foreign_table'];
+                                       $field = $configuration['foreign_field'];
+                                       $whereClauseParts = array('`' . $field . '` = ' . intval($uid));
+                                       if (isset($configuration['foreign_match_fields']) && is_array($configuration['foreign_match_fields'])) {
+                                               foreach ($configuration['foreign_match_fields'] as $field => $value) {
+                                                       $whereClauseParts[] = '`' . $field . '` = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr($value);
+                                               }
+
+                                       }
+                                       if (isset($configuration['foreign_table_field'])) {
+                                               $whereClauseParts[] = '`' . trim($configuration['foreign_table_field']) . '` = \'pages\'';
+                                       }
+                                       $whereClause = implode(' AND ', $whereClauseParts);
+                                       $rows = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $table, $whereClause);
+                                       if (!is_array($rows)) {
+                                               throw new RuntimeException('Could to resolve related records for page ' . $uid . ' and foreign_table ' . htmlspecialchars($configuration['foreign_table']), 1343589452);
+                                       }
+                                       $relatedUids = array();
+                                       foreach ($rows as $row) {
+                                               $relatedUids[] = $row['uid'];
+                                       }
+                               }
+
+                               $pageRecord[$column] = implode(',', $relatedUids);
+                       }
+               }
+               return $pageRecord;
+       }
+
+       /**
+        * Checks whether the TCA Configuration array of a column
+        * describes a relation which is not stored as CSV in the record
+        *
+        * @param array $configuration TCA configuration to check
+        * @return boolean TRUE, if it describes a non-CSV relation
+        */
+       protected function columnHasRelationToResolve(array $configuration) {
+               $configuration = $configuration['config'];
+               if (isset($configuration['MM']) && isset($configuration['type']) && in_array($configuration['type'], array('select', 'inline', 'group'))) {
+                       return TRUE;
+               }
+               if (isset($configuration['foreign_field']) && isset($configuration['type']) && in_array($configuration['type'], array('select', 'inline'))) {
+                       return TRUE;
+               }
+               return FALSE;
+       }
+
+       /**
+        * Actual function to generate the rootline and cache it
+        *
+        * @throws RuntimeException
+        * @return void
+        */
+       protected function generateRootlineCache() {
+               $page = $this->getRecordArray($this->pageUid);
+
+                       // If the current page is a mounted (according to the MP parameter) handle the mount-point
+               if ($this->isMountedPage()) {
+                       $mountPoint = $this->getRecordArray($this->parsedMountPointParameters[$this->pageUid]);
+
+                       $page = $this->processMountedPage($page, $mountPoint);
+                       $parentUid = $mountPoint['pid'];
+                               // Anyhow after reaching the mount-point, we have to go up that rootline
+                       unset($this->parsedMountPointParameters[$this->pageUid]);
+               } else {
+                       $parentUid = $page['pid'];
+               }
+
+               $cacheTags = array('pageId_' . $page['uid']);
+
+               if ($parentUid > 0) {
+                               // Get rootline of (and including) parent page
+                       $mountPointParameter = count($this->parsedMountPointParameters) > 0 ? $this->mountPointParameter : '';
+                       /** @var $rootline t3lib_rootline */
+                       $rootline = t3lib_div::makeInstance('t3lib_rootline', $parentUid, $mountPointParameter, $this->pageContext);
+                       $rootline = $rootline->get();
+
+                               // retrieve cache tags of parent rootline
+                       foreach ($rootline as $entry) {
+                               $cacheTags[] = 'pageId_' . $entry['uid'];
+                               if ($entry['uid'] == $this->pageUid) {
+                                       throw new RuntimeException('Circular connection in rootline for page with uid ' . $this->pageUid . ' found. Check your mountpoint configuration.', 1343464103);
+                               }
+                       }
+               } else {
+                       $rootline = array();
+               }
+
+               array_push($rootline, $page);
+
+               krsort($rootline);
+               self::$cache->set(
+                       $this->getCacheIdentifier(),
+                       $rootline,
+                       $cacheTags
+               );
+               self::$localCache[$this->getCacheIdentifier()] = $rootline;
+       }
+
+       /**
+        * Checks whether the current Page is a Mounted Page
+        * (according to the MP-URL-Parameter)
+        *
+        * @return boolean
+        */
+       protected function isMountedPage() {
+               return in_array($this->pageUid, array_keys($this->parsedMountPointParameters));
+       }
+
+       /**
+        * Enhances with mount point information or replaces the node if needed
+        *
+        * @param array $mountedPageData page record array of mounted page
+        * @param array $mountPointPageData page record array of mount point page
+        * @throws RuntimeException
+        * @return array
+        */
+       protected function processMountedPage(array $mountedPageData, array $mountPointPageData) {
+               if ($mountPointPageData['mount_pid'] != $mountedPageData['uid']) {
+                       throw new RuntimeException(
+                               'Broken rootline. Mountpoint parameter does not match the actual rootline. mount_pid (' . $mountPointPageData['mount_pid'] . ') does not match page uid (' . $mountedPageData['uid'] . ').',
+                               1343464100);
+               }
+
+                       // Current page replaces the original mount-page
+               if ($mountPointPageData['mount_pid_ol']) {
+                       $mountedPageData['_MOUNT_OL'] = TRUE;
+                       $mountedPageData['_MOUNT_PAGE'] = array(
+                               'uid' => $mountPointPageData['uid'],
+                               'pid' => $mountPointPageData['pid'],
+                               'title' => $mountPointPageData['title']
+                       );
+               } else {
+                               // The mount-page is not replaced, the mount-page itself has to be used
+                       $mountedPageData = $mountPointPageData;
+               }
+
+               $mountedPageData['_MOUNTED_FROM'] = $this->pageUid;
+               $mountedPageData['_MP_PARAM'] = $this->pageUid . '-' . $mountPointPageData['uid'];
+               return $mountedPageData;
+       }
+
+       /**
+        * Parse the MountPoint Parameters
+        * Splits the MP-Param via "," for several nested mountpoints
+        * and afterwords registers the mountpoint configurations
+        *
+        * @return void
+        */
+       protected function parseMountPointParameter() {
+               $mountPoints = t3lib_div::trimExplode(',', $this->mountPointParameter);
+
+               foreach ($mountPoints as $mP) {
+                       list($mountedPageUid, $mountPageUid) = t3lib_div::intExplode('-', $mP);
+                       $this->parsedMountPointParameters[$mountedPageUid] = $mountPageUid;
+               }
+       }
+
+}
+
+?>
\ No newline at end of file
index f3c62fc..184b82e 100644 (file)
@@ -6893,12 +6893,9 @@ class t3lib_TCEmain {
 
                                                // Delete cache for selected pages:
                                        if (is_array($list_cache)) {
-                                               $pageCache = $GLOBALS['typo3CacheManager']->getCache('cache_pages');
-                                               $pageSectionCache = $GLOBALS['typo3CacheManager']->getCache('cache_pagesection');
                                                $pageIds = $GLOBALS['TYPO3_DB']->cleanIntArray($list_cache);
                                                foreach ($pageIds as $pageId) {
-                                                       $pageCache->flushByTag('pageId_' . $pageId);
-                                                       $pageSectionCache->flushByTag('pageId_' . $pageId);
+                                                       $GLOBALS['typo3CacheManager']->flushCachesByTag('pageId_' . $pageId);
                                                }
                                        }
                                }
index c1b32a2..e86a097 100644 (file)
@@ -236,6 +236,7 @@ $t3libClasses = array(
        't3lib_recordlist' => PATH_t3lib . 'class.t3lib_recordlist.php',
        't3lib_refindex' => PATH_t3lib . 'class.t3lib_refindex.php',
        't3lib_registry' => PATH_t3lib . 'class.t3lib_registry.php',
+       't3lib_rootline' => PATH_t3lib . 'class.t3lib_rootline.php',
        't3lib_rteapi' => PATH_t3lib . 'class.t3lib_rteapi.php',
        't3lib_scbase' => PATH_t3lib . 'class.t3lib_scbase.php',
        't3lib_search_livesearch' => PATH_t3lib . 'search/class.t3lib_search_livesearch.php',
@@ -380,4 +381,4 @@ $typo3Classes = array(
 $tslibClasses = require(PATH_typo3 . 'sysext/cms/ext_autoload.php');
 
 return array_merge($t3libClasses, $typo3Classes, $tslibClasses);
-?>
\ No newline at end of file
+?>
index dc75471..949fb2e 100644 (file)
@@ -167,6 +167,11 @@ return array(
                                        'backend' => 't3lib_cache_backend_TransientMemoryBackend',
                                        'options' => array(),
                                ),
+                               'cache_rootline' => array(
+                                       'frontend' => 't3lib_cache_frontend_VariableFrontend',
+                                       'backend' => 't3lib_cache_backend_DbBackend',
+                                       'options' => array(),
+                               )
                        ),
                ),
                'displayErrors' => -1,                                  // <p>Integer (-1, 0, 1, 2). Configures whether PHP errors should be displayed.</p><dl><dt>0</dt><dd>Do not display any PHP error messages. Overrides the value of "exceptionalErrors" and sets it to 0 (= no errors are turned into exceptions), the configured "productionExceptionHandler" is used as exception handler</dd><dt>1</dt><dd>Display error messages with the registered errorhandler. The configured "debugExceptionHandler" is used as exception handler</dd><dt>2</dt><dd>Display errors only if client matches <a href="#SYS-devIPmask">[SYS][devIPmask]</a>. If devIPmask matches the users IP address  the configured "debugExceptionHandler" is used  for exceptions, if not "productionExceptionHandler" will be used</dd><dt>-1</dt><dd>Default setting. With this option, you can override the PHP setting "display_errors". If devIPmask matches the users IP address  the configured "debugExceptionHandler" is used  for exceptions, if not "productionExceptionHandler" will be used.</dd></dl>
diff --git a/tests/Unit/t3lib/class.t3lib_rootlineTest.php b/tests/Unit/t3lib/class.t3lib_rootlineTest.php
new file mode 100644 (file)
index 0000000..0fe3028
--- /dev/null
@@ -0,0 +1,305 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Steffen Ritter <steffen.ritter@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+require_once(__DIR__ . '/fixtures/AccessibleRootline.php');
+/**
+ * Testcase for class t3lib_rootline
+ *
+ * @author Steffen Ritter <steffen.ritter@typo3.org>
+ *
+ * @package TYPO3
+ * @subpackage t3lib
+ */
+class t3lib_rootlineTest extends tx_phpunit_testcase {
+
+       /***
+        *
+        *              UTILITY FUNCTIONS
+        *
+        */
+
+
+       /**
+        * Tests that $subsetCandidate is completely part of $superset
+        * and keys match.
+        *
+        * @see (A ^ B) = A <=> A c B
+        *
+        * @param array $subsetCandidate
+        * @param array $superset
+        */
+       protected function assertIsSubset(array $subsetCandidate, array $superset) {
+               $this->assertSame(
+                       $subsetCandidate,
+                       array_intersect_assoc($subsetCandidate, $superset)
+               );
+       }
+
+
+
+
+       /***
+        *
+        *              >TEST CASES
+        *
+        */
+
+       /**
+        * @test
+        */
+       public function isMountedPageWithoutMountPointsReturnsFalse() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+
+               $this->assertFalse(
+                       $fixture->isMountedPage()
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function isMountedPageWithMatchingMountPointParameterReturnsTrue() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+
+               $this->assertTrue(
+                       $fixture->isMountedPage()
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function isMountedPageWithNonMatchingMountPointParameterReturnsFalse() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '99-99');
+
+               $this->assertFalse(
+                       $fixture->isMountedPage()
+               );
+       }
+
+       /**
+        * @test
+        * @expectedException RuntimeException
+        */
+       public function processMountedPageWithNonMountedPageThrowsException() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $fixture->processMountedPage(
+                       array('uid' => 1),
+                       array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_DEFAULT)
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function processMountedPageWithMountedPageNotThrowsException() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $fixture->processMountedPage(
+                       array('uid' => 1),
+                       array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1)
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function processMountedPageWithMountedPageAddsMountedFromParameter() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $result = $fixture->processMountedPage(
+                       array('uid' => 1),
+                       array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1)
+               );
+
+               $this->assertTrue(isset($result['_MOUNTED_FROM']));
+               $this->assertSame(1, $result['_MOUNTED_FROM']);
+       }
+
+       /**
+        * @test
+        */
+       public function processMountedPageWithMountedPageAddsMountPointParameterToReturnValue() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $result = $fixture->processMountedPage(
+                       array('uid' => 1),
+                       array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1)
+               );
+
+               $this->assertTrue(isset($result['_MP_PARAM']));
+               $this->assertSame(
+                       '1-99',
+                       $result['_MP_PARAM']
+               );
+       }
+
+
+
+       /**
+        * @test
+        */
+       public function processMountedPageForMountPageIsOverlayAddsMountOLParameter() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $result = $fixture->processMountedPage(
+                       array('uid' => 1),
+                       array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1, 'mount_pid_ol' => 1)
+               );
+
+               $this->assertTrue(isset($result['_MOUNT_OL']));
+               $this->assertSame(TRUE, $result['_MOUNT_OL']);
+       }
+
+       /**
+        * @test
+        */
+       public function processMountedPageForMountPageIsOverlayAddsDataInformationAboutMountPage() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $result = $fixture->processMountedPage(
+                       array('uid' => 1),
+                       array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1, 'mount_pid_ol' => 1, 'pid' => 5, 'title' => 'TestCase')
+               );
+
+               $this->assertTrue(isset($result['_MOUNT_PAGE']));
+               $this->assertSame(
+                       array('uid' => 99, 'pid' => 5, 'title' => 'TestCase'),
+                       $result['_MOUNT_PAGE']
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function processMountedPageForMountPageWithoutOverlayReplacesMountedPageWithMountPage() {
+               $a = array('uid' => 99, 'doktype' => t3lib_pageSelect::DOKTYPE_MOUNTPOINT, 'mount_pid' => 1, 'mount_pid_ol' => 0);
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1, '1-99');
+               $result = $fixture->processMountedPage(
+                       array('uid' => 1),
+                       $a
+               );
+
+               $this->assertIsSubset($a, $result);
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsGroupFieldAsLocal() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertFalse($fixture->columnHasRelationToResolve(array(
+                       'type' => 'group'
+               )));
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsGroupFieldWithMMAsRemote() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertTrue($fixture->columnHasRelationToResolve(array('config' => array(
+                       'type' => 'group',
+                       'MM' => 'tx_xyz'
+               ))));
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsInlineFieldAsLocal() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertFalse($fixture->columnHasRelationToResolve(array('config' => array(
+                       'type' => 'inline'
+               ))));
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsInlineFieldWithForeignKeyAsRemote() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertTrue($fixture->columnHasRelationToResolve(array('config' => array(
+                       'type' => 'inline',
+                       'foreign_field' => 'xyz'
+               ))));
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsInlineFieldWithFMMAsRemote() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertTrue($fixture->columnHasRelationToResolve(array('config' => array(
+                       'type' => 'inline',
+                       'MM' => 'xyz'
+               ))));
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsSelectFieldAsLocal() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertFalse($fixture->columnHasRelationToResolve(array('config' => array(
+                       'type' => 'select'
+               ))));
+       }
+
+       /**
+        * @test
+        */
+       public function columnHasRelationToResolveDetectsSelectFieldWithMMAsRemote() {
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(1);
+               $this->assertTrue($fixture->columnHasRelationToResolve(array('config' => array(
+                       'type' => 'select',
+                       'MM' => 'xyz'
+               ))));
+       }
+
+       /**
+        * @test
+        */
+       public function getCacheIdentifierContainsAllContextParameters() {
+               $pageContext = t3lib_div::makeInstance('t3lib_pageSelect');
+               $pageContext->sys_language_uid = 8;
+               $pageContext->versioningWorkspaceId = 15;
+               $pageContext->versioningPreview = TRUE;
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(42, '47-11', $pageContext);
+               $this->assertSame(
+                       '42_47-11_8_15_1',
+                       $fixture->getCacheIdentifier()
+               );
+
+               $pageContext->versioningPreview = FALSE;
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(42, '47-11', $pageContext);
+               $this->assertSame(
+                       '42_47-11_8_15_0',
+                       $fixture->getCacheIdentifier()
+               );
+
+               $pageContext->versioningWorkspaceId = 0;
+               $fixture = new Tests_unit_t3lib_AccessibleRootline(42, '47-11', $pageContext);
+               $this->assertSame(
+                       '42_47-11_8_0_0',
+                       $fixture->getCacheIdentifier()
+               );
+       }
+
+}
diff --git a/tests/Unit/t3lib/fixtures/AccessibleRootline.php b/tests/Unit/t3lib/fixtures/AccessibleRootline.php
new file mode 100644 (file)
index 0000000..a5b72bb
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2012 Steffen Ritter <steffen.ritter@typo3.org>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Make method public
+ *
+ * @author Steffen Ritter <steffen.ritter@typo3.org>
+ *
+ * @package TYPO3
+ * @subpackage test
+ */
+class Tests_unit_t3lib_AccessibleRootline extends t3lib_rootline {
+
+       public function isMountedPage() {
+               return parent::isMountedPage();
+       }
+
+       public function processMountedPage($mountedPageData, $mountPointPageData) {
+               return parent::processMountedPage($mountedPageData, $mountPointPageData);
+       }
+
+       public function columnHasRelationToResolve($configuration) {
+               return parent::columnHasRelationToResolve($configuration);
+       }
+
+
+}
\ No newline at end of file