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