/** * @test */ public function getTreeListReturnsChildPageUidsAndOriginalPidForNegativeValue() { $GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTgetSingleRow')->with('treelist')->will($this->returnValue(null)); $GLOBALS['TSFE']->sys_page->expects($this->any())->method('getRawRecord')->will($this->onConsecutiveCalls(array('uid' => 17), array('uid' => 321), array('uid' => 719), array('uid' => 42))); $GLOBALS['TSFE']->sys_page->expects($this->any())->method('getMountPointInfo')->will($this->returnValue(null)); $GLOBALS['TYPO3_DB']->expects($this->any())->method('exec_SELECTgetRows')->will($this->onConsecutiveCalls(array(array('uid' => 321)), array(array('uid' => 719)), array(array('uid' => 42)))); // 17 = pageId, 5 = recursionLevel, 0 = begin (entry to recursion, internal), TRUE = do not check enable fields // 17 is negative, we expect 17 to be included in result $result = $this->subject->getTreeList(-17, 5, 0, true); $expectedResult = '42,719,321,17'; $this->assertEquals($expectedResult, $result); }
/** * Returns a commalist of page ids for a query (eg. 'WHERE pid IN (...)') * * @param string $pid_list A comma list of page ids (if empty current page is used) * @param int $recursive An integer >=0 telling how deep to dig for pids under each entry in $pid_list * @return string List of PID values (comma separated) */ public function pi_getPidList($pid_list, $recursive = 0) { if (!strcmp($pid_list, '')) { $pid_list = $this->frontendController->id; } $recursive = MathUtility::forceIntegerInRange($recursive, 0); $pid_list_arr = array_unique(GeneralUtility::trimExplode(',', $pid_list, TRUE)); $pid_list = array(); foreach ($pid_list_arr as $val) { $val = MathUtility::forceIntegerInRange($val, 0); if ($val) { $_list = $this->cObj->getTreeList(-1 * $val, $recursive); if ($_list) { $pid_list[] = $_list; } } } return implode(',', $pid_list); }
/** * Returns a commalist of page ids for a query (eg. 'WHERE pid IN (...)') * * @param string $pid_list A comma list of page ids (if empty current page is used) * @param integer$recursive An integer >=0 telling how deep to dig for pids under each entry in $pid_list * @return string List of PID values (comma separated) * @todo Define visibility */ public function pi_getPidList($pid_list, $recursive = 0) { if (!strcmp($pid_list, '')) { $pid_list = $GLOBALS['TSFE']->id; } $recursive = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($recursive, 0); $pid_list_arr = array_unique(\TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $pid_list, 1)); $pid_list = array(); foreach ($pid_list_arr as $val) { $val = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($val, 0); if ($val) { $_list = $this->cObj->getTreeList(-1 * $val, $recursive); if ($_list) { $pid_list[] = $_list; } } } return implode(',', $pid_list); }
/** * Creates the menu in the internal variables, ready for output. * Basically this will read the page records needed and fill in the internal $this->menuArr * Based on a hash of this array and some other variables the $this->result variable will be loaded either from cache OR by calling the generate() method of the class to create the menu for real. * * @return void * @todo Define visibility */ public function makeMenu() { if ($this->id) { $this->useCacheHash = FALSE; // Initializing showAccessRestrictedPages if ($this->mconf['showAccessRestrictedPages']) { // SAVING where_groupAccess $SAVED_where_groupAccess = $this->sys_page->where_groupAccess; // Temporarily removing fe_group checking! $this->sys_page->where_groupAccess = ''; } // Begin production of menu: $temp = array(); $altSortFieldValue = trim($this->mconf['alternativeSortingField']); $altSortField = $altSortFieldValue ?: 'sorting'; // ... only for the FIRST level of a HMENU if ($this->menuNumber == 1 && $this->conf['special']) { $value = isset($this->conf['special.']['value.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['value'], $this->conf['special.']['value.']) : $this->conf['special.']['value']; switch ($this->conf['special']) { case 'userfunction': $temp = $this->parent_cObj->callUserFunction($this->conf['special.']['userFunc'], array_merge($this->conf['special.'], array('_altSortField' => $altSortField)), ''); if (!is_array($temp)) { $temp = array(); } break; case 'language': $temp = array(); // Getting current page record NOT overlaid by any translation: $currentPageWithNoOverlay = $this->sys_page->getRawRecord('pages', $GLOBALS['TSFE']->page['uid']); // Traverse languages set up: $languageItems = GeneralUtility::intExplode(',', $value); foreach ($languageItems as $sUid) { // Find overlay record: if ($sUid) { $lRecs = $this->sys_page->getPageOverlay($GLOBALS['TSFE']->page['uid'], $sUid); } else { $lRecs = array(); } // Checking if the "disabled" state should be set. if (GeneralUtility::hideIfNotTranslated($GLOBALS['TSFE']->page['l18n_cfg']) && $sUid && !count($lRecs) || $GLOBALS['TSFE']->page['l18n_cfg'] & 1 && (!$sUid || !count($lRecs)) || !$this->conf['special.']['normalWhenNoLanguage'] && $sUid && !count($lRecs)) { $iState = $GLOBALS['TSFE']->sys_language_uid == $sUid ? 'USERDEF2' : 'USERDEF1'; } else { $iState = $GLOBALS['TSFE']->sys_language_uid == $sUid ? 'ACT' : 'NO'; } if ($this->conf['addQueryString']) { $getVars = $this->parent_cObj->getQueryArguments($this->conf['addQueryString.'], array('L' => $sUid), TRUE); $this->analyzeCacheHashRequirements($getVars); } else { $getVars = '&L=' . $sUid; } // Adding menu item: $temp[] = array_merge(array_merge($currentPageWithNoOverlay, $lRecs), array('ITEM_STATE' => $iState, '_ADD_GETVARS' => $getVars, '_SAFE' => TRUE)); } break; case 'directory': if ($value == '') { $value = $GLOBALS['TSFE']->page['uid']; } $items = GeneralUtility::intExplode(',', $value); foreach ($items as $id) { $MP = $this->tmpl->getFromMPmap($id); // Checking if a page is a mount page and if so, change the ID and set the MP var properly. $mount_info = $this->sys_page->getMountPointInfo($id); if (is_array($mount_info)) { if ($mount_info['overlay']) { // Overlays should already have their full MPvars calculated: $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']); $MP = $MP ? $MP : $mount_info['MPvar']; } else { $MP = ($MP ? $MP . ',' : '') . $mount_info['MPvar']; } $id = $mount_info['mount_pid']; } // Get sub-pages: $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'pid=' . (int) $id . $this->sys_page->where_hid_del, '', $altSortField); while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $row = $this->sys_page->getPage($row['uid']); $GLOBALS['TSFE']->sys_page->versionOL('pages', $row, TRUE); if (!empty($row)) { // Keep mount point? $mount_info = $this->sys_page->getMountPointInfo($row['uid'], $row); // There is a valid mount point. if (is_array($mount_info) && $mount_info['overlay']) { // Using "getPage" is OK since we need the check for enableFields // AND for type 2 of mount pids we DO require a doktype < 200! $mp_row = $this->sys_page->getPage($mount_info['mount_pid']); if (count($mp_row)) { $row = $mp_row; $row['_MP_PARAM'] = $mount_info['MPvar']; } else { // If the mount point could not be fetched with respect // to enableFields, unset the row so it does not become a part of the menu! unset($row); } } // Add external MP params, then the row: if (!empty($row)) { if ($MP) { $row['_MP_PARAM'] = $MP . ($row['_MP_PARAM'] ? ',' . $row['_MP_PARAM'] : ''); } $temp[$row['uid']] = $row; } } } $GLOBALS['TYPO3_DB']->sql_free_result($res); } break; case 'list': if ($value == '') { $value = $this->id; } $skippedEnableFields = array(); if (!empty($this->mconf['showAccessRestrictedPages'])) { $skippedEnableFields = array('fe_group' => 1); } /** @var \TYPO3\CMS\Core\Database\RelationHandler $loadDB*/ $loadDB = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Database\\RelationHandler'); $loadDB->setFetchAllFields(TRUE); $loadDB->start($value, 'pages'); $loadDB->additionalWhere['pages'] = $this->parent_cObj->enableFields('pages', FALSE, $skippedEnableFields); $loadDB->getFromDB(); foreach ($loadDB->itemArray as $val) { $MP = $this->tmpl->getFromMPmap($val['id']); // Keep mount point? $mount_info = $this->sys_page->getMountPointInfo($val['id']); // There is a valid mount point. if (is_array($mount_info) && $mount_info['overlay']) { // Using "getPage" is OK since we need the check for enableFields // AND for type 2 of mount pids we DO require a doktype < 200! $mp_row = $this->sys_page->getPage($mount_info['mount_pid']); if (count($mp_row)) { $row = $mp_row; $row['_MP_PARAM'] = $mount_info['MPvar']; // Overlays should already have their full MPvars calculated if ($mount_info['overlay']) { $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']); if ($MP) { unset($row['_MP_PARAM']); } } } else { // If the mount point could not be fetched with respect to // enableFields, unset the row so it does not become a part of the menu! unset($row); } } else { $row = $loadDB->results['pages'][$val['id']]; } //Add versioning overlay for current page (to respect workspaces) if (is_array($row)) { $this->sys_page->versionOL('pages', $row, TRUE); } // Add external MP params, then the row: if (is_array($row)) { if ($MP) { $row['_MP_PARAM'] = $MP . ($row['_MP_PARAM'] ? ',' . $row['_MP_PARAM'] : ''); } $temp[] = $this->sys_page->getPageOverlay($row); } } break; case 'updated': if ($value == '') { $value = $GLOBALS['TSFE']->page['uid']; } $items = GeneralUtility::intExplode(',', $value); if (MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'])) { $depth = MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 1, 20); } else { $depth = 20; } // Max number of items $limit = MathUtility::forceIntegerInRange($this->conf['special.']['limit'], 0, 100); $maxAge = (int) $this->parent_cObj->calc($this->conf['special.']['maxAge']); if (!$limit) { $limit = 10; } // *'auto', 'manual', 'tstamp' $mode = $this->conf['special.']['mode']; // Get id's $id_list_arr = array(); foreach ($items as $id) { $bA = MathUtility::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100); $id_list_arr[] = $this->parent_cObj->getTreeList(-1 * $id, $depth - 1 + $bA, $bA - 1); } $id_list = implode(',', $id_list_arr); // Get sortField (mode) switch ($mode) { case 'starttime': $sortField = 'starttime'; break; case 'lastUpdated': case 'manual': $sortField = 'lastUpdated'; break; case 'tstamp': $sortField = 'tstamp'; break; case 'crdate': $sortField = 'crdate'; break; default: $sortField = 'SYS_LASTCHANGED'; } // Get $extraWhere = ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->getDoktypeExcludeWhere(); if ($this->conf['special.']['excludeNoSearchPages']) { $extraWhere .= ' AND pages.no_search=0'; } if ($maxAge > 0) { $extraWhere .= ' AND ' . $sortField . '>' . ($GLOBALS['SIM_ACCESS_TIME'] - $maxAge); } $res = $this->parent_cObj->exec_getQuery('pages', array('pidInList' => '0', 'uidInList' => $id_list, 'where' => $sortField . '>=0' . $extraWhere, 'orderBy' => $altSortFieldValue ? $altSortFieldValue : $sortField . ' desc', 'max' => $limit)); while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $GLOBALS['TSFE']->sys_page->versionOL('pages', $row, TRUE); if (is_array($row)) { $temp[$row['uid']] = $this->sys_page->getPageOverlay($row); } } break; case 'keywords': list($value) = GeneralUtility::intExplode(',', $value); if (!$value) { $value = $GLOBALS['TSFE']->page['uid']; } if ($this->conf['special.']['setKeywords'] || $this->conf['special.']['setKeywords.']) { $kw = isset($this->conf['special.']['setKeywords.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['setKeywords'], $this->conf['special.']['setKeywords.']) : $this->conf['special.']['setKeywords']; } else { // The page record of the 'value'. $value_rec = $this->sys_page->getPage($value); $kfieldSrc = $this->conf['special.']['keywordsField.']['sourceField'] ? $this->conf['special.']['keywordsField.']['sourceField'] : 'keywords'; // keywords. $kw = trim($this->parent_cObj->keywords($value_rec[$kfieldSrc])); } // *'auto', 'manual', 'tstamp' $mode = $this->conf['special.']['mode']; switch ($mode) { case 'starttime': $sortField = 'starttime'; break; case 'lastUpdated': case 'manual': $sortField = 'lastUpdated'; break; case 'tstamp': $sortField = 'tstamp'; break; case 'crdate': $sortField = 'crdate'; break; default: $sortField = 'SYS_LASTCHANGED'; } // Depth, limit, extra where if (MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'])) { $depth = MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 0, 20); } else { $depth = 20; } // Max number of items $limit = MathUtility::forceIntegerInRange($this->conf['special.']['limit'], 0, 100); $extraWhere = ' AND pages.uid<>' . $value . ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->getDoktypeExcludeWhere(); if ($this->conf['special.']['excludeNoSearchPages']) { $extraWhere .= ' AND pages.no_search=0'; } // Start point $eLevel = $this->parent_cObj->getKey(isset($this->conf['special.']['entryLevel.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['entryLevel'], $this->conf['special.']['entryLevel.']) : $this->conf['special.']['entryLevel'], $this->tmpl->rootLine); $startUid = (int) $this->tmpl->rootLine[$eLevel]['uid']; // Which field is for keywords $kfield = 'keywords'; if ($this->conf['special.']['keywordsField']) { list($kfield) = explode(' ', trim($this->conf['special.']['keywordsField'])); } // If there are keywords and the startuid is present. if ($kw && $startUid) { $bA = MathUtility::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100); $id_list = $this->parent_cObj->getTreeList(-1 * $startUid, $depth - 1 + $bA, $bA - 1); $kwArr = explode(',', $kw); foreach ($kwArr as $word) { $word = trim($word); if ($word) { $keyWordsWhereArr[] = $kfield . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($word, 'pages') . '%\''; } } $res = $this->parent_cObj->exec_getQuery('pages', array('pidInList' => '0', 'uidInList' => $id_list, 'where' => '(' . implode(' OR ', $keyWordsWhereArr) . ')' . $extraWhere, 'orderBy' => $altSortFieldValue ? $altSortFieldValue : $sortField . ' desc', 'max' => $limit)); while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) { $GLOBALS['TSFE']->sys_page->versionOL('pages', $row, TRUE); if (is_array($row)) { $temp[$row['uid']] = $this->sys_page->getPageOverlay($row); } } } break; case 'categories': /** @var \TYPO3\CMS\Frontend\ContentObject\Menu\CategoryMenuUtility $categoryMenuUtility */ $categoryMenuUtility = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\Menu\\CategoryMenuUtility'); $temp = $categoryMenuUtility->collectPages($value, $this->conf['special.'], $this); break; case 'rootline': $range = isset($this->conf['special.']['range.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['range'], $this->conf['special.']['range.']) : $this->conf['special.']['range']; $begin_end = explode('|', $range); $begin_end[0] = (int) $begin_end[0]; if (!MathUtility::canBeInterpretedAsInteger($begin_end[1])) { $begin_end[1] = -1; } $beginKey = $this->parent_cObj->getKey($begin_end[0], $this->tmpl->rootLine); $endKey = $this->parent_cObj->getKey($begin_end[1], $this->tmpl->rootLine); if ($endKey < $beginKey) { $endKey = $beginKey; } $rl_MParray = array(); foreach ($this->tmpl->rootLine as $k_rl => $v_rl) { // For overlaid mount points, set the variable right now: if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) { $rl_MParray[] = $v_rl['_MP_PARAM']; } // Traverse rootline: if ($k_rl >= $beginKey && $k_rl <= $endKey) { $temp_key = $k_rl; $temp[$temp_key] = $this->sys_page->getPage($v_rl['uid']); if (count($temp[$temp_key])) { // If there are no specific target for the page, put the level specific target on. if (!$temp[$temp_key]['target']) { $temp[$temp_key]['target'] = $this->conf['special.']['targets.'][$k_rl]; $temp[$temp_key]['_MP_PARAM'] = implode(',', $rl_MParray); } } else { unset($temp[$temp_key]); } } // For normal mount points, set the variable for next level. if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) { $rl_MParray[] = $v_rl['_MP_PARAM']; } } // Reverse order of elements (e.g. "1,2,3,4" gets "4,3,2,1"): if (isset($this->conf['special.']['reverseOrder']) && $this->conf['special.']['reverseOrder']) { $temp = array_reverse($temp); $rl_MParray = array_reverse($rl_MParray); } break; case 'browse': list($value) = GeneralUtility::intExplode(',', $value); if (!$value) { $value = $GLOBALS['TSFE']->page['uid']; } // Will not work out of rootline if ($value != $this->tmpl->rootLine[0]['uid']) { $recArr = array(); // The page record of the 'value'. $value_rec = $this->sys_page->getPage($value); // 'up' page cannot be outside rootline if ($value_rec['pid']) { // The page record of 'up'. $recArr['up'] = $this->sys_page->getPage($value_rec['pid']); } // If the 'up' item was NOT level 0 in rootline... if ($recArr['up']['pid'] && $value_rec['pid'] != $this->tmpl->rootLine[0]['uid']) { // The page record of "index". $recArr['index'] = $this->sys_page->getPage($recArr['up']['pid']); } // prev / next is found $prevnext_menu = $this->removeInaccessiblePages($this->sys_page->getMenu($value_rec['pid'], '*', $altSortField)); $lastKey = 0; $nextActive = 0; foreach ($prevnext_menu as $k_b => $v_b) { if ($nextActive) { $recArr['next'] = $v_b; $nextActive = 0; } if ($v_b['uid'] == $value) { if ($lastKey) { $recArr['prev'] = $prevnext_menu[$lastKey]; } $nextActive = 1; } $lastKey = $k_b; } reset($prevnext_menu); $recArr['first'] = pos($prevnext_menu); end($prevnext_menu); $recArr['last'] = pos($prevnext_menu); // prevsection / nextsection is found // You can only do this, if there is a valid page two levels up! if (is_array($recArr['index'])) { $prevnextsection_menu = $this->removeInaccessiblePages($this->sys_page->getMenu($recArr['index']['uid'], '*', $altSortField)); $lastKey = 0; $nextActive = 0; foreach ($prevnextsection_menu as $k_b => $v_b) { if ($nextActive) { $sectionRec_temp = $this->removeInaccessiblePages($this->sys_page->getMenu($v_b['uid'], '*', $altSortField)); if (count($sectionRec_temp)) { reset($sectionRec_temp); $recArr['nextsection'] = pos($sectionRec_temp); end($sectionRec_temp); $recArr['nextsection_last'] = pos($sectionRec_temp); $nextActive = 0; } } if ($v_b['uid'] == $value_rec['pid']) { if ($lastKey) { $sectionRec_temp = $this->removeInaccessiblePages($this->sys_page->getMenu($prevnextsection_menu[$lastKey]['uid'], '*', $altSortField)); if (count($sectionRec_temp)) { reset($sectionRec_temp); $recArr['prevsection'] = pos($sectionRec_temp); end($sectionRec_temp); $recArr['prevsection_last'] = pos($sectionRec_temp); } } $nextActive = 1; } $lastKey = $k_b; } } if ($this->conf['special.']['items.']['prevnextToSection']) { if (!is_array($recArr['prev']) && is_array($recArr['prevsection_last'])) { $recArr['prev'] = $recArr['prevsection_last']; } if (!is_array($recArr['next']) && is_array($recArr['nextsection'])) { $recArr['next'] = $recArr['nextsection']; } } $items = explode('|', $this->conf['special.']['items']); $c = 0; foreach ($items as $k_b => $v_b) { $v_b = strtolower(trim($v_b)); if ((int) $this->conf['special.'][$v_b . '.']['uid']) { $recArr[$v_b] = $this->sys_page->getPage((int) $this->conf['special.'][$v_b . '.']['uid']); } if (is_array($recArr[$v_b])) { $temp[$c] = $recArr[$v_b]; if ($this->conf['special.'][$v_b . '.']['target']) { $temp[$c]['target'] = $this->conf['special.'][$v_b . '.']['target']; } $tmpSpecialFields = $this->conf['special.'][$v_b . '.']['fields.']; if (is_array($tmpSpecialFields)) { foreach ($tmpSpecialFields as $fk => $val) { $temp[$c][$fk] = $val; } } $c++; } } } break; } if ($this->mconf['sectionIndex']) { $sectionIndexes = array(); foreach ($temp as $page) { $sectionIndexes = $sectionIndexes + $this->sectionIndex($altSortField, $page['uid']); } $temp = $sectionIndexes; } } elseif (is_array($this->alternativeMenuTempArray)) { // Setting $temp array if not level 1. $temp = $this->alternativeMenuTempArray; } elseif ($this->mconf['sectionIndex']) { $temp = $this->sectionIndex($altSortField); } else { // Default: // gets the menu $temp = $this->sys_page->getMenu($this->id, '*', $altSortField); } $c = 0; $c_b = 0; $minItems = (int) ($this->mconf['minItems'] ?: $this->conf['minItems']); $maxItems = (int) ($this->mconf['maxItems'] ?: $this->conf['maxItems']); $begin = $this->parent_cObj->calc($this->mconf['begin'] ? $this->mconf['begin'] : $this->conf['begin']); $minItemsConf = isset($this->mconf['minItems.']) ? $this->mconf['minItems.'] : (isset($this->conf['minItems.']) ? $this->conf['minItems.'] : NULL); $minItems = is_array($minItemsConf) ? $this->parent_cObj->stdWrap($minItems, $minItemsConf) : $minItems; $maxItemsConf = isset($this->mconf['maxItems.']) ? $this->mconf['maxItems.'] : (isset($this->conf['maxItems.']) ? $this->conf['maxItems.'] : NULL); $maxItems = is_array($maxItemsConf) ? $this->parent_cObj->stdWrap($maxItems, $maxItemsConf) : $maxItems; $beginConf = isset($this->mconf['begin.']) ? $this->mconf['begin.'] : (isset($this->conf['begin.']) ? $this->conf['begin.'] : NULL); $begin = is_array($beginConf) ? $this->parent_cObj->stdWrap($begin, $beginConf) : $begin; $banUidArray = $this->getBannedUids(); // Fill in the menuArr with elements that should go into the menu: $this->menuArr = array(); foreach ($temp as $data) { $spacer = GeneralUtility::inList($this->spacerIDList, $data['doktype']) || $data['ITEM_STATE'] === 'SPC' ? 1 : 0; // if item is a spacer, $spacer is set if ($this->filterMenuPages($data, $banUidArray, $spacer)) { $c_b++; // If the beginning item has been reached. if ($begin <= $c_b) { $this->menuArr[$c] = $data; $this->menuArr[$c]['isSpacer'] = $spacer; $c++; if ($maxItems && $c >= $maxItems) { break; } } } } // Fill in fake items, if min-items is set. if ($minItems) { while ($c < $minItems) { $this->menuArr[$c] = array('title' => '...', 'uid' => $GLOBALS['TSFE']->id); $c++; } } // Passing the menuArr through a user defined function: if ($this->mconf['itemArrayProcFunc']) { if (!is_array($this->parentMenuArr)) { $this->parentMenuArr = array(); } $this->menuArr = $this->userProcess('itemArrayProcFunc', $this->menuArr); } // Setting number of menu items $GLOBALS['TSFE']->register['count_menuItems'] = count($this->menuArr); $this->hash = md5(serialize($this->menuArr) . serialize($this->mconf) . serialize($this->tmpl->rootLine) . serialize($this->MP_array)); // Get the cache timeout: if ($this->conf['cache_period']) { $cacheTimeout = $this->conf['cache_period']; } else { $cacheTimeout = $GLOBALS['TSFE']->get_cache_timeout(); } $cache = $this->getCache(); $cachedData = $cache->get($this->hash); if (!is_array($cachedData)) { $this->generate(); $cache->set($this->hash, $this->result, array('ident_MENUDATA'), (int) $cacheTimeout); } else { $this->result = $cachedData; } // End showAccessRestrictedPages if ($this->mconf['showAccessRestrictedPages']) { // RESTORING where_groupAccess $this->sys_page->where_groupAccess = $SAVED_where_groupAccess; } } }
/** * Fetches all menuitems if special = keywords is set * * @param string $specialValue The value from special.value * @param string $sortingField The sorting field * @return array */ protected function prepareMenuItemsForKeywordsMenu($specialValue, $sortingField) { $tsfe = $this->getTypoScriptFrontendController(); $menuItems = array(); list($specialValue) = GeneralUtility::intExplode(',', $specialValue); if (!$specialValue) { $specialValue = $tsfe->page['uid']; } if ($this->conf['special.']['setKeywords'] || $this->conf['special.']['setKeywords.']) { $kw = isset($this->conf['special.']['setKeywords.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['setKeywords'], $this->conf['special.']['setKeywords.']) : $this->conf['special.']['setKeywords']; } else { // The page record of the 'value'. $value_rec = $this->sys_page->getPage($specialValue); $kfieldSrc = $this->conf['special.']['keywordsField.']['sourceField'] ? $this->conf['special.']['keywordsField.']['sourceField'] : 'keywords'; // keywords. $kw = trim($this->parent_cObj->keywords($value_rec[$kfieldSrc])); } // *'auto', 'manual', 'tstamp' $mode = $this->conf['special.']['mode']; switch ($mode) { case 'starttime': $sortField = 'starttime'; break; case 'lastUpdated': case 'manual': $sortField = 'lastUpdated'; break; case 'tstamp': $sortField = 'tstamp'; break; case 'crdate': $sortField = 'crdate'; break; default: $sortField = 'SYS_LASTCHANGED'; } // Depth, limit, extra where if (MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'])) { $depth = MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 0, 20); } else { $depth = 20; } // Max number of items $limit = MathUtility::forceIntegerInRange($this->conf['special.']['limit'], 0, 100); $extraWhere = ' AND pages.uid<>' . $specialValue . ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->getDoktypeExcludeWhere(); if ($this->conf['special.']['excludeNoSearchPages']) { $extraWhere .= ' AND pages.no_search=0'; } // Start point $eLevel = $this->parent_cObj->getKey(isset($this->conf['special.']['entryLevel.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['entryLevel'], $this->conf['special.']['entryLevel.']) : $this->conf['special.']['entryLevel'], $this->tmpl->rootLine); $startUid = (int) $this->tmpl->rootLine[$eLevel]['uid']; // Which field is for keywords $kfield = 'keywords'; if ($this->conf['special.']['keywordsField']) { list($kfield) = explode(' ', trim($this->conf['special.']['keywordsField'])); } // If there are keywords and the startuid is present if ($kw && $startUid) { $bA = MathUtility::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100); $id_list = $this->parent_cObj->getTreeList(-1 * $startUid, $depth - 1 + $bA, $bA - 1); $kwArr = explode(',', $kw); $keyWordsWhereArr = array(); foreach ($kwArr as $word) { $word = trim($word); if ($word) { $keyWordsWhereArr[] = $kfield . ' LIKE \'%' . $this->getDatabaseConnection()->quoteStr($word, 'pages') . '%\''; } } $where = empty($keyWordsWhereArr) ? '' : '(' . implode(' OR ', $keyWordsWhereArr) . ')'; $res = $this->parent_cObj->exec_getQuery('pages', array('pidInList' => '0', 'uidInList' => $id_list, 'where' => $where . $extraWhere, 'orderBy' => $sortingField ?: $sortField . ' desc', 'max' => $limit)); while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) { $tsfe->sys_page->versionOL('pages', $row, true); if (is_array($row)) { $menuItems[$row['uid']] = $this->sys_page->getPageOverlay($row); } } $this->getDatabaseConnection()->sql_free_result($res); } return $menuItems; }
/** * Execute final query, based on phash integer list. The main point is sorting the result in the right order. * * @param string List of phash integers which match the search. * @param integer Pointer to which indexing configuration you want to search in. -1 means no filtering. 0 means only regular indexed content. * @return pointer Query result pointer */ protected function execFinalQuery($list, $freeIndexUid = -1) { // Setting up methods of filtering results // based on page types, access, etc. $page_join = ''; $page_where = ''; // Indexing configuration clause: $freeIndexUidClause = $this->freeIndexUidWhere($freeIndexUid); // Calling hook for alternative creation of page ID list if ($hookObj = $this->hookRequest('execFinalQuery_idList')) { $page_where = $hookObj->execFinalQuery_idList($list); } // Alternative to getting all page ids by ->getTreeList() where // "excludeSubpages" is NOT respected. if ($this->joinPagesForQuery) { $page_join = ', pages'; $page_where = ' AND pages.uid = ISEC.page_id ' . $this->enableFields('pages') . ' AND pages.no_search=0 AND pages.doktype<200 '; } elseif ($this->searchRootPageIdList >= 0) { // Collecting all pages IDs in which to search; // filtering out ALL pages that are not accessible due to enableFields. // Does NOT look for "no_search" field! $siteIdNumbers = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $this->searchRootPageIdList); $pageIdList = array(); foreach ($siteIdNumbers as $rootId) { $pageIdList[] = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getTreeList($rootId, 9999, 0, 0, '', '') . $rootId; } $page_where = ' AND ISEC.page_id IN (' . implode(',', $pageIdList) . ')'; } // otherwise select all / disable everything // If any of the ranking sortings are selected, we must make a // join with the word/rel-table again, because we need to // calculate ranking based on all search-words found. if (substr($this->sortOrder, 0, 5) == 'rank_') { switch ($this->sortOrder) { case 'rank_flag': // This gives priority to word-position (max-value) so that words in title, keywords, description counts more than in content. // The ordering is refined with the frequency sum as well. $grsel = 'MAX(IR.flags) AS order_val1, SUM(IR.freq) AS order_val2'; $orderBy = 'order_val1' . $this->getDescendingSortOrderFlag() . ', order_val2' . $this->getDescendingSortOrderFlag(); break; case 'rank_first': // Results in average position of search words on page. // Must be inversely sorted (low numbers are closer to top) $grsel = 'AVG(IR.first) AS order_val'; $orderBy = 'order_val' . $this->getDescendingSortOrderFlag(TRUE); break; case 'rank_count': // Number of words found $grsel = 'SUM(IR.count) AS order_val'; $orderBy = 'order_val' . $this->getDescendingSortOrderFlag(); break; default: // Frequency sum. I'm not sure if this is the best way to do // it (make a sum...). Or should it be the average? $grsel = 'SUM(IR.freq) AS order_val'; $orderBy = 'order_val' . $this->getDescendingSortOrderFlag(); break; } $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('ISEC.*, IP.*, ' . $grsel, 'index_words IW, index_rel IR, index_section ISEC, index_phash IP' . $page_join, 'IP.phash IN (' . $list . ') ' . $this->mediaTypeWhere() . $this->languageWhere() . $freeIndexUidClause . ' AND IW.wid=IR.wid AND ISEC.phash = IR.phash AND IP.phash = IR.phash' . $page_where, 'IP.phash,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2 ,ISEC.page_id,ISEC.uniqid,IP.phash_grouping,IP.data_filename ,IP.data_page_id ,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,IP.cHashParams,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId', $orderBy); } else { // Otherwise, if sorting are done with the pages table or other fields, // there is no need for joining with the rel/word tables: $orderBy = ''; switch ((string) $this->sortOrder) { case 'title': $orderBy = 'IP.item_title' . $this->getDescendingSortOrderFlag(); break; case 'crdate': $orderBy = 'IP.item_crdate' . $this->getDescendingSortOrderFlag(); break; case 'mtime': $orderBy = 'IP.item_mtime' . $this->getDescendingSortOrderFlag(); break; } $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('ISEC.*, IP.*', 'index_phash IP,index_section ISEC' . $page_join, 'IP.phash IN (' . $list . ') ' . $this->mediaTypeWhere() . $this->languageWhere() . $freeIndexUidClause . ' AND IP.phash = ISEC.phash' . $page_where, 'IP.phash,ISEC.phash,ISEC.phash_t3,ISEC.rl0,ISEC.rl1,ISEC.rl2 ,ISEC.page_id,ISEC.uniqid,IP.phash_grouping,IP.data_filename ,IP.data_page_id ,IP.data_page_reg1,IP.data_page_type,IP.data_page_mp,IP.gr_list,IP.item_type,IP.item_title,IP.item_description,IP.item_mtime,IP.tstamp,IP.item_size,IP.contentHash,IP.crdate,IP.parsetime,IP.sys_language_uid,IP.item_crdate,IP.cHashParams,IP.externalUrl,IP.recordUid,IP.freeIndexUid,IP.freeIndexSetId', $orderBy); } return $res; }
/** * renders a recursive pidList to reference content from a list of pages */ public function user_getTreeList() { $GLOBALS['TSFE']->register['pidInList'] = trim($this->cObj->data['uid'] . ',' . ($GLOBALS['TSFE']->register['tt_content_shortcut_recursive'] ? $this->cObj->getTreeList($this->cObj->data['uid'], $GLOBALS['TSFE']->register['tt_content_shortcut_recursive']) : ''), ','); }