[TASK] Remove superfluous parenthesis in sysext frontend
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / ContentObject / Menu / AbstractMenuContentObject.php
1 <?php
2 namespace TYPO3\CMS\Frontend\ContentObject\Menu;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 1999-2011 Kasper Skårhøj (kasperYYYY@typo3.com)
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the textfile GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29 /**
30 * Generating navigation / menus from TypoScript
31 *
32 * This file contains five classes, four of which are extensions to the main class, tslib_menu.
33 * The main class, tslib_menu, is also extended by other external PHP scripts such as the GMENU_LAYERS and GMENU_FOLDOUT scripts which creates pop-up menus.
34 * Notice that extension classes (like "tslib_tmenu") must have their suffix (here "tmenu") listed in $this->tmpl->menuclasses - otherwise they cannot be instantiated.
35 *
36 * Revised for TYPO3 3.6 June/2003 by Kasper Skårhøj
37 * XHTML compliant
38 *
39 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
40 */
41 /**
42 * Base class. The HMENU content object uses this (or more precisely one of the extension classes).
43 * Amoung others the class generates an array of menuitems. Thereafter functions from the subclasses are called.
44 * The class is ALWAYS used through extension classes (like tslib_gmenu or tslib_tmenu which are classics) and
45 *
46 * Example of usage (from tslib_cObj):
47 *
48 * $menu = t3lib_div::makeInstance('tslib_'.$cls);
49 * $menu->parent_cObj = $this;
50 * $menu->start($GLOBALS['TSFE']->tmpl, $GLOBALS['TSFE']->sys_page, '', $conf,1);
51 * $menu->makeMenu();
52 * $content.=$menu->writeMenu();
53 *
54 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
55 * @package TYPO3
56 * @subpackage tslib
57 * @see tslib_cObj::HMENU()
58 */
59 class AbstractMenuContentObject {
60
61 // tells you which menu-number this is. This is important when getting data from the setup
62 /**
63 * @todo Define visibility
64 */
65 public $menuNumber = 1;
66
67 // 0 = rootFolder
68 /**
69 * @todo Define visibility
70 */
71 public $entryLevel = 0;
72
73 // The doktype-number that defines a spacer
74 /**
75 * @todo Define visibility
76 */
77 public $spacerIDList = '199';
78
79 // Doktypes that define which should not be included in a menu
80 /**
81 * @todo Define visibility
82 */
83 public $doktypeExcludeList = '6';
84
85 /**
86 * @todo Define visibility
87 */
88 public $alwaysActivePIDlist = array();
89
90 /**
91 * @todo Define visibility
92 */
93 public $imgNamePrefix = 'img';
94
95 /**
96 * @todo Define visibility
97 */
98 public $imgNameNotRandom = 0;
99
100 /**
101 * @todo Define visibility
102 */
103 public $debug = 0;
104
105 /**
106 * Loaded with the parent cObj-object when a new HMENU is made
107 *
108 * @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
109 * @todo Define visibility
110 */
111 public $parent_cObj;
112
113 /**
114 * @todo Define visibility
115 */
116 public $GMENU_fixKey = 'gmenu';
117
118 // accumulation of mount point data
119 /**
120 * @todo Define visibility
121 */
122 public $MP_array = array();
123
124 // internal
125 // HMENU configuration
126 /**
127 * @todo Define visibility
128 */
129 public $conf = array();
130
131 // xMENU configuration (TMENU, GMENU etc)
132 /**
133 * @todo Define visibility
134 */
135 public $mconf = array();
136
137 /**
138 * template-object
139 *
140 * @var \TYPO3\CMS\Core\TypoScript\TemplateService
141 * @todo Define visibility
142 */
143 public $tmpl;
144
145 /**
146 * sys_page-object, pagefunctions
147 *
148 * @var \TYPO3\CMS\Frontend\Page\PageRepository
149 * @todo Define visibility
150 */
151 public $sys_page;
152
153 // The base page-id of the menu.
154 /**
155 * @todo Define visibility
156 */
157 public $id;
158
159 // Holds the page uid of the NEXT page in the root line from the page pointed to by entryLevel;
160 // Used to expand the menu automatically if in a certain root line.
161 /**
162 * @todo Define visibility
163 */
164 public $nextActive;
165
166 // The array of menuItems which is built
167 /**
168 * @todo Define visibility
169 */
170 public $menuArr;
171
172 /**
173 * @todo Define visibility
174 */
175 public $hash;
176
177 /**
178 * @todo Define visibility
179 */
180 public $result = array();
181
182 // Array: Is filled with an array of page uid numbers + RL parameters which are in the current
183 // root line (used to evaluate whether a menu item is in active state)
184 /**
185 * @todo Define visibility
186 */
187 public $rL_uidRegister = '';
188
189 /**
190 * @todo Define visibility
191 */
192 public $INPfixMD5;
193
194 /**
195 * @todo Define visibility
196 */
197 public $I;
198
199 /**
200 * @todo Define visibility
201 */
202 public $WMresult;
203
204 /**
205 * @todo Define visibility
206 */
207 public $WMfreezePrefix;
208
209 /**
210 * @todo Define visibility
211 */
212 public $WMmenuItems;
213
214 /**
215 * @todo Define visibility
216 */
217 public $WMsubmenuObjSuffixes;
218
219 /**
220 * @todo Define visibility
221 */
222 public $WMextraScript;
223
224 // Can be set to contain menu item arrays for sub-levels.
225 /**
226 * @todo Define visibility
227 */
228 public $alternativeMenuTempArray = '';
229
230 // Will be 'id' in XHTML-mode
231 /**
232 * @todo Define visibility
233 */
234 public $nameAttribute = 'name';
235
236 /**
237 * The initialization of the object. This just sets some internal variables.
238 *
239 * @param object $tmpl The $GLOBALS['TSFE']->tmpl object
240 * @param object $sys_page The $GLOBALS['TSFE']->sys_page object
241 * @param integer $id A starting point page id. This should probably be blank since the 'entryLevel' value will be used then.
242 * @param array $conf The TypoScript configuration for the HMENU cObject
243 * @param integer $menuNumber Menu number; 1,2,3. Should probably be '1'
244 * @param string $objSuffix Submenu Object suffix. This offers submenus a way to use alternative configuration for specific positions in the menu; By default "1 = TMENU" would use "1." for the TMENU configuration, but if this string is set to eg. "a" then "1a." would be used for configuration instead (while "1 = " is still used for the overall object definition of "TMENU")
245 * @return boolean Returns TRUE on success
246 * @see tslib_cObj::HMENU()
247 * @todo Define visibility
248 */
249 public function start(&$tmpl, &$sys_page, $id, $conf, $menuNumber, $objSuffix = '') {
250 // Init:
251 $this->conf = $conf;
252 $this->menuNumber = $menuNumber;
253 $this->mconf = $conf[$this->menuNumber . $objSuffix . '.'];
254 $this->debug = $GLOBALS['TSFE']->debug;
255 // In XHTML there is no "name" attribute anymore
256 switch ($GLOBALS['TSFE']->xhtmlDoctype) {
257 case 'xhtml_strict':
258
259 case 'xhtml_11':
260
261 case 'xhtml_2':
262
263 case 'html5':
264 $this->nameAttribute = 'id';
265 break;
266 default:
267 $this->nameAttribute = 'name';
268 break;
269 }
270 // Sets the internal vars. $tmpl MUST be the template-object. $sys_page MUST be the sys_page object
271 if ($this->conf[$this->menuNumber . $objSuffix] && is_object($tmpl) && is_object($sys_page)) {
272 $this->tmpl = $tmpl;
273 $this->sys_page = $sys_page;
274 // alwaysActivePIDlist initialized:
275 if (trim($this->conf['alwaysActivePIDlist']) || isset($this->conf['alwaysActivePIDlist.'])) {
276 if (isset($this->conf['alwaysActivePIDlist.'])) {
277 $this->conf['alwaysActivePIDlist'] = $this->parent_cObj->stdWrap($this->conf['alwaysActivePIDlist'], $this->conf['alwaysActivePIDlist.']);
278 }
279 $this->alwaysActivePIDlist = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $this->conf['alwaysActivePIDlist']);
280 }
281 // 'not in menu' doktypes
282 if ($this->conf['excludeDoktypes']) {
283 $this->doktypeExcludeList = $GLOBALS['TYPO3_DB']->cleanIntList($this->conf['excludeDoktypes']);
284 }
285 // EntryLevel
286 $this->entryLevel = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getKey(isset($conf['entryLevel.']) ? $this->parent_cObj->stdWrap($conf['entryLevel'], $conf['entryLevel.']) : $conf['entryLevel'], $this->tmpl->rootLine);
287 // Set parent page: If $id not stated with start() then the base-id will be found from rootLine[$this->entryLevel]
288 // Called as the next level in a menu. It is assumed that $this->MP_array is set from parent menu.
289 if ($id) {
290 $this->id = intval($id);
291 } else {
292 // This is a BRAND NEW menu, first level. So we take ID from rootline and also find MP_array (mount points)
293 $this->id = intval($this->tmpl->rootLine[$this->entryLevel]['uid']);
294 // Traverse rootline to build MP_array of pages BEFORE the entryLevel
295 // (MP var for ->id is picked up in the next part of the code...)
296 foreach ($this->tmpl->rootLine as $entryLevel => $levelRec) {
297 // For overlaid mount points, set the variable right now:
298 if ($levelRec['_MP_PARAM'] && $levelRec['_MOUNT_OL']) {
299 $this->MP_array[] = $levelRec['_MP_PARAM'];
300 }
301 // Break when entry level is reached:
302 if ($entryLevel >= $this->entryLevel) {
303 break;
304 }
305 // For normal mount points, set the variable for next level.
306 if ($levelRec['_MP_PARAM'] && !$levelRec['_MOUNT_OL']) {
307 $this->MP_array[] = $levelRec['_MP_PARAM'];
308 }
309 }
310 }
311 // Return FALSE if no page ID was set (thus no menu of subpages can be made).
312 if ($this->id <= 0) {
313 return FALSE;
314 }
315 // Check if page is a mount point, and if so set id and MP_array
316 // (basically this is ONLY for non-overlay mode, but in overlay mode an ID with a mount point should never reach this point anyways, so no harm done...)
317 $mount_info = $this->sys_page->getMountPointInfo($this->id);
318 if (is_array($mount_info)) {
319 $this->MP_array[] = $mount_info['MPvar'];
320 $this->id = $mount_info['mount_pid'];
321 }
322 // Gather list of page uids in root line (for "isActive" evaluation). Also adds the MP params in the path so Mount Points are respected.
323 // (List is specific for this rootline, so it may be supplied from parent menus for speed...)
324 if (!is_array($this->rL_uidRegister)) {
325 $rl_MParray = array();
326 foreach ($this->tmpl->rootLine as $v_rl) {
327 // For overlaid mount points, set the variable right now:
328 if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) {
329 $rl_MParray[] = $v_rl['_MP_PARAM'];
330 }
331 // Add to register:
332 $this->rL_uidRegister[] = 'ITEM:' . $v_rl['uid'] . (count($rl_MParray) ? ':' . implode(',', $rl_MParray) : '');
333 // For normal mount points, set the variable for next level.
334 if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) {
335 $rl_MParray[] = $v_rl['_MP_PARAM'];
336 }
337 }
338 }
339 // Set $directoryLevel so the following evalution of the nextActive will not return
340 // an invalid value if .special=directory was set
341 $directoryLevel = 0;
342 if ($this->conf['special'] == 'directory') {
343 $value = isset($this->conf['special.']['value.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['value'], $this->conf['special.']['value.']) : $this->conf['special.']['value'];
344 if ($value == '') {
345 $value = $GLOBALS['TSFE']->page['uid'];
346 }
347 $directoryLevel = intval($GLOBALS['TSFE']->tmpl->getRootlineLevel($value));
348 }
349 // Setting "nextActive": This is the page uid + MPvar of the NEXT page in rootline. Used to expand the menu if we are in the right branch of the tree
350 // Notice: The automatic expansion of a menu is designed to work only when no "special" modes (except "directory") are used.
351 $startLevel = $directoryLevel ? $directoryLevel : $this->entryLevel;
352 $currentLevel = $startLevel + $this->menuNumber;
353 if (is_array($this->tmpl->rootLine[$currentLevel])) {
354 $nextMParray = $this->MP_array;
355 if (!count($nextMParray) && !$this->tmpl->rootLine[$currentLevel]['_MOUNT_OL'] && $currentLevel > 0) {
356 // Make sure to slide-down any mount point information (_MP_PARAM) to children records in the rootline
357 // otherwise automatic expansion will not work
358 $parentRecord = $this->tmpl->rootLine[$currentLevel - 1];
359 if (isset($parentRecord['_MP_PARAM'])) {
360 $nextMParray[] = $parentRecord['_MP_PARAM'];
361 }
362 }
363 // In overlay mode, add next level MPvars as well:
364 if ($this->tmpl->rootLine[$currentLevel]['_MOUNT_OL']) {
365 $nextMParray[] = $this->tmpl->rootLine[$currentLevel]['_MP_PARAM'];
366 }
367 $this->nextActive = $this->tmpl->rootLine[$currentLevel]['uid'] . (count($nextMParray) ? ':' . implode(',', $nextMParray) : '');
368 } else {
369 $this->nextActive = '';
370 }
371 // imgNamePrefix
372 if ($this->mconf['imgNamePrefix']) {
373 $this->imgNamePrefix = $this->mconf['imgNamePrefix'];
374 }
375 $this->imgNameNotRandom = $this->mconf['imgNameNotRandom'];
376 $retVal = TRUE;
377 } else {
378 $GLOBALS['TT']->setTSlogMessage('ERROR in menu', 3);
379 $retVal = FALSE;
380 }
381 return $retVal;
382 }
383
384 /**
385 * Creates the menu in the internal variables, ready for output.
386 * Basically this will read the page records needed and fill in the internal $this->menuArr
387 * 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.
388 *
389 * @return void
390 * @todo Define visibility
391 */
392 public function makeMenu() {
393 if ($this->id) {
394 // Initializing showAccessRestrictedPages
395 if ($this->mconf['showAccessRestrictedPages']) {
396 // SAVING where_groupAccess
397 $SAVED_where_groupAccess = $this->sys_page->where_groupAccess;
398 // Temporarily removing fe_group checking!
399 $this->sys_page->where_groupAccess = '';
400 }
401 // Begin production of menu:
402 $temp = array();
403 $altSortFieldValue = trim($this->mconf['alternativeSortingField']);
404 $altSortField = $altSortFieldValue ? $altSortFieldValue : 'sorting';
405 // ... only for the FIRST level of a HMENU
406 if ($this->menuNumber == 1 && $this->conf['special']) {
407 $value = isset($this->conf['special.']['value.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['value'], $this->conf['special.']['value.']) : $this->conf['special.']['value'];
408 switch ($this->conf['special']) {
409 case 'userfunction':
410 $temp = $this->parent_cObj->callUserFunction($this->conf['special.']['userFunc'], array_merge($this->conf['special.'], array('_altSortField' => $altSortField)), '');
411 if (!is_array($temp)) {
412 $temp = array();
413 }
414 break;
415 case 'language':
416 $temp = array();
417 // Getting current page record NOT overlaid by any translation:
418 $currentPageWithNoOverlay = $this->sys_page->getRawRecord('pages', $GLOBALS['TSFE']->page['uid']);
419 // Traverse languages set up:
420 $languageItems = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $value);
421 foreach ($languageItems as $sUid) {
422 // Find overlay record:
423 if ($sUid) {
424 $lRecs = $this->sys_page->getPageOverlay($GLOBALS['TSFE']->page['uid'], $sUid);
425 } else {
426 $lRecs = array();
427 }
428 // Checking if the "disabled" state should be set.
429 if (\TYPO3\CMS\Core\Utility\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)) {
430 $iState = $GLOBALS['TSFE']->sys_language_uid == $sUid ? 'USERDEF2' : 'USERDEF1';
431 } else {
432 $iState = $GLOBALS['TSFE']->sys_language_uid == $sUid ? 'ACT' : 'NO';
433 }
434 if ($this->conf['addQueryString']) {
435 $getVars = $this->parent_cObj->getQueryArguments($this->conf['addQueryString.'], array('L' => $sUid), TRUE);
436 } else {
437 $getVars = '&L=' . $sUid;
438 }
439 // Adding menu item:
440 $temp[] = array_merge(array_merge($currentPageWithNoOverlay, $lRecs), array(
441 'ITEM_STATE' => $iState,
442 '_ADD_GETVARS' => $getVars,
443 '_SAFE' => TRUE
444 ));
445 }
446 break;
447 case 'directory':
448 if ($value == '') {
449 $value = $GLOBALS['TSFE']->page['uid'];
450 }
451 $items = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $value);
452 foreach ($items as $id) {
453 $MP = $this->tmpl->getFromMPmap($id);
454 // Checking if a page is a mount page and if so, change the ID and set the MP var properly.
455 $mount_info = $this->sys_page->getMountPointInfo($id);
456 if (is_array($mount_info)) {
457 if ($mount_info['overlay']) {
458 // Overlays should already have their full MPvars calculated:
459 $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']);
460 $MP = $MP ? $MP : $mount_info['MPvar'];
461 } else {
462 $MP = ($MP ? $MP . ',' : '') . $mount_info['MPvar'];
463 }
464 $id = $mount_info['mount_pid'];
465 }
466 // Get sub-pages:
467 $res = $this->parent_cObj->exec_getQuery('pages', array('pidInList' => $id, 'orderBy' => $altSortField));
468 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
469 $GLOBALS['TSFE']->sys_page->versionOL('pages', $row);
470 if (is_array($row)) {
471 // Keep mount point?
472 $mount_info = $this->sys_page->getMountPointInfo($row['uid'], $row);
473 // There is a valid mount point.
474 if (is_array($mount_info) && $mount_info['overlay']) {
475 // Using "getPage" is OK since we need the check for enableFields
476 // AND for type 2 of mount pids we DO require a doktype < 200!
477 $mp_row = $this->sys_page->getPage($mount_info['mount_pid']);
478 if (count($mp_row)) {
479 $row = $mp_row;
480 $row['_MP_PARAM'] = $mount_info['MPvar'];
481 } else {
482 // If the mount point could not be fetched with respect
483 // to enableFields, unset the row so it does not become a part of the menu!
484 unset($row);
485 }
486 }
487 // Add external MP params, then the row:
488 if (is_array($row)) {
489 if ($MP) {
490 $row['_MP_PARAM'] = $MP . ($row['_MP_PARAM'] ? ',' . $row['_MP_PARAM'] : '');
491 }
492 $temp[$row['uid']] = $this->sys_page->getPageOverlay($row);
493 }
494 }
495 }
496 }
497 break;
498 case 'list':
499 if ($value == '') {
500 $value = $this->id;
501 }
502 $loadDB = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('FE_loadDBGroup');
503 $loadDB->start($value, 'pages');
504 $loadDB->additionalWhere['pages'] = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::enableFields('pages');
505 $loadDB->getFromDB();
506 foreach ($loadDB->itemArray as $val) {
507 $MP = $this->tmpl->getFromMPmap($val['id']);
508 // Keep mount point?
509 $mount_info = $this->sys_page->getMountPointInfo($val['id']);
510 // There is a valid mount point.
511 if (is_array($mount_info) && $mount_info['overlay']) {
512 // Using "getPage" is OK since we need the check for enableFields
513 // AND for type 2 of mount pids we DO require a doktype < 200!
514 $mp_row = $this->sys_page->getPage($mount_info['mount_pid']);
515 if (count($mp_row)) {
516 $row = $mp_row;
517 $row['_MP_PARAM'] = $mount_info['MPvar'];
518 // Overlays should already have their full MPvars calculated
519 if ($mount_info['overlay']) {
520 $MP = $this->tmpl->getFromMPmap($mount_info['mount_pid']);
521 if ($MP) {
522 unset($row['_MP_PARAM']);
523 }
524 }
525 } else {
526 // If the mount point could not be fetched with respect to
527 // enableFields, unset the row so it does not become a part of the menu!
528 unset($row);
529 }
530 } else {
531 $row = $loadDB->results['pages'][$val['id']];
532 }
533 //Add versioning overlay for current page (to respect workspaces)
534 if (is_array($row)) {
535 $this->sys_page->versionOL('pages', $row, TRUE);
536 }
537 // Add external MP params, then the row:
538 if (is_array($row)) {
539 if ($MP) {
540 $row['_MP_PARAM'] = $MP . ($row['_MP_PARAM'] ? ',' . $row['_MP_PARAM'] : '');
541 }
542 $temp[] = $this->sys_page->getPageOverlay($row);
543 }
544 }
545 break;
546 case 'updated':
547 if ($value == '') {
548 $value = $GLOBALS['TSFE']->page['uid'];
549 }
550 $items = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $value);
551 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'])) {
552 $depth = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 1, 20);
553 } else {
554 $depth = 20;
555 }
556 // Max number of items
557 $limit = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->conf['special.']['limit'], 0, 100);
558 $maxAge = intval(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::calc($this->conf['special.']['maxAge']));
559 if (!$limit) {
560 $limit = 10;
561 }
562 // *'auto', 'manual', 'tstamp'
563 $mode = $this->conf['special.']['mode'];
564 // Get id's
565 $id_list_arr = array();
566 foreach ($items as $id) {
567 $bA = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100);
568 $id_list_arr[] = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getTreeList(-1 * $id, $depth - 1 + $bA, $bA - 1);
569 }
570 $id_list = implode(',', $id_list_arr);
571 // Get sortField (mode)
572 switch ($mode) {
573 case 'starttime':
574 $sortField = 'starttime';
575 break;
576 case 'lastUpdated':
577
578 case 'manual':
579 $sortField = 'lastUpdated';
580 break;
581 case 'tstamp':
582 $sortField = 'tstamp';
583 break;
584 case 'crdate':
585 $sortField = 'crdate';
586 break;
587 default:
588 $sortField = 'SYS_LASTCHANGED';
589 break;
590 }
591 // Get
592 $extraWhere = ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->getDoktypeExcludeWhere();
593 if ($this->conf['special.']['excludeNoSearchPages']) {
594 $extraWhere .= ' AND pages.no_search=0';
595 }
596 if ($maxAge > 0) {
597 $extraWhere .= ' AND ' . $sortField . '>' . ($GLOBALS['SIM_ACCESS_TIME'] - $maxAge);
598 }
599 $res = $this->parent_cObj->exec_getQuery('pages', array(
600 'pidInList' => '0',
601 'uidInList' => $id_list,
602 'where' => $sortField . '>=0' . $extraWhere,
603 'orderBy' => $altSortFieldValue ? $altSortFieldValue : $sortField . ' desc',
604 'max' => $limit
605 ));
606 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
607 $GLOBALS['TSFE']->sys_page->versionOL('pages', $row);
608 if (is_array($row)) {
609 $temp[$row['uid']] = $this->sys_page->getPageOverlay($row);
610 }
611 }
612 break;
613 case 'keywords':
614 list($value) = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $value);
615 if (!$value) {
616 $value = $GLOBALS['TSFE']->page['uid'];
617 }
618 if ($this->conf['special.']['setKeywords'] || $this->conf['special.']['setKeywords.']) {
619 $kw = isset($this->conf['special.']['setKeywords.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['setKeywords'], $this->conf['special.']['setKeywords.']) : $this->conf['special.']['setKeywords'];
620 } else {
621 // The page record of the 'value'.
622 $value_rec = $this->sys_page->getPage($value);
623 $kfieldSrc = $this->conf['special.']['keywordsField.']['sourceField'] ? $this->conf['special.']['keywordsField.']['sourceField'] : 'keywords';
624 // keywords.
625 $kw = trim(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::keywords($value_rec[$kfieldSrc]));
626 }
627 // *'auto', 'manual', 'tstamp'
628 $mode = $this->conf['special.']['mode'];
629 switch ($mode) {
630 case 'starttime':
631 $sortField = 'starttime';
632 break;
633 case 'lastUpdated':
634
635 case 'manual':
636 $sortField = 'lastUpdated';
637 break;
638 case 'tstamp':
639 $sortField = 'tstamp';
640 break;
641 case 'crdate':
642 $sortField = 'crdate';
643 break;
644 default:
645 $sortField = 'SYS_LASTCHANGED';
646 break;
647 }
648 // Depth, limit, extra where
649 if (\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'])) {
650 $depth = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 0, 20);
651 } else {
652 $depth = 20;
653 }
654 // Max number of items
655 $limit = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->conf['special.']['limit'], 0, 100);
656 $extraWhere = ' AND pages.uid<>' . $value . ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->getDoktypeExcludeWhere();
657 if ($this->conf['special.']['excludeNoSearchPages']) {
658 $extraWhere .= ' AND pages.no_search=0';
659 }
660 // Start point
661 $eLevel = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::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);
662 $startUid = intval($this->tmpl->rootLine[$eLevel]['uid']);
663 // Which field is for keywords
664 $kfield = 'keywords';
665 if ($this->conf['special.']['keywordsField']) {
666 list($kfield) = explode(' ', trim($this->conf['special.']['keywordsField']));
667 }
668 // If there are keywords and the startuid is present.
669 if ($kw && $startUid) {
670 $bA = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($this->conf['special.']['beginAtLevel'], 0, 100);
671 $id_list = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getTreeList(-1 * $startUid, $depth - 1 + $bA, $bA - 1);
672 $kwArr = explode(',', $kw);
673 foreach ($kwArr as $word) {
674 $word = trim($word);
675 if ($word) {
676 $keyWordsWhereArr[] = $kfield . ' LIKE \'%' . $GLOBALS['TYPO3_DB']->quoteStr($word, 'pages') . '%\'';
677 }
678 }
679 $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));
680 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
681 $GLOBALS['TSFE']->sys_page->versionOL('pages', $row);
682 if (is_array($row)) {
683 $temp[$row['uid']] = $this->sys_page->getPageOverlay($row);
684 }
685 }
686 }
687 break;
688 case 'rootline':
689 $range = isset($this->conf['special.']['range.']) ? $this->parent_cObj->stdWrap($this->conf['special.']['range'], $this->conf['special.']['range.']) : $this->conf['special.']['range'];
690 $begin_end = explode('|', $range);
691 $begin_end[0] = intval($begin_end[0]);
692 if (!\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($begin_end[1])) {
693 $begin_end[1] = -1;
694 }
695 $beginKey = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getKey($begin_end[0], $this->tmpl->rootLine);
696 $endKey = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getKey($begin_end[1], $this->tmpl->rootLine);
697 if ($endKey < $beginKey) {
698 $endKey = $beginKey;
699 }
700 $rl_MParray = array();
701 foreach ($this->tmpl->rootLine as $k_rl => $v_rl) {
702 // For overlaid mount points, set the variable right now:
703 if ($v_rl['_MP_PARAM'] && $v_rl['_MOUNT_OL']) {
704 $rl_MParray[] = $v_rl['_MP_PARAM'];
705 }
706 // Traverse rootline:
707 if ($k_rl >= $beginKey && $k_rl <= $endKey) {
708 $temp_key = $k_rl;
709 $temp[$temp_key] = $this->sys_page->getPage($v_rl['uid']);
710 if (count($temp[$temp_key])) {
711 // If there are no specific target for the page, put the level specific target on.
712 if (!$temp[$temp_key]['target']) {
713 $temp[$temp_key]['target'] = $this->conf['special.']['targets.'][$k_rl];
714 $temp[$temp_key]['_MP_PARAM'] = implode(',', $rl_MParray);
715 }
716 } else {
717 unset($temp[$temp_key]);
718 }
719 }
720 // For normal mount points, set the variable for next level.
721 if ($v_rl['_MP_PARAM'] && !$v_rl['_MOUNT_OL']) {
722 $rl_MParray[] = $v_rl['_MP_PARAM'];
723 }
724 }
725 // Reverse order of elements (e.g. "1,2,3,4" gets "4,3,2,1"):
726 if (isset($this->conf['special.']['reverseOrder']) && $this->conf['special.']['reverseOrder']) {
727 $temp = array_reverse($temp);
728 $rl_MParray = array_reverse($rl_MParray);
729 }
730 break;
731 case 'browse':
732 list($value) = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $value);
733 if (!$value) {
734 $value = $GLOBALS['TSFE']->page['uid'];
735 }
736 // Will not work out of rootline
737 if ($value != $this->tmpl->rootLine[0]['uid']) {
738 $recArr = array();
739 // The page record of the 'value'.
740 $value_rec = $this->sys_page->getPage($value);
741 // 'up' page cannot be outside rootline
742 if ($value_rec['pid']) {
743 // The page record of 'up'.
744 $recArr['up'] = $this->sys_page->getPage($value_rec['pid']);
745 }
746 // If the 'up' item was NOT level 0 in rootline...
747 if ($recArr['up']['pid'] && $value_rec['pid'] != $this->tmpl->rootLine[0]['uid']) {
748 // The page record of "index".
749 $recArr['index'] = $this->sys_page->getPage($recArr['up']['pid']);
750 }
751 // prev / next is found
752 $prevnext_menu = $this->sys_page->getMenu($value_rec['pid'], '*', $altSortField);
753 $lastKey = 0;
754 $nextActive = 0;
755 foreach ($prevnext_menu as $k_b => $v_b) {
756 if ($nextActive) {
757 $recArr['next'] = $v_b;
758 $nextActive = 0;
759 }
760 if ($v_b['uid'] == $value) {
761 if ($lastKey) {
762 $recArr['prev'] = $prevnext_menu[$lastKey];
763 }
764 $nextActive = 1;
765 }
766 $lastKey = $k_b;
767 }
768 reset($prevnext_menu);
769 $recArr['first'] = pos($prevnext_menu);
770 end($prevnext_menu);
771 $recArr['last'] = pos($prevnext_menu);
772 // prevsection / nextsection is found
773 // You can only do this, if there is a valid page two levels up!
774 if (is_array($recArr['index'])) {
775 $prevnextsection_menu = $this->sys_page->getMenu($recArr['index']['uid'], '*', $altSortField);
776 $lastKey = 0;
777 $nextActive = 0;
778 foreach ($prevnextsection_menu as $k_b => $v_b) {
779 if ($nextActive) {
780 $sectionRec_temp = $this->sys_page->getMenu($v_b['uid'], '*', $altSortField);
781 if (count($sectionRec_temp)) {
782 reset($sectionRec_temp);
783 $recArr['nextsection'] = pos($sectionRec_temp);
784 end($sectionRec_temp);
785 $recArr['nextsection_last'] = pos($sectionRec_temp);
786 $nextActive = 0;
787 }
788 }
789 if ($v_b['uid'] == $value_rec['pid']) {
790 if ($lastKey) {
791 $sectionRec_temp = $this->sys_page->getMenu($prevnextsection_menu[$lastKey]['uid'], '*', $altSortField);
792 if (count($sectionRec_temp)) {
793 reset($sectionRec_temp);
794 $recArr['prevsection'] = pos($sectionRec_temp);
795 end($sectionRec_temp);
796 $recArr['prevsection_last'] = pos($sectionRec_temp);
797 }
798 }
799 $nextActive = 1;
800 }
801 $lastKey = $k_b;
802 }
803 }
804 if ($this->conf['special.']['items.']['prevnextToSection']) {
805 if (!is_array($recArr['prev']) && is_array($recArr['prevsection_last'])) {
806 $recArr['prev'] = $recArr['prevsection_last'];
807 }
808 if (!is_array($recArr['next']) && is_array($recArr['nextsection'])) {
809 $recArr['next'] = $recArr['nextsection'];
810 }
811 }
812 $items = explode('|', $this->conf['special.']['items']);
813 $c = 0;
814 foreach ($items as $k_b => $v_b) {
815 $v_b = strtolower(trim($v_b));
816 if (intval($this->conf['special.'][$v_b . '.']['uid'])) {
817 $recArr[$v_b] = $this->sys_page->getPage(intval($this->conf['special.'][$v_b . '.']['uid']));
818 }
819 if (is_array($recArr[$v_b])) {
820 $temp[$c] = $recArr[$v_b];
821 if ($this->conf['special.'][$v_b . '.']['target']) {
822 $temp[$c]['target'] = $this->conf['special.'][$v_b . '.']['target'];
823 }
824 $tmpSpecialFields = $this->conf['special.'][$v_b . '.']['fields.'];
825 if (is_array($tmpSpecialFields)) {
826 foreach ($tmpSpecialFields as $fk => $val) {
827 $temp[$c][$fk] = $val;
828 }
829 }
830 $c++;
831 }
832 }
833 }
834 break;
835 }
836 if ($this->mconf['sectionIndex']) {
837 $sectionIndexes = array();
838 foreach ($temp as $page) {
839 $sectionIndexes = $sectionIndexes + $this->sectionIndex($altSortField, $page['uid']);
840 }
841 $temp = $sectionIndexes;
842 }
843 } elseif (is_array($this->alternativeMenuTempArray)) {
844 // Setting $temp array if not level 1.
845 $temp = $this->alternativeMenuTempArray;
846 } elseif ($this->mconf['sectionIndex']) {
847 $temp = $this->sectionIndex($altSortField);
848 } else {
849 // Default:
850 // gets the menu
851 $temp = $this->sys_page->getMenu($this->id, '*', $altSortField);
852 }
853 $c = 0;
854 $c_b = 0;
855 $minItems = intval($this->mconf['minItems'] ? $this->mconf['minItems'] : $this->conf['minItems']);
856 $maxItems = intval($this->mconf['maxItems'] ? $this->mconf['maxItems'] : $this->conf['maxItems']);
857 $begin = \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::calc($this->mconf['begin'] ? $this->mconf['begin'] : $this->conf['begin']);
858 $minItemsConf = isset($this->mconf['minItems.']) ? $this->mconf['minItems.'] : (isset($this->conf['minItems.']) ? $this->conf['minItems.'] : NULL);
859 $minItems = is_array($minItemsConf) ? $this->parent_cObj->stdWrap($minItems, $minItemsConf) : $minItems;
860 $maxItemsConf = isset($this->mconf['maxItems.']) ? $this->mconf['maxItems.'] : (isset($this->conf['maxItems.']) ? $this->conf['maxItems.'] : NULL);
861 $maxItems = is_array($maxItemsConf) ? $this->parent_cObj->stdWrap($maxItems, $maxItemsConf) : $maxItems;
862 $beginConf = isset($this->mconf['begin.']) ? $this->mconf['begin.'] : (isset($this->conf['begin.']) ? $this->conf['begin.'] : NULL);
863 $begin = is_array($beginConf) ? $this->parent_cObj->stdWrap($begin, $beginConf) : $begin;
864 $banUidArray = $this->getBannedUids();
865 // Fill in the menuArr with elements that should go into the menu:
866 $this->menuArr = array();
867 foreach ($temp as $data) {
868 $spacer = \TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->spacerIDList, $data['doktype']) || !strcmp($data['ITEM_STATE'], 'SPC') ? 1 : 0;
869 // if item is a spacer, $spacer is set
870 if ($this->filterMenuPages($data, $banUidArray, $spacer)) {
871 $c_b++;
872 // If the beginning item has been reached.
873 if ($begin <= $c_b) {
874 $this->menuArr[$c] = $data;
875 $this->menuArr[$c]['isSpacer'] = $spacer;
876 $c++;
877 if ($maxItems && $c >= $maxItems) {
878 break;
879 }
880 }
881 }
882 }
883 // Fill in fake items, if min-items is set.
884 if ($minItems) {
885 while ($c < $minItems) {
886 $this->menuArr[$c] = array(
887 'title' => '...',
888 'uid' => $GLOBALS['TSFE']->id
889 );
890 $c++;
891 }
892 }
893 // Passing the menuArr through a user defined function:
894 if ($this->mconf['itemArrayProcFunc']) {
895 if (!is_array($this->parentMenuArr)) {
896 $this->parentMenuArr = array();
897 }
898 $this->menuArr = $this->userProcess('itemArrayProcFunc', $this->menuArr);
899 }
900 // Setting number of menu items
901 $GLOBALS['TSFE']->register['count_menuItems'] = count($this->menuArr);
902 $this->hash = md5(serialize($this->menuArr) . serialize($this->mconf) . serialize($this->tmpl->rootLine) . serialize($this->MP_array));
903 // Get the cache timeout:
904 if ($this->conf['cache_period']) {
905 $cacheTimeout = $this->conf['cache_period'];
906 } else {
907 $cacheTimeout = $GLOBALS['TSFE']->get_cache_timeout();
908 }
909 $serData = $this->sys_page->getHash($this->hash);
910 if (!$serData) {
911 $this->generate();
912 $this->sys_page->storeHash($this->hash, serialize($this->result), 'MENUDATA', $cacheTimeout);
913 } else {
914 $this->result = unserialize($serData);
915 }
916 // End showAccessRestrictedPages
917 if ($this->mconf['showAccessRestrictedPages']) {
918 // RESTORING where_groupAccess
919 $this->sys_page->where_groupAccess = $SAVED_where_groupAccess;
920 }
921 }
922 }
923
924 /**
925 * Checks if a page is OK to include in the final menu item array. Pages can be excluded if the doktype is wrong, if they are hidden in navigation, have a uid in the list of banned uids etc.
926 *
927 * @param array $data Array of menu items
928 * @param array $banUidArray Array of page uids which are to be excluded
929 * @param boolean $spacer If set, then the page is a spacer.
930 * @return boolean Returns TRUE if the page can be safely included.
931 * @todo Define visibility
932 */
933 public function filterMenuPages(&$data, $banUidArray, $spacer) {
934 $includePage = TRUE;
935 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/tslib/class.tslib_menu.php']['filterMenuPages'])) {
936 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/tslib/class.tslib_menu.php']['filterMenuPages'] as $classRef) {
937 $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classRef);
938 if (!$hookObject instanceof \TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuFilterPagesHookInterface) {
939 throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Frontend\\ContentObject\\Menu\\AbstractMenuContentObject_filterMenuPagesHook', 1269877402);
940 }
941 $includePage = $includePage && $hookObject->processFilter($data, $banUidArray, $spacer, $this);
942 }
943 }
944 if (!$includePage) {
945 return FALSE;
946 }
947 if ($data['_SAFE']) {
948 return TRUE;
949 }
950 $uid = $data['uid'];
951 // If the spacer-function is not enabled, spacers will not enter the $menuArr
952 if ($this->mconf['SPC'] || !$spacer) {
953 // Page may not be 'not_in_menu' or 'Backend User Section'
954 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->doktypeExcludeList, $data['doktype'])) {
955 // Not hidden in navigation
956 if (!$data['nav_hide'] || $this->conf['includeNotInMenu']) {
957 // not in banned uid's
958 if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inArray($banUidArray, $uid)) {
959 // Checks if the default language version can be shown:
960 // Block page is set, if l18n_cfg allows plus: 1) Either default language or 2) another language but NO overlay record set for page!
961 $blockPage = $data['l18n_cfg'] & 1 && (!$GLOBALS['TSFE']->sys_language_uid || $GLOBALS['TSFE']->sys_language_uid && !$data['_PAGES_OVERLAY']);
962 if (!$blockPage) {
963 // Checking if a page should be shown in the menu depending on whether a translation exists:
964 $tok = TRUE;
965 // There is an alternative language active AND the current page requires a translation:
966 if ($GLOBALS['TSFE']->sys_language_uid && \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['l18n_cfg'])) {
967 if (!$data['_PAGES_OVERLAY']) {
968 $tok = FALSE;
969 }
970 }
971 // Continue if token is TRUE:
972 if ($tok) {
973 // Checking if "&L" should be modified so links to non-accessible pages will not happen.
974 if ($this->conf['protectLvar']) {
975 $languageUid = intval($GLOBALS['TSFE']->config['config']['sys_language_uid']);
976 if ($languageUid && ($this->conf['protectLvar'] == 'all' || \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['l18n_cfg']))) {
977 $olRec = $GLOBALS['TSFE']->sys_page->getPageOverlay($data['uid'], $languageUid);
978 if (!count($olRec)) {
979 // If no pages_language_overlay record then page can NOT be accessed in the language pointed to by "&L" and therefore we protect the link by setting "&L=0"
980 $data['_ADD_GETVARS'] .= '&L=0';
981 }
982 }
983 }
984 return TRUE;
985 }
986 }
987 }
988 }
989 }
990 }
991 }
992
993 /**
994 * Generating the per-menu-item configuration arrays based on the settings for item states (NO, RO, ACT, CUR etc) set in ->mconf (config for the current menu object)
995 * Basically it will produce an individual array for each menu item based on the item states. BUT in addition the "optionSplit" syntax for the values is ALSO evaluated here so that all property-values are "option-splitted" and the output will thus be resolved.
996 * Is called from the "generate" functions in the extension classes. The function is processor intensive due to the option split feature in particular. But since the generate function is not always called (since the ->result array may be cached, see makeMenu) it doesn't hurt so badly.
997 *
998 * @param integer $splitCount Number of menu items in the menu
999 * @return array An array with two keys: array($NOconf,$ROconf) - where $NOconf contains the resolved configuration for each item when NOT rolled-over and $ROconf contains the ditto for the mouseover state (if any)
1000 * @access private
1001 * @todo Define visibility
1002 */
1003 public function procesItemStates($splitCount) {
1004 // Prepare normal settings
1005 if (!is_array($this->mconf['NO.']) && $this->mconf['NO']) {
1006 // Setting a blank array if NO=1 and there are no properties.
1007 $this->mconf['NO.'] = array();
1008 }
1009 $NOconf = $this->tmpl->splitConfArray($this->mconf['NO.'], $splitCount);
1010 // Prepare rollOver settings, overriding normal settings
1011 $ROconf = array();
1012 if ($this->mconf['RO']) {
1013 $ROconf = $this->tmpl->splitConfArray($this->mconf['RO.'], $splitCount);
1014 }
1015 // Prepare IFSUB settings, overriding normal settings
1016 // IFSUB is TRUE if there exist submenu items to the current item
1017 if ($this->mconf['IFSUB']) {
1018 // Flag: If $IFSUB is generated
1019 $IFSUBinit = 0;
1020 foreach ($NOconf as $key => $val) {
1021 if ($this->isItemState('IFSUB', $key)) {
1022 // if this is the first IFSUB element, we must generate IFSUB.
1023 if (!$IFSUBinit) {
1024 $IFSUBconf = $this->tmpl->splitConfArray($this->mconf['IFSUB.'], $splitCount);
1025 if ($this->mconf['IFSUBRO']) {
1026 $IFSUBROconf = $this->tmpl->splitConfArray($this->mconf['IFSUBRO.'], $splitCount);
1027 }
1028 $IFSUBinit = 1;
1029 }
1030 // Substitute normal with ifsub
1031 $NOconf[$key] = $IFSUBconf[$key];
1032 // If rollOver on normal, we must apply a state for rollOver on the active
1033 if ($ROconf) {
1034 // If RollOver on active then apply this
1035 $ROconf[$key] = $IFSUBROconf[$key] ? $IFSUBROconf[$key] : $IFSUBconf[$key];
1036 }
1037 }
1038 }
1039 }
1040 // Prepare active settings, overriding normal settings
1041 if ($this->mconf['ACT']) {
1042 // Flag: If $ACT is generated
1043 $ACTinit = 0;
1044 // Find active
1045 foreach ($NOconf as $key => $val) {
1046 if ($this->isItemState('ACT', $key)) {
1047 // If this is the first 'active', we must generate ACT.
1048 if (!$ACTinit) {
1049 $ACTconf = $this->tmpl->splitConfArray($this->mconf['ACT.'], $splitCount);
1050 // Prepare active rollOver settings, overriding normal active settings
1051 if ($this->mconf['ACTRO']) {
1052 $ACTROconf = $this->tmpl->splitConfArray($this->mconf['ACTRO.'], $splitCount);
1053 }
1054 $ACTinit = 1;
1055 }
1056 // Substitute normal with active
1057 $NOconf[$key] = $ACTconf[$key];
1058 // If rollOver on normal, we must apply a state for rollOver on the active
1059 if ($ROconf) {
1060 // If RollOver on active then apply this
1061 $ROconf[$key] = $ACTROconf[$key] ? $ACTROconf[$key] : $ACTconf[$key];
1062 }
1063 }
1064 }
1065 }
1066 // Prepare ACT (active)/IFSUB settings, overriding normal settings
1067 // ACTIFSUB is TRUE if there exist submenu items to the current item and the current item is active
1068 if ($this->mconf['ACTIFSUB']) {
1069 // Flag: If $ACTIFSUB is generated
1070 $ACTIFSUBinit = 0;
1071 // Find active
1072 foreach ($NOconf as $key => $val) {
1073 if ($this->isItemState('ACTIFSUB', $key)) {
1074 // If this is the first 'active', we must generate ACTIFSUB.
1075 if (!$ACTIFSUBinit) {
1076 $ACTIFSUBconf = $this->tmpl->splitConfArray($this->mconf['ACTIFSUB.'], $splitCount);
1077 // Prepare active rollOver settings, overriding normal active settings
1078 if ($this->mconf['ACTIFSUBRO']) {
1079 $ACTIFSUBROconf = $this->tmpl->splitConfArray($this->mconf['ACTIFSUBRO.'], $splitCount);
1080 }
1081 $ACTIFSUBinit = 1;
1082 }
1083 // Substitute normal with active
1084 $NOconf[$key] = $ACTIFSUBconf[$key];
1085 // If rollOver on normal, we must apply a state for rollOver on the active
1086 if ($ROconf) {
1087 // If RollOver on active then apply this
1088 $ROconf[$key] = $ACTIFSUBROconf[$key] ? $ACTIFSUBROconf[$key] : $ACTIFSUBconf[$key];
1089 }
1090 }
1091 }
1092 }
1093 // Prepare CUR (current) settings, overriding normal settings
1094 // CUR is TRUE if the current page equals the item here!
1095 if ($this->mconf['CUR']) {
1096 // Flag: If $CUR is generated
1097 $CURinit = 0;
1098 foreach ($NOconf as $key => $val) {
1099 if ($this->isItemState('CUR', $key)) {
1100 // if this is the first 'current', we must generate CUR. Basically this control is just inherited
1101 // from the other implementations as current would only exist one time and thats it
1102 // (unless you use special-features of HMENU)
1103 if (!$CURinit) {
1104 $CURconf = $this->tmpl->splitConfArray($this->mconf['CUR.'], $splitCount);
1105 if ($this->mconf['CURRO']) {
1106 $CURROconf = $this->tmpl->splitConfArray($this->mconf['CURRO.'], $splitCount);
1107 }
1108 $CURinit = 1;
1109 }
1110 // Substitute normal with current
1111 $NOconf[$key] = $CURconf[$key];
1112 // If rollOver on normal, we must apply a state for rollOver on the active
1113 if ($ROconf) {
1114 // If RollOver on active then apply this
1115 $ROconf[$key] = $CURROconf[$key] ? $CURROconf[$key] : $CURconf[$key];
1116 }
1117 }
1118 }
1119 }
1120 // Prepare CUR (current)/IFSUB settings, overriding normal settings
1121 // CURIFSUB is TRUE if there exist submenu items to the current item and the current page equals the item here!
1122 if ($this->mconf['CURIFSUB']) {
1123 // Flag: If $CURIFSUB is generated
1124 $CURIFSUBinit = 0;
1125 foreach ($NOconf as $key => $val) {
1126 if ($this->isItemState('CURIFSUB', $key)) {
1127 // If this is the first 'current', we must generate CURIFSUB.
1128 if (!$CURIFSUBinit) {
1129 $CURIFSUBconf = $this->tmpl->splitConfArray($this->mconf['CURIFSUB.'], $splitCount);
1130 // Prepare current rollOver settings, overriding normal current settings
1131 if ($this->mconf['CURIFSUBRO']) {
1132 $CURIFSUBROconf = $this->tmpl->splitConfArray($this->mconf['CURIFSUBRO.'], $splitCount);
1133 }
1134 $CURIFSUBinit = 1;
1135 }
1136 // Substitute normal with active
1137 $NOconf[$key] = $CURIFSUBconf[$key];
1138 // If rollOver on normal, we must apply a state for rollOver on the current
1139 if ($ROconf) {
1140 // If RollOver on current then apply this
1141 $ROconf[$key] = $CURIFSUBROconf[$key] ? $CURIFSUBROconf[$key] : $CURIFSUBconf[$key];
1142 }
1143 }
1144 }
1145 }
1146 // Prepare active settings, overriding normal settings
1147 if ($this->mconf['USR']) {
1148 // Flag: If $USR is generated
1149 $USRinit = 0;
1150 // Find active
1151 foreach ($NOconf as $key => $val) {
1152 if ($this->isItemState('USR', $key)) {
1153 // if this is the first active, we must generate USR.
1154 if (!$USRinit) {
1155 $USRconf = $this->tmpl->splitConfArray($this->mconf['USR.'], $splitCount);
1156 // Prepare active rollOver settings, overriding normal active settings
1157 if ($this->mconf['USRRO']) {
1158 $USRROconf = $this->tmpl->splitConfArray($this->mconf['USRRO.'], $splitCount);
1159 }
1160 $USRinit = 1;
1161 }
1162 // Substitute normal with active
1163 $NOconf[$key] = $USRconf[$key];
1164 // If rollOver on normal, we must apply a state for rollOver on the active
1165 if ($ROconf) {
1166 // If RollOver on active then apply this
1167 $ROconf[$key] = $USRROconf[$key] ? $USRROconf[$key] : $USRconf[$key];
1168 }
1169 }
1170 }
1171 }
1172 // Prepare spacer settings, overriding normal settings
1173 if ($this->mconf['SPC']) {
1174 // Flag: If $SPC is generated
1175 $SPCinit = 0;
1176 // Find spacers
1177 foreach ($NOconf as $key => $val) {
1178 if ($this->isItemState('SPC', $key)) {
1179 // If this is the first spacer, we must generate SPC.
1180 if (!$SPCinit) {
1181 $SPCconf = $this->tmpl->splitConfArray($this->mconf['SPC.'], $splitCount);
1182 $SPCinit = 1;
1183 }
1184 // Substitute normal with spacer
1185 $NOconf[$key] = $SPCconf[$key];
1186 }
1187 }
1188 }
1189 // Prepare Userdefined settings
1190 if ($this->mconf['USERDEF1']) {
1191 // Flag: If $USERDEF1 is generated
1192 $USERDEF1init = 0;
1193 // Find active
1194 foreach ($NOconf as $key => $val) {
1195 if ($this->isItemState('USERDEF1', $key)) {
1196 // If this is the first active, we must generate USERDEF1.
1197 if (!$USERDEF1init) {
1198 $USERDEF1conf = $this->tmpl->splitConfArray($this->mconf['USERDEF1.'], $splitCount);
1199 // Prepare active rollOver settings, overriding normal active settings
1200 if ($this->mconf['USERDEF1RO']) {
1201 $USERDEF1ROconf = $this->tmpl->splitConfArray($this->mconf['USERDEF1RO.'], $splitCount);
1202 }
1203 $USERDEF1init = 1;
1204 }
1205 // Substitute normal with active
1206 $NOconf[$key] = $USERDEF1conf[$key];
1207 // If rollOver on normal, we must apply a state for rollOver on the active
1208 if ($ROconf) {
1209 // If RollOver on active then apply this
1210 $ROconf[$key] = $USERDEF1ROconf[$key] ? $USERDEF1ROconf[$key] : $USERDEF1conf[$key];
1211 }
1212 }
1213 }
1214 }
1215 // Prepare Userdefined settings
1216 if ($this->mconf['USERDEF2']) {
1217 // Flag: If $USERDEF2 is generated
1218 $USERDEF2init = 0;
1219 // Find active
1220 foreach ($NOconf as $key => $val) {
1221 if ($this->isItemState('USERDEF2', $key)) {
1222 // If this is the first active, we must generate USERDEF2.
1223 if (!$USERDEF2init) {
1224 $USERDEF2conf = $this->tmpl->splitConfArray($this->mconf['USERDEF2.'], $splitCount);
1225 // Prepare active rollOver settings, overriding normal active settings
1226 if ($this->mconf['USERDEF2RO']) {
1227 $USERDEF2ROconf = $this->tmpl->splitConfArray($this->mconf['USERDEF2RO.'], $splitCount);
1228 }
1229 $USERDEF2init = 1;
1230 }
1231 // Substitute normal with active
1232 $NOconf[$key] = $USERDEF2conf[$key];
1233 // If rollOver on normal, we must apply a state for rollOver on the active
1234 if ($ROconf) {
1235 // If RollOver on active then apply this
1236 $ROconf[$key] = $USERDEF2ROconf[$key] ? $USERDEF2ROconf[$key] : $USERDEF2conf[$key];
1237 }
1238 }
1239 }
1240 }
1241 return array($NOconf, $ROconf);
1242 }
1243
1244 /**
1245 * Creates the URL, target and onclick values for the menu item link. Returns them in an array as key/value pairs for <A>-tag attributes
1246 * This function doesn't care about the url, because if we let the url be redirected, it will be logged in the stat!!!
1247 *
1248 * @param integer $key Pointer to a key in the $this->menuArr array where the value for that key represents the menu item we are linking to (page record)
1249 * @param string $altTarget Alternative target
1250 * @param integer $typeOverride Alternative type
1251 * @return array Returns an array with A-tag attributes as key/value pairs (HREF, TARGET and onClick)
1252 * @access private
1253 * @todo Define visibility
1254 */
1255 public function link($key, $altTarget = '', $typeOverride = '') {
1256 // Mount points:
1257 $MP_var = $this->getMPvar($key);
1258 $MP_params = $MP_var ? '&MP=' . rawurlencode($MP_var) : '';
1259 // Setting override ID
1260 if ($this->mconf['overrideId'] || $this->menuArr[$key]['overrideId']) {
1261 $overrideArray = array();
1262 // If a user script returned the value overrideId in the menu array we use that as page id
1263 $overrideArray['uid'] = $this->mconf['overrideId'] ? $this->mconf['overrideId'] : $this->menuArr[$key]['overrideId'];
1264 $overrideArray['alias'] = '';
1265 // Clear MP parameters since ID was changed.
1266 $MP_params = '';
1267 } else {
1268 $overrideArray = '';
1269 }
1270 // Setting main target:
1271 if ($altTarget) {
1272 $mainTarget = $altTarget;
1273 } elseif ($this->mconf['target.']) {
1274 $mainTarget = $this->parent_cObj->stdWrap($this->mconf['target'], $this->mconf['target.']);
1275 } else {
1276 $mainTarget = $this->mconf['target'];
1277 }
1278 // Creating link:
1279 if ($this->mconf['collapse'] && $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key))) {
1280 $thePage = $this->sys_page->getPage($this->menuArr[$key]['pid']);
1281 $LD = $this->menuTypoLink($thePage, $mainTarget, '', '', $overrideArray, $this->mconf['addParams'] . $MP_params . $this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
1282 } else {
1283 $LD = $this->menuTypoLink($this->menuArr[$key], $mainTarget, '', '', $overrideArray, $this->mconf['addParams'] . $MP_params . $this->I['val']['additionalParams'] . $this->menuArr[$key]['_ADD_GETVARS'], $typeOverride);
1284 }
1285 // Override URL if using "External URL" as doktype with a valid e-mail address:
1286 if ($this->menuArr[$key]['doktype'] == \TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_LINK && $this->menuArr[$key]['urltype'] == 3 && \TYPO3\CMS\Core\Utility\GeneralUtility::validEmail($this->menuArr[$key]['url'])) {
1287 // Create mailto-link using tslib_cObj::typolink (concerning spamProtectEmailAddresses):
1288 $LD['totalURL'] = $this->parent_cObj->typoLink_URL(array('parameter' => $this->menuArr[$key]['url']));
1289 $LD['target'] = '';
1290 }
1291 // Override url if current page is a shortcut
1292 if ($this->menuArr[$key]['doktype'] == \TYPO3\CMS\Frontend\Page\PageRepository::DOKTYPE_SHORTCUT && $this->menuArr[$key]['shortcut_mode'] != \TYPO3\CMS\Frontend\Page\PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE) {
1293 $shortcut = NULL;
1294 try {
1295 $shortcut = $GLOBALS['TSFE']->getPageShortcut($this->menuArr[$key]['shortcut'], $this->menuArr[$key]['shortcut_mode'], $this->menuArr[$key]['uid']);
1296 } catch (\Exception $ex) {
1297
1298 }
1299 if (!is_array($shortcut)) {
1300 return array();
1301 }
1302 // Only setting url, not target
1303 $LD['totalURL'] = $this->parent_cObj->typoLink_URL(array(
1304 'parameter' => $shortcut['uid'],
1305 'additionalParams' => $this->mconf['addParams'] . $MP_params . $this->I['val']['additionalParams'] . $this->menuArr[$key]['_ADD_GETVARS']
1306 ));
1307 }
1308 // Manipulation in case of access restricted pages:
1309 $this->changeLinksForAccessRestrictedPages($LD, $this->menuArr[$key], $mainTarget, $typeOverride);
1310 // Overriding URL / Target if set to do so:
1311 if ($this->menuArr[$key]['_OVERRIDE_HREF']) {
1312 $LD['totalURL'] = $this->menuArr[$key]['_OVERRIDE_HREF'];
1313 if ($this->menuArr[$key]['_OVERRIDE_TARGET']) {
1314 $LD['target'] = $this->menuArr[$key]['_OVERRIDE_TARGET'];
1315 }
1316 }
1317 // OnClick open in windows.
1318 $onClick = '';
1319 if ($this->mconf['JSWindow']) {
1320 $conf = $this->mconf['JSWindow.'];
1321 $url = $LD['totalURL'];
1322 $LD['totalURL'] = '#';
1323 $onClick = 'openPic(\'' . $GLOBALS['TSFE']->baseUrlWrap($url) . '\',\'' . ($conf['newWindow'] ? md5($url) : 'theNewPage') . '\',\'' . $conf['params'] . '\'); return false;';
1324 $GLOBALS['TSFE']->setJS('openPic');
1325 }
1326 // look for type and popup
1327 // following settings are valid in field target:
1328 // 230 will add type=230 to the link
1329 // 230 500x600 will add type=230 to the link and open in popup window with 500x600 pixels
1330 // 230 _blank will add type=230 to the link and open with target "_blank"
1331 // 230x450:resizable=0,location=1 will open in popup window with 500x600 pixels with settings "resizable=0,location=1"
1332 $matches = array();
1333 $targetIsType = $LD['target'] && (string) intval($LD['target']) == trim($LD['target']) ? intval($LD['target']) : FALSE;
1334 if (preg_match('/([0-9]+[\\s])?(([0-9]+)x([0-9]+))?(:.+)?/s', $LD['target'], $matches) || $targetIsType) {
1335 // has type?
1336 if (intval($matches[1]) || $targetIsType) {
1337 $LD['totalURL'] = $this->parent_cObj->URLqMark($LD['totalURL'], '&type=' . ($targetIsType ? $targetIsType : intval($matches[1])));
1338 $LD['target'] = $targetIsType ? '' : trim(substr($LD['target'], strlen($matches[1]) + 1));
1339 }
1340 // Open in popup window?
1341 if ($matches[3] && $matches[4]) {
1342 $JSparamWH = 'width=' . $matches[3] . ',height=' . $matches[4] . ($matches[5] ? ',' . substr($matches[5], 1) : '');
1343 $onClick = 'vHWin=window.open(\'' . $LD['totalURL'] . '\',\'FEopenLink\',\'' . $JSparamWH . '\');vHWin.focus();return false;';
1344 $LD['target'] = '';
1345 }
1346 }
1347 // out:
1348 $list = array();
1349 // Added this check: What it does is to enter the baseUrl (if set, which it should for "realurl" based sites)
1350 // as URL if the calculated value is empty. The problem is that no link is generated with a blank URL
1351 // and blank URLs might appear when the realurl encoding is used and a link to the frontpage is generated.
1352 $list['HREF'] = strlen($LD['totalURL']) ? $LD['totalURL'] : $GLOBALS['TSFE']->baseUrl;
1353 $list['TARGET'] = $LD['target'];
1354 $list['onClick'] = $onClick;
1355 return $list;
1356 }
1357
1358 /**
1359 * Will change $LD (passed by reference) if the page is access restricted
1360 *
1361 * @param array $LD The array from the linkData() function
1362 * @param array $page Page array
1363 * @param string $mainTarget Main target value
1364 * @param string $typeOverride Type number override if any
1365 * @return void ($LD passed by reference might be changed.)
1366 * @todo Define visibility
1367 */
1368 public function changeLinksForAccessRestrictedPages(&$LD, $page, $mainTarget, $typeOverride) {
1369 // If access restricted pages should be shown in menus, change the link of such pages to link to a redirection page:
1370 if ($this->mconf['showAccessRestrictedPages'] && $this->mconf['showAccessRestrictedPages'] !== 'NONE' && !$GLOBALS['TSFE']->checkPageGroupAccess($page)) {
1371 $thePage = $this->sys_page->getPage($this->mconf['showAccessRestrictedPages']);
1372 $addParams = $this->mconf['showAccessRestrictedPages.']['addParams'];
1373 $addParams = str_replace('###RETURN_URL###', rawurlencode($LD['totalURL']), $addParams);
1374 $addParams = str_replace('###PAGE_ID###', $page['uid'], $addParams);
1375 $LD = $this->menuTypoLink($thePage, $mainTarget, '', '', '', $addParams, $typeOverride);
1376 }
1377 }
1378
1379 /**
1380 * Creates a submenu level to the current level - if configured for.
1381 *
1382 * @param integer $uid Page id of the current page for which a submenu MAY be produced (if conditions are met)
1383 * @param string $objSuffix Object prefix, see ->start()
1384 * @return string HTML content of the submenu
1385 * @access private
1386 * @todo Define visibility
1387 */
1388 public function subMenu($uid, $objSuffix = '') {
1389 // Setting alternative menu item array if _SUB_MENU has been defined in the current ->menuArr
1390 $altArray = '';
1391 if (is_array($this->menuArr[$this->I['key']]['_SUB_MENU']) && count($this->menuArr[$this->I['key']]['_SUB_MENU'])) {
1392 $altArray = $this->menuArr[$this->I['key']]['_SUB_MENU'];
1393 }
1394 // Make submenu if the page is the next active
1395 $cls = strtolower($this->conf[($this->menuNumber + 1) . $objSuffix]);
1396 $subLevelClass = $cls && \TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->tmpl->menuclasses, $cls) ? $cls : '';
1397 // stdWrap for expAll
1398 if (isset($this->mconf['expAll.'])) {
1399 $this->mconf['expAll'] = $this->parent_cObj->stdWrap($this->mconf['expAll'], $this->mconf['expAll.']);
1400 }
1401 if ($subLevelClass && ($this->mconf['expAll'] || $this->isNext($uid, $this->getMPvar($this->I['key'])) || is_array($altArray)) && !$this->mconf['sectionIndex']) {
1402 $submenu = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tslib_' . $subLevelClass);
1403 $submenu->entryLevel = $this->entryLevel + 1;
1404 $submenu->rL_uidRegister = $this->rL_uidRegister;
1405 $submenu->MP_array = $this->MP_array;
1406 if ($this->menuArr[$this->I['key']]['_MP_PARAM']) {
1407 $submenu->MP_array[] = $this->menuArr[$this->I['key']]['_MP_PARAM'];
1408 }
1409 // Especially scripts that build the submenu needs the parent data
1410 $submenu->parent_cObj = $this->parent_cObj;
1411 $submenu->parentMenuArr = $this->menuArr;
1412 // Setting alternativeMenuTempArray (will be effective only if an array)
1413 if (is_array($altArray)) {
1414 $submenu->alternativeMenuTempArray = $altArray;
1415 }
1416 if ($submenu->start($this->tmpl, $this->sys_page, $uid, $this->conf, $this->menuNumber + 1, $objSuffix)) {
1417 $submenu->makeMenu();
1418 // Memorize the current menu item count
1419 $tempCountMenuObj = $GLOBALS['TSFE']->register['count_MENUOBJ'];
1420 // Reset the menu item count for the submenu
1421 $GLOBALS['TSFE']->register['count_MENUOBJ'] = 0;
1422 $content = $submenu->writeMenu();
1423 // Restore the item count now that the submenu has been handled
1424 $GLOBALS['TSFE']->register['count_MENUOBJ'] = $tempCountMenuObj;
1425 $GLOBALS['TSFE']->register['count_menuItems'] = count($this->menuArr);
1426 return $content;
1427 }
1428 }
1429 }
1430
1431 /**
1432 * Returns TRUE if the page with UID $uid is the NEXT page in root line (which means a submenu should be drawn)
1433 *
1434 * @param integer $uid Page uid to evaluate.
1435 * @param string $MPvar MPvar for the current position of item.
1436 * @return boolean TRUE if page with $uid is active
1437 * @access private
1438 * @see subMenu()
1439 * @todo Define visibility
1440 */
1441 public function isNext($uid, $MPvar = '') {
1442 // Check for always active PIDs:
1443 if (count($this->alwaysActivePIDlist) && in_array($uid, $this->alwaysActivePIDlist)) {
1444 return TRUE;
1445 }
1446 $testUid = $uid . ($MPvar ? ':' . $MPvar : '');
1447 if ($uid && $testUid == $this->nextActive) {
1448 return TRUE;
1449 }
1450 }
1451
1452 /**
1453 * Returns TRUE if the page with UID $uid is active (in the current rootline)
1454 *
1455 * @param integer $uid Page uid to evaluate.
1456 * @param string $MPvar MPvar for the current position of item.
1457 * @return boolean TRUE if page with $uid is active
1458 * @access private
1459 * @todo Define visibility
1460 */
1461 public function isActive($uid, $MPvar = '') {
1462 // Check for always active PIDs:
1463 if (count($this->alwaysActivePIDlist) && in_array($uid, $this->alwaysActivePIDlist)) {
1464 return TRUE;
1465 }
1466 $testUid = $uid . ($MPvar ? ':' . $MPvar : '');
1467 if ($uid && in_array('ITEM:' . $testUid, $this->rL_uidRegister)) {
1468 return TRUE;
1469 }
1470 }
1471
1472 /**
1473 * Returns TRUE if the page with UID $uid is the CURRENT page (equals $GLOBALS['TSFE']->id)
1474 *
1475 * @param integer $uid Page uid to evaluate.
1476 * @param string $MPvar MPvar for the current position of item.
1477 * @return boolean TRUE if page $uid = $GLOBALS['TSFE']->id
1478 * @access private
1479 * @todo Define visibility
1480 */
1481 public function isCurrent($uid, $MPvar = '') {
1482 $testUid = $uid . ($MPvar ? ':' . $MPvar : '');
1483 if ($uid && !strcmp(end($this->rL_uidRegister), ('ITEM:' . $testUid))) {
1484 return TRUE;
1485 }
1486 }
1487
1488 /**
1489 * Returns TRUE if there is a submenu with items for the page id, $uid
1490 * Used by the item states "IFSUB", "ACTIFSUB" and "CURIFSUB" to check if there is a submenu
1491 *
1492 * @param integer $uid Page uid for which to search for a submenu
1493 * @return boolean Returns TRUE if there was a submenu with items found
1494 * @access private
1495 * @todo Define visibility
1496 */
1497 public function isSubMenu($uid) {
1498 // Looking for a mount-pid for this UID since if that
1499 // exists we should look for a subpages THERE and not in the input $uid;
1500 $mount_info = $this->sys_page->getMountPointInfo($uid);
1501 if (is_array($mount_info)) {
1502 $uid = $mount_info['mount_pid'];
1503 }
1504 $recs = $this->sys_page->getMenu($uid, 'uid,pid,doktype,mount_pid,mount_pid_ol,nav_hide,shortcut,shortcut_mode,l18n_cfg');
1505 $hasSubPages = FALSE;
1506 foreach ($recs as $theRec) {
1507 // no valid subpage if the document type is excluded from the menu
1508 if (\TYPO3\CMS\Core\Utility\GeneralUtility::inList($this->doktypeExcludeList, $theRec['doktype'])) {
1509 continue;
1510 }
1511 // No valid subpage if the page is hidden inside menus and
1512 // it wasn't forced to show such entries
1513 if ($theRec['nav_hide'] && !$this->conf['includeNotInMenu']) {
1514 continue;
1515 }
1516 // No valid subpage if the default language should be shown and the page settings
1517 // are excluding the visibility of the default language
1518 if (!$GLOBALS['TSFE']->sys_language_uid && \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfDefaultLanguage($theRec['l18n_cfg'])) {
1519 continue;
1520 }
1521 // No valid subpage if the alternative language should be shown and the page settings
1522 // are requiring a valid overlay but it doesn't exists
1523 $hideIfNotTranslated = \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($theRec['l18n_cfg']);
1524 if ($GLOBALS['TSFE']->sys_language_uid && $hideIfNotTranslated && !$theRec['_PAGES_OVERLAY']) {
1525 continue;
1526 }
1527 $hasSubPages = TRUE;
1528 break;
1529 }
1530 return $hasSubPages;
1531 }
1532
1533 /**
1534 * Used by procesItemStates() to evaluate if a menu item (identified by $key) is in a certain state.
1535 *
1536 * @param string $kind The item state to evaluate (SPC, IFSUB, ACT etc... but no xxxRO states of course)
1537 * @param integer $key Key pointing to menu item from ->menuArr
1538 * @return boolean True (integer!=0) if match, otherwise FALSE (=0, zero)
1539 * @access private
1540 * @see procesItemStates()
1541 * @todo Define visibility
1542 */
1543 public function isItemState($kind, $key) {
1544 $natVal = 0;
1545 // If any value is set for ITEM_STATE the normal evaluation is discarded
1546 if ($this->menuArr[$key]['ITEM_STATE']) {
1547 if (!strcmp($this->menuArr[$key]['ITEM_STATE'], $kind)) {
1548 $natVal = 1;
1549 }
1550 } else {
1551 switch ($kind) {
1552 case 'SPC':
1553 $natVal = $this->menuArr[$key]['isSpacer'];
1554 break;
1555 case 'IFSUB':
1556 $natVal = $this->isSubMenu($this->menuArr[$key]['uid']);
1557 break;
1558 case 'ACT':
1559 $natVal = $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key));
1560 break;
1561 case 'ACTIFSUB':
1562 $natVal = $this->isActive($this->menuArr[$key]['uid'], $this->getMPvar($key)) && $this->isSubMenu($this->menuArr[$key]['uid']);
1563 break;
1564 case 'CUR':
1565 $natVal = $this->isCurrent($this->menuArr[$key]['uid'], $this->getMPvar($key));
1566 break;
1567 case 'CURIFSUB':
1568 $natVal = $this->isCurrent($this->menuArr[$key]['uid'], $this->getMPvar($key)) && $this->isSubMenu($this->menuArr[$key]['uid']);
1569 break;
1570 case 'USR':
1571 $natVal = $this->menuArr[$key]['fe_group'];
1572 break;
1573 }
1574 }
1575 return $natVal;
1576 }
1577
1578 /**
1579 * Creates an access-key for a TMENU/GMENU menu item based on the menu item titles first letter
1580 *
1581 * @param string $title Menu item title.
1582 * @return array Returns an array with keys "code" ("accesskey" attribute for the img-tag) and "alt" (text-addition to the "alt" attribute) if an access key was defined. Otherwise array was empty
1583 * @access private
1584 * @todo Define visibility
1585 */
1586 public function accessKey($title) {
1587 // The global array ACCESSKEY is used to globally control if letters are already used!!
1588 $result = array();
1589 $title = trim(strip_tags($title));
1590 $titleLen = strlen($title);
1591 for ($a = 0; $a < $titleLen; $a++) {
1592 $key = strtoupper(substr($title, $a, 1));
1593 if (preg_match('/[A-Z]/', $key) && !isset($GLOBALS['TSFE']->accessKey[$key])) {
1594 $GLOBALS['TSFE']->accessKey[$key] = 1;
1595 $result['code'] = ' accesskey="' . $key . '"';
1596 $result['alt'] = ' (ALT+' . $key . ')';
1597 $result['key'] = $key;
1598 break;
1599 }
1600 }
1601 return $result;
1602 }
1603
1604 /**
1605 * Calls a user function for processing of internal data.
1606 * Used for the properties "IProcFunc" and "itemArrayProcFunc"
1607 *
1608 * @param string $mConfKey Key pointing for the property in the current ->mconf array holding possibly parameters to pass along to the function/method. Currently the keys used are "IProcFunc" and "itemArrayProcFunc".
1609 * @param mixed $passVar A variable to pass to the user function and which should be returned again from the user function. The idea is that the user function modifies this variable according to what you want to achieve and then returns it. For "itemArrayProcFunc" this variable is $this->menuArr, for "IProcFunc" it is $this->I
1610 * @return mixed The processed $passVar
1611 * @access private
1612 * @todo Define visibility
1613 */
1614 public function userProcess($mConfKey, $passVar) {
1615 if ($this->mconf[$mConfKey]) {
1616 $funcConf = $this->mconf[$mConfKey . '.'];
1617 $funcConf['parentObj'] = $this;
1618 $passVar = $this->parent_cObj->callUserFunction($this->mconf[$mConfKey], $funcConf, $passVar);
1619 }
1620 return $passVar;
1621 }
1622
1623 /**
1624 * Creates the <A> tag parts for the current item (in $this->I, [A1] and [A2]) based on other information in this array (like $this->I['linkHREF'])
1625 *
1626 * @return void
1627 * @access private
1628 * @todo Define visibility
1629 */
1630 public function setATagParts() {
1631 $this->I['A1'] = '<a ' . \TYPO3\CMS\Core\Utility\GeneralUtility::implodeAttributes($this->I['linkHREF'], 1) . ' ' . $this->I['val']['ATagParams'] . $this->I['accessKey']['code'] . '>';
1632 $this->I['A2'] = '</a>';
1633 }
1634
1635 /**
1636 * Returns the title for the navigation
1637 *
1638 * @param string $title The current page title
1639 * @param string $nav_title The current value of the navigation title
1640 * @return string Returns the navigation title if it is NOT blank, otherwise the page title.
1641 * @access private
1642 * @todo Define visibility
1643 */
1644 public function getPageTitle($title, $nav_title) {
1645 return strcmp(trim($nav_title), '') ? $nav_title : $title;
1646 }
1647
1648 /**
1649 * Return MPvar string for entry $key in ->menuArr
1650 *
1651 * @param integer $key Pointer to element in ->menuArr
1652 * @param string Implode token.
1653 * @return string MP vars for element.
1654 * @see link()
1655 * @todo Define visibility
1656 */
1657 public function getMPvar($key) {
1658 if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1659 $localMP_array = $this->MP_array;
1660 // NOTICE: "_MP_PARAM" is allowed to be a commalist of PID pairs!
1661 if ($this->menuArr[$key]['_MP_PARAM']) {
1662 $localMP_array[] = $this->menuArr[$key]['_MP_PARAM'];
1663 }
1664 $MP_params = count($localMP_array) ? implode(',', $localMP_array) : '';
1665 return $MP_params;
1666 }
1667 }
1668
1669 /**
1670 * Returns where clause part to exclude 'not in menu' pages
1671 *
1672 * @return string where clause part.
1673 * @access private
1674 * @todo Define visibility
1675 */
1676 public function getDoktypeExcludeWhere() {
1677 return $this->doktypeExcludeList ? ' AND pages.doktype NOT IN (' . $this->doktypeExcludeList . ')' : '';
1678 }
1679
1680 /**
1681 * Returns an array of banned UIDs (from excludeUidList)
1682 *
1683 * @return array Array of banned UIDs
1684 * @access private
1685 * @todo Define visibility
1686 */
1687 public function getBannedUids() {
1688 $banUidArray = array();
1689 if (trim($this->conf['excludeUidList'])) {
1690 $banUidList = str_replace('current', $GLOBALS['TSFE']->page['uid'], $this->conf['excludeUidList']);
1691 $banUidArray = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $banUidList);
1692 }
1693 return $banUidArray;
1694 }
1695
1696 /**
1697 * Calls typolink to create menu item links.
1698 *
1699 * @param array $page Page record (uid points where to link to)
1700 * @param string $oTarget Target frame/window
1701 * @param boolean $no_cache TRUE if caching should be disabled
1702 * @param string $script Alternative script name
1703 * @param array $overrideArray Array to override values in $page
1704 * @param string $addParams Parameters to add to URL
1705 * @param array $typeOverride "type" value
1706 * @return array See linkData
1707 * @todo Define visibility
1708 */
1709 public function menuTypoLink($page, $oTarget, $no_cache, $script, $overrideArray = '', $addParams = '', $typeOverride = '') {
1710 $conf = array(
1711 'parameter' => is_array($overrideArray) && $overrideArray['uid'] ? $overrideArray['uid'] : $page['uid']
1712 );
1713 if ($typeOverride && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($typeOverride)) {
1714 $conf['parameter'] .= ',' . $typeOverride;
1715 }
1716 if ($addParams) {
1717 $conf['additionalParams'] = $addParams;
1718 }
1719 if ($no_cache) {
1720 $conf['no_cache'] = TRUE;
1721 }
1722 if ($oTarget) {
1723 $conf['target'] = $oTarget;
1724 }
1725 if ($page['sectionIndex_uid']) {
1726 $conf['section'] = $page['sectionIndex_uid'];
1727 }
1728 $this->parent_cObj->typoLink('|', $conf);
1729 $LD = $this->parent_cObj->lastTypoLinkLD;
1730 $LD['totalURL'] = $this->parent_cObj->lastTypoLinkUrl;
1731 return $LD;
1732 }
1733
1734 /**
1735 * Generates a list of content objects with sectionIndex enabled
1736 * available on a specific page
1737 *
1738 * Used for menus with sectionIndex enabled
1739 *
1740 * @param string $altSortField Alternative sorting field
1741 * @param integer $pid The page id to search for sections
1742 * @throws UnexpectedValueException if the query to fetch the content elements unexpectedly fails
1743 * @return array
1744 */
1745 protected function sectionIndex($altSortField, $pid = NULL) {
1746 $pid = intval($pid ? $pid : $this->id);
1747 $basePageRow = $this->sys_page->getPage($pid);
1748 if (!is_array($basePageRow)) {
1749 return array();
1750 }
1751 $configuration = $this->mconf['sectionIndex.'];
1752 $useColPos = 0;
1753 if (trim($configuration['useColPos']) !== '' || is_array($configuration['useColPos.'])) {
1754 $useColPos = $GLOBALS['TSFE']->cObj->stdWrap($configuration['useColPos'], $configuration['useColPos.']);
1755 $useColPos = intval($useColPos);
1756 }
1757 $selectSetup = array(
1758 'pidInList' => $pid,
1759 'orderBy' => $altSortField,
1760 'languageField' => 'sys_language_uid',
1761 'where' => $useColPos >= 0 ? 'colPos=' . $useColPos : ''
1762 );
1763 $resource = $this->parent_cObj->exec_getQuery('tt_content', $selectSetup);
1764 if (!$resource) {
1765 $message = 'SectionIndex: Query to fetch the content elements failed!';
1766 throw new \UnexpectedValueException($message, 1337334849);
1767 }
1768 $result = array();
1769 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($resource)) {
1770 $this->sys_page->versionOL('tt_content', $row);
1771 if ($GLOBALS['TSFE']->sys_language_contentOL && $basePageRow['_PAGES_OVERLAY_LANGUAGE']) {
1772 $row = $this->sys_page->getRecordOverlay('tt_content', $row, $basePageRow['_PAGES_OVERLAY_LANGUAGE'], $GLOBALS['TSFE']->sys_language_contentOL);
1773 }
1774 if ($this->mconf['sectionIndex.']['type'] !== 'all') {
1775 $doIncludeInSectionIndex = $row['sectionIndex'] >= 1;
1776 $doHeaderCheck = $this->mconf['sectionIndex.']['type'] === 'header';
1777 $isValidHeader = intval($row['header_layout']) !== 100 && trim($row['header']) !== '';
1778 if (!$doIncludeInSectionIndex || $doHeaderCheck && !$isValidHeader) {
1779 continue;
1780 }
1781 }
1782 if (is_array($row)) {
1783 $uid = $row['uid'];
1784 $result[$uid] = $basePageRow;
1785 $result[$uid]['title'] = $row['header'];
1786 $result[$uid]['nav_title'] = $row['header'];
1787 $result[$uid]['subtitle'] = $row['subheader'];
1788 $result[$uid]['starttime'] = $row['starttime'];
1789 $result[$uid]['endtime'] = $row['endtime'];
1790 $result[$uid]['fe_group'] = $row['fe_group'];
1791 $result[$uid]['media'] = $row['media'];
1792 $result[$uid]['header_layout'] = $row['header_layout'];
1793 $result[$uid]['bodytext'] = $row['bodytext'];
1794 $result[$uid]['image'] = $row['image'];
1795 $result[$uid]['sectionIndex_uid'] = $uid;
1796 }
1797 }
1798 $GLOBALS['TYPO3_DB']->sql_free_result($resource);
1799 return $result;
1800 }
1801
1802 }
1803
1804
1805 ?>