‪TYPO3CMS  ‪main
AbstractMenuContentObject.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\EventDispatcher\EventDispatcherInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use Psr\Log\LogLevel;
44 
53 {
57  protected int ‪$menuNumber = 1;
58 
64  protected ‪$entryLevel = 0;
65 
72 
76  protected ‪$alwaysActivePIDlist = [];
77 
83  public ‪$parent_cObj;
84 
90  protected ‪$MP_array = [];
91 
97  protected ‪$conf = [];
98 
104  protected ‪$mconf = [];
105 
109  protected ‪$sys_page;
110 
116  protected ‪$id;
117 
124  protected ‪$nextActive;
125 
131  protected ‪$menuArr;
132 
136  protected ‪$hash;
137 
141  protected ‪$result = [];
142 
149  protected ‪$rL_uidRegister;
150 
154  protected ‪$I;
155 
156  protected ServerRequestInterface ‪$request;
157 
161  protected array ‪$alternativeMenuTempArray = [];
162 
168  protected ‪$parentMenuArrItemKey;
169 
173  protected ‪$parentMenuArr;
174 
175  protected bool ‪$disableGroupAccessCheck = false;
176 
177  protected const ‪customItemStates = [
178  // IFSUB is TRUE if there exist submenu items to the current item
179  'IFSUB',
180  'ACT',
181  // ACTIFSUB is TRUE if there exist submenu items to the current item and the current item is active
182  'ACTIFSUB',
183  // CUR is TRUE if the current page equals the item here!
184  'CUR',
185  // CURIFSUB is TRUE if there exist submenu items to the current item and the current page equals the item here!
186  'CURIFSUB',
187  'USR',
188  'SPC',
189  'USERDEF1',
190  'USERDEF2',
191  ];
192 
205  public function ‪start($_, ‪$sys_page, ‪$id, ‪$conf, int ‪$menuNumber, $objSuffix = '', ?ServerRequestInterface ‪$request = null)
206  {
207  $tsfe = $this->‪getTypoScriptFrontendController();
208  $this->conf = (array)‪$conf;
209  $this->menuNumber = ‪$menuNumber;
210  $this->mconf = (array)‪$conf[$this->menuNumber . $objSuffix . '.'];
211  $this->request = ‪$request;
212  // Sets the internal vars. $sys_page MUST be the PageRepository object
213  if ($this->conf[$this->menuNumber . $objSuffix] && is_object(‪$sys_page)) {
214  $this->sys_page = ‪$sys_page;
215  // alwaysActivePIDlist initialized:
216  $this->conf['alwaysActivePIDlist'] = (string)$this->parent_cObj->stdWrapValue('alwaysActivePIDlist', $this->conf);
217  if (trim($this->conf['alwaysActivePIDlist'])) {
218  $this->alwaysActivePIDlist = GeneralUtility::intExplode(',', $this->conf['alwaysActivePIDlist']);
219  }
220  // includeNotInMenu initialized:
221  $this->conf['includeNotInMenu'] = $this->parent_cObj->stdWrapValue('includeNotInMenu', $this->conf, false);
222  // exclude doktypes that should not be shown in menu (e.g. backend user section)
223  if ($this->conf['excludeDoktypes'] ?? false) {
224  $this->excludedDoktypes = GeneralUtility::intExplode(',', (string)($this->conf['excludeDoktypes']));
225  }
226  // EntryLevel
227  $this->entryLevel = $this->parent_cObj->getKey(
228  $this->parent_cObj->stdWrapValue('entryLevel', $this->conf),
229  $tsfe->config['rootLine'] ?? []
230  );
231  // Set parent page: If $id not stated with start() then the base-id will be found from rootLine[$this->entryLevel]
232  // Called as the next level in a menu. It is assumed that $this->MP_array is set from parent menu.
233  if (‪$id) {
234  $this->id = (int)‪$id;
235  } else {
236  // This is a BRAND NEW menu, first level. So we take ID from rootline and also find MP_array (mount points)
237  $this->id = (int)($tsfe->config['rootLine'][$this->entryLevel]['uid'] ?? 0);
238 
239  // Traverse rootline to build MP_array of pages BEFORE the entryLevel
240  // (MP var for ->id is picked up in the next part of the code...)
241  foreach (($tsfe->config['rootLine'] ?? []) as ‪$entryLevel => $levelRec) {
242  // For overlaid mount points, set the variable right now:
243  if (($levelRec['_MP_PARAM'] ?? false) && ($levelRec['_MOUNT_OL'] ?? false)) {
244  $this->MP_array[] = $levelRec['_MP_PARAM'];
245  }
246 
247  // Break when entry level is reached:
248  if (‪$entryLevel >= $this->entryLevel) {
249  break;
250  }
251 
252  // For normal mount points, set the variable for next level.
253  if (!empty($levelRec['_MP_PARAM']) && empty($levelRec['_MOUNT_OL'])) {
254  $this->MP_array[] = $levelRec['_MP_PARAM'];
255  }
256  }
257  }
258  // Return FALSE if no page ID was set (thus no menu of subpages can be made).
259  if ($this->id <= 0) {
260  return false;
261  }
262  // Check if page is a mount point, and if so set id and MP_array
263  // (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...)
264  $mount_info = $this->sys_page->getMountPointInfo($this->id);
265  if (is_array($mount_info)) {
266  $this->MP_array[] = $mount_info['MPvar'];
267  $this->id = $mount_info['mount_pid'];
268  }
269  // Gather list of page uids in root line (for "isActive" evaluation). Also adds the MP params in the path so Mount Points are respected.
270  // (List is specific for this rootline, so it may be supplied from parent menus for speed...)
271  if ($this->rL_uidRegister === null) {
272  $this->rL_uidRegister = [];
273  $rl_MParray = [];
274  foreach (($tsfe->config['rootLine'] ?? []) as $v_rl) {
275  // For overlaid mount points, set the variable right now:
276  if (($v_rl['_MP_PARAM'] ?? false) && ($v_rl['_MOUNT_OL'] ?? false)) {
277  $rl_MParray[] = $v_rl['_MP_PARAM'];
278  }
279  // Add to register:
280  $this->rL_uidRegister[] = 'ITEM:' . $v_rl['uid'] .
281  (
282  !empty($rl_MParray)
283  ? ':' . implode(',', $rl_MParray)
284  : ''
285  );
286  // For normal mount points, set the variable for next level.
287  if (($v_rl['_MP_PARAM'] ?? false) && !($v_rl['_MOUNT_OL'] ?? false)) {
288  $rl_MParray[] = $v_rl['_MP_PARAM'];
289  }
290  }
291  }
292  // Set $directoryLevel so the following evaluation of the nextActive will not return
293  // an invalid value if .special=directory was set
294  $directoryLevel = 0;
295  if (($this->conf['special'] ?? '') === 'directory') {
296  $value = $this->parent_cObj->stdWrapValue('value', $this->conf['special.'] ?? [], null);
297  if ($value === '') {
298  $value = $tsfe->id;
299  }
300  $directoryLevel = $this->‪getRootlineLevel($tsfe->config['rootLine'], (string)$value);
301  }
302  // 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
303  // Notice: The automatic expansion of a menu is designed to work only when no "special" modes (except "directory") are used.
304  $startLevel = $directoryLevel ?: ‪$this->entryLevel;
305  $currentLevel = $startLevel + ‪$this->menuNumber;
306  if (is_array($tsfe->config['rootLine'][$currentLevel] ?? null)) {
307  $nextMParray = ‪$this->MP_array;
308  if (empty($nextMParray) && !($tsfe->config['rootLine'][$currentLevel]['_MOUNT_OL'] ?? false) && $currentLevel > 0) {
309  // Make sure to slide-down any mount point information (_MP_PARAM) to children records in the rootline
310  // otherwise automatic expansion will not work
311  $parentRecord = $tsfe->config['rootLine'][$currentLevel - 1] ?? [];
312  if (isset($parentRecord['_MP_PARAM'])) {
313  $nextMParray[] = $parentRecord['_MP_PARAM'];
314  }
315  }
316  // In overlay mode, add next level MPvars as well:
317  if ($tsfe->config['rootLine'][$currentLevel]['_MOUNT_OL'] ?? false) {
318  $nextMParray[] = $tsfe->config['rootLine'][$currentLevel]['_MP_PARAM'] ?? [];
319  }
320  $this->nextActive = ($tsfe->config['rootLine'][$currentLevel]['uid'] ?? 0) .
321  (
322  !empty($nextMParray)
323  ? ':' . implode(',', $nextMParray)
324  : ''
325  );
326  } else {
327  $this->nextActive = '';
328  }
329  return true;
330  }
331  $this->‪getTimeTracker()->setTSlogMessage('ERROR in menu', LogLevel::ERROR);
332  return false;
333  }
334 
341  public function ‪makeMenu()
342  {
343  if (!$this->id) {
344  return;
345  }
346 
347  $frontendController = $this->‪getTypoScriptFrontendController();
348  // Initializing showAccessRestrictedPages
349  $SAVED_where_groupAccess = '';
350  if ($this->mconf['showAccessRestrictedPages'] ?? false) {
351  $this->disableGroupAccessCheck = true;
352  }
353 
354  $menuItems = $this->‪prepareMenuItems();
355 
356  $c = 0;
357  $c_b = 0;
358 
359  $minItems = (int)(($this->mconf['minItems'] ?? 0) ?: ($this->conf['minItems'] ?? 0));
360  $maxItems = (int)(($this->mconf['maxItems'] ?? 0) ?: ($this->conf['maxItems'] ?? 0));
361  $begin = $this->parent_cObj->calc(($this->mconf['begin'] ?? 0) ?: ($this->conf['begin'] ?? 0));
362  $minItemsConf = $this->mconf['minItems.'] ?? $this->conf['minItems.'] ?? null;
363  $minItems = is_array($minItemsConf) ? $this->parent_cObj->stdWrap((string)$minItems, $minItemsConf) : $minItems;
364  $maxItemsConf = $this->mconf['maxItems.'] ?? $this->conf['maxItems.'] ?? null;
365  $maxItems = is_array($maxItemsConf) ? $this->parent_cObj->stdWrap((string)$maxItems, $maxItemsConf) : $maxItems;
366  $beginConf = $this->mconf['begin.'] ?? $this->conf['begin.'] ?? null;
367  $begin = is_array($beginConf) ? $this->parent_cObj->stdWrap((string)$begin, $beginConf) : $begin;
368  $this->menuArr = [];
369  foreach ($menuItems as &$data) {
370  $data['isSpacer'] = ($data['isSpacer'] ?? false) || (int)($data['doktype'] ?? 0) === ‪PageRepository::DOKTYPE_SPACER || ($data['ITEM_STATE'] ?? '') === 'SPC';
371  }
372  $menuItems = $this->‪removeInaccessiblePages($menuItems);
373  // Fill in the menuArr with elements that should go into the menu
374  foreach ($menuItems as $menuItem) {
375  $c_b++;
376  // If the beginning item has been reached, add the items.
377  if ($begin <= $c_b) {
378  $this->menuArr[$c] = $menuItem;
379  $c++;
380  if ($maxItems && $c >= $maxItems) {
381  break;
382  }
383  }
384  }
385  // Fill in fake items, if min-items is set.
386  if ($minItems) {
387  while ($c < $minItems) {
388  $this->menuArr[$c] = [
389  'title' => '...',
390  'uid' => $frontendController->id,
391  ];
392  $c++;
393  }
394  }
395  // Passing the menuArr through a user defined function:
396  if ($this->mconf['itemArrayProcFunc'] ?? false) {
397  $this->menuArr = $this->‪userProcess('itemArrayProcFunc', $this->menuArr);
398  }
399  // Setting number of menu items
400  $frontendController->register['count_menuItems'] = count($this->menuArr);
401  $this->‪generate();
402  // End showAccessRestrictedPages
403  if ($this->mconf['showAccessRestrictedPages'] ?? false) {
404  $this->disableGroupAccessCheck = false;
405  }
406  }
407 
414  public function ‪generate()
415  {
416  $itemConfiguration = [];
417  $splitCount = count($this->menuArr);
418  if ($splitCount) {
419  $itemConfiguration = $this->‪processItemStates($splitCount);
420  }
421  $this->result = $itemConfiguration;
422  }
423 
427  public function ‪writeMenu()
428  {
429  return '';
430  }
431 
435  protected function ‪removeInaccessiblePages(array $pages): array
436  {
437  $banned = $this->‪getBannedUids();
438  $filteredPages = [];
439  foreach ($pages as $aPage) {
440  $isSpacerPage = ((int)($aPage['doktype'] ?? 0) === ‪PageRepository::DOKTYPE_SPACER) || ($aPage['isSpacer'] ?? false);
441  if ($this->‪filterMenuPages($aPage, $banned, $isSpacerPage)) {
442  $filteredPages[] = $aPage;
443  }
444  }
445  $event = new FilterMenuItemsEvent(
446  $pages,
447  $filteredPages,
448  $this->mconf,
449  $this->conf,
450  $banned,
451  $this->excludedDoktypes,
452  $this->‪getCurrentSite(),
453  $this->‪getTypoScriptFrontendController()->getContext(),
455  );
456  $event = GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch($event);
457  return $event->getFilteredMenuItems();
458  }
459 
465  protected function ‪prepareMenuItems()
466  {
467  $menuItems = [];
468  $alternativeSortingField = trim($this->mconf['alternativeSortingField'] ?? '') ?: 'sorting';
469 
470  // Additional where clause, usually starts with AND (as usual with all additionalWhere functionality in TS)
471  $additionalWhere = $this->parent_cObj->stdWrapValue('additionalWhere', $this->mconf);
472  $additionalWhere .= $this->‪getDoktypeExcludeWhere();
473 
474  // ... only for the FIRST level of a HMENU
475  if ($this->menuNumber == 1 && ($this->conf['special'] ?? false)) {
476  $value = (string)$this->parent_cObj->stdWrapValue('value', $this->conf['special.'] ?? [], null);
477  switch ($this->conf['special']) {
478  case 'userfunction':
479  $menuItems = $this->‪prepareMenuItemsForUserSpecificMenu($value, $alternativeSortingField);
480  break;
481  case 'language':
482  $menuItems = $this->‪prepareMenuItemsForLanguageMenu($value);
483  break;
484  case 'directory':
485  $menuItems = $this->‪prepareMenuItemsForDirectoryMenu($value, $alternativeSortingField);
486  break;
487  case 'list':
488  $menuItems = $this->‪prepareMenuItemsForListMenu($value);
489  break;
490  case 'updated':
491  $menuItems = $this->‪prepareMenuItemsForUpdatedMenu(
492  $value,
493  $this->mconf['alternativeSortingField'] ?? ''
494  );
495  break;
496  case 'keywords':
497  $menuItems = $this->‪prepareMenuItemsForKeywordsMenu(
498  $value,
499  $this->mconf['alternativeSortingField'] ?? ''
500  );
501  break;
502  case 'categories':
503  $categoryMenuUtility = GeneralUtility::makeInstance(CategoryMenuUtility::class);
504  $menuItems = $categoryMenuUtility->collectPages($value, $this->conf['special.'], $this);
505  break;
506  case 'rootline':
507  $menuItems = $this->‪prepareMenuItemsForRootlineMenu();
508  break;
509  case 'browse':
510  $menuItems = $this->‪prepareMenuItemsForBrowseMenu($value, $alternativeSortingField, $additionalWhere);
511  break;
512  }
513  if ($this->mconf['sectionIndex'] ?? false) {
514  $sectionIndexes = [];
515  foreach ($menuItems as $page) {
516  $sectionIndexes = $sectionIndexes + $this->‪sectionIndex($alternativeSortingField, $page['uid']);
517  }
518  $menuItems = $sectionIndexes;
519  }
520  } elseif ($this->alternativeMenuTempArray !== []) {
521  // Setting $menuItems array if not level 1.
523  } elseif ($this->mconf['sectionIndex'] ?? false) {
524  $menuItems = $this->‪sectionIndex($alternativeSortingField);
525  } else {
526  // Default: Gets a hierarchical menu based on subpages of $this->id
527  $subMenuDecision = $this->‪getRuntimeCache()->get($this->‪getCacheIdentifierForSubMenuDecision($this->id));
528  if (!isset($subMenuDecision['result']) || $subMenuDecision['result'] === true) {
529  $menuItems = $this->sys_page->getMenu($this->id, '*', $alternativeSortingField, $additionalWhere, true, $this->disableGroupAccessCheck);
530  }
531  }
532  return $menuItems;
533  }
534 
542  protected function ‪prepareMenuItemsForUserSpecificMenu($specialValue, $sortingField)
543  {
544  $menuItems = $this->parent_cObj->callUserFunction(
545  $this->conf['special.']['userFunc'],
546  array_merge($this->conf['special.'], ['value' => $specialValue, '_altSortField' => $sortingField]),
547  ''
548  );
549  return is_array($menuItems) ? $menuItems : [];
550  }
551 
558  protected function ‪prepareMenuItemsForLanguageMenu($specialValue)
559  {
560  $menuItems = [];
561  // Getting current page record NOT overlaid by any translation:
562  $tsfe = $this->‪getTypoScriptFrontendController();
563  $currentPageWithNoOverlay = ($tsfe->page['_TRANSLATION_SOURCE'] ?? null)?->toArray(true) ?? $tsfe->page;
564 
565  ‪$languages = $this->‪getCurrentSite()->getLanguages();
566  if ($specialValue === 'auto') {
567  $languageItems = array_keys(‪$languages);
568  } else {
569  $languageItems = GeneralUtility::intExplode(',', $specialValue);
570  }
571 
572  $tsfe->register['languages_HMENU'] = implode(',', $languageItems);
573 
574  $currentLanguageId = $this->‪getCurrentLanguageAspect()->getId();
575 
576  // @todo Fetch all language overlays in a single query
577  foreach ($languageItems as $sUid) {
578  // Find overlay record:
579  if ($sUid) {
581  $pageRepository = $this->‪buildPageRepository($languageAspect);
582  $lRecs = $pageRepository->getPageOverlay($currentPageWithNoOverlay, $languageAspect);
583  // getPageOverlay() might return the original record again, if so this is emptied
584  // this should be fixed in PageRepository in the future.
585  if (!empty($lRecs) && !isset($lRecs['_PAGES_OVERLAY'])) {
586  $lRecs = [];
587  }
588  } else {
589  $lRecs = [];
590  }
591  // Checking if the "disabled" state should be set.
592  $pageTranslationVisibility = new PageTranslationVisibility((int)($currentPageWithNoOverlay['l18n_cfg'] ?? 0));
593  if ($pageTranslationVisibility->shouldHideTranslationIfNoTranslatedRecordExists() && $sUid &&
594  empty($lRecs) || $pageTranslationVisibility->shouldBeHiddenInDefaultLanguage() &&
595  (!$sUid || empty($lRecs)) ||
596  !($this->conf['special.']['normalWhenNoLanguage'] ?? false) && $sUid && empty($lRecs)
597  ) {
598  $iState = $currentLanguageId === $sUid ? 'USERDEF2' : 'USERDEF1';
599  } else {
600  $iState = $currentLanguageId === $sUid ? 'ACT' : 'NO';
601  }
602  // Adding menu item:
603  $menuItems[] = array_merge(
604  array_merge($currentPageWithNoOverlay, $lRecs),
605  [
606  '_PAGES_OVERLAY_REQUESTEDLANGUAGE' => $sUid,
607  'ITEM_STATE' => $iState,
608  '_ADD_GETVARS' => $this->conf['addQueryString'] ?? false,
609  '_SAFE' => true,
610  ]
611  );
612  }
613  return $menuItems;
614  }
615 
620  protected function ‪buildPageRepository(‪LanguageAspect $languageAspect = null): ‪PageRepository
621  {
622  // clone global context object (singleton)
623  $context = clone GeneralUtility::makeInstance(Context::class);
624  $context->setAspect(
625  'language',
626  $languageAspect ?? GeneralUtility::makeInstance(LanguageAspect::class)
627  );
628  return GeneralUtility::makeInstance(
629  PageRepository::class,
630  $context
631  );
632  }
633 
641  protected function ‪prepareMenuItemsForDirectoryMenu($specialValue, $sortingField)
642  {
643  $tsfe = $this->‪getTypoScriptFrontendController();
644  $menuItems = [];
645  if ($specialValue == '') {
646  $specialValue = $tsfe->id;
647  }
648  $items = GeneralUtility::intExplode(',', (string)$specialValue);
649  $pageLinkBuilder = GeneralUtility::makeInstance(PageLinkBuilder::class, $this->parent_cObj);
650  foreach ($items as ‪$id) {
651  $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps(‪$id);
652  // Checking if a page is a mount page and if so, change the ID and set the MP var properly.
653  $mount_info = $this->sys_page->getMountPointInfo(‪$id);
654  if (is_array($mount_info)) {
655  if ($mount_info['overlay']) {
656  // Overlays should already have their full MPvars calculated:
657  $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps((int)$mount_info['mount_pid']);
658  $MP = $MP ?: $mount_info['MPvar'];
659  } else {
660  $MP = ($MP ? $MP . ',' : '') . $mount_info['MPvar'];
661  }
662  ‪$id = $mount_info['mount_pid'];
663  }
664  $subPages = $this->sys_page->getMenu(‪$id, '*', $sortingField, '', true, $this->disableGroupAccessCheck);
665  foreach ($subPages as $row) {
666  // Add external MP params
667  if ($MP) {
668  $row['_MP_PARAM'] = $MP . (($row['_MP_PARAM'] ?? '') ? ',' . $row['_MP_PARAM'] : '');
669  }
670  $menuItems[] = $row;
671  }
672  }
673 
674  return $menuItems;
675  }
676 
683  protected function ‪prepareMenuItemsForListMenu($specialValue)
684  {
685  $menuItems = [];
686  if ($specialValue == '') {
687  $specialValue = ‪$this->id;
688  }
689  $pageIds = GeneralUtility::intExplode(',', (string)$specialValue);
690  ‪$disableGroupAccessCheck = !empty($this->mconf['showAccessRestrictedPages']);
691  $pageRecords = $this->sys_page->getMenuForPages($pageIds, '*', 'sorting', '', true, ‪$disableGroupAccessCheck);
692  // After fetching the page records, restore the initial order by using the page id list as arrays keys and
693  // replace them with the resolved page records. The id list is cleaned up first, since ids might be invalid.
694  $pageRecords = array_replace(
695  array_flip(array_intersect(array_values($pageIds), array_keys($pageRecords))),
696  $pageRecords
697  );
698  $pageLinkBuilder = GeneralUtility::makeInstance(PageLinkBuilder::class, $this->parent_cObj);
699  foreach ($pageRecords as $row) {
700  $pageId = (int)$row['uid'];
701  $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps($pageId);
702  // Keep mount point?
703  $mount_info = $this->sys_page->getMountPointInfo($pageId, $row);
704  // $pageId is a valid mount point
705  if (is_array($mount_info) && $mount_info['overlay']) {
706  $mountedPageId = (int)$mount_info['mount_pid'];
707  // Using "getPage" is OK since we need the check for enableFields
708  // AND for type 2 of mount pids we DO require a doktype < 200!
709  $mountedPageRow = $this->sys_page->getPage($mountedPageId, ‪$disableGroupAccessCheck);
710  if (empty($mountedPageRow)) {
711  // If the mount point could not be fetched with respect to
712  // enableFields, the page should not become a part of the menu!
713  continue;
714  }
715  $row = $mountedPageRow;
716  $row['_MP_PARAM'] = $mount_info['MPvar'];
717  // Overlays should already have their full MPvars calculated, that's why we unset the
718  // existing $row['_MP_PARAM'], as the full $MP will be added again below
719  $MP = $pageLinkBuilder->getMountPointParameterFromRootPointMaps($mountedPageId);
720  if ($MP) {
721  unset($row['_MP_PARAM']);
722  }
723  }
724  if ($MP) {
725  $row['_MP_PARAM'] = $MP . ($row['_MP_PARAM'] ? ',' . $row['_MP_PARAM'] : '');
726  }
727  $menuItems[] = $row;
728  }
729  return $menuItems;
730  }
731 
739  protected function ‪prepareMenuItemsForUpdatedMenu($specialValue, $sortingField)
740  {
741  $tsfe = $this->‪getTypoScriptFrontendController();
742  $menuItems = [];
743  if ($specialValue == '') {
744  $specialValue = $tsfe->id;
745  }
746  $items = GeneralUtility::intExplode(',', (string)$specialValue);
747  if (‪MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'] ?? null)) {
748  $depth = ‪MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 1, 20);
749  } else {
750  $depth = 20;
751  }
752  // Max number of items
753  $limit = ‪MathUtility::forceIntegerInRange(($this->conf['special.']['limit'] ?? 0), 0, 100);
754  $maxAge = (int)($this->parent_cObj->calc($this->conf['special.']['maxAge'] ?? 0));
755  if (!$limit) {
756  $limit = 10;
757  }
758  // 'auto', 'manual', 'tstamp'
759  $mode = $this->conf['special.']['mode'] ?? '';
760  // Get id's
761  $beginAtLevel = ‪MathUtility::forceIntegerInRange(($this->conf['special.']['beginAtLevel'] ?? 0), 0, 100);
762  $pageIds = [];
763  foreach ($items as ‪$id) {
764  // Exclude the current ID if beginAtLevel is > 0
765  if ($beginAtLevel > 0) {
766  $pageIds = array_merge($pageIds, $this->sys_page->getDescendantPageIdsRecursive(‪$id, $depth - 1 + $beginAtLevel, $beginAtLevel - 1));
767  } else {
768  $pageIds = array_merge($pageIds, [‪$id], $this->sys_page->getDescendantPageIdsRecursive(‪$id, $depth - 1 + $beginAtLevel, $beginAtLevel - 1));
769  }
770  }
771  // Get sortField (mode)
772  $sortField = $this->‪getMode($mode);
773 
774  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages');
775  $extraWhere = ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->‪getDoktypeExcludeWhere();
776  if ($this->conf['special.']['excludeNoSearchPages'] ?? false) {
777  $extraWhere .= sprintf(' AND %s=%s', $connection->quoteIdentifier('pages.no_search'), $connection->quote(0, ‪Connection::PARAM_INT));
778  }
779  if ($maxAge > 0) {
780  $extraWhere .= sprintf(' AND %s>%s', $connection->quoteIdentifier($sortField), $connection->quote((‪$GLOBALS['SIM_ACCESS_TIME'] - $maxAge), ‪Connection::PARAM_INT));
781  }
782  $extraWhere = sprintf('%s>=%s', $connection->quoteIdentifier($sortField), $connection->quote(0, ‪Connection::PARAM_INT)) . $extraWhere;
783 
784  $i = 0;
785  $pageRecords = $this->sys_page->getMenuForPages($pageIds, '*', $sortingField ?: $sortField . ' DESC', $extraWhere, true, $this->disableGroupAccessCheck);
786  foreach ($pageRecords as $row) {
787  // Build a custom LIMIT clause as "getMenuForPages()" does not support this
788  if (++$i > $limit) {
789  continue;
790  }
791  $menuItems[$row['uid']] = $row;
792  }
793 
794  return $menuItems;
795  }
796 
804  protected function ‪prepareMenuItemsForKeywordsMenu($specialValue, $sortingField)
805  {
806  $tsfe = $this->‪getTypoScriptFrontendController();
807  $menuItems = [];
808  [$specialValue] = GeneralUtility::intExplode(',', $specialValue);
809  if (!$specialValue) {
810  $specialValue = $tsfe->id;
811  }
812  if (($this->conf['special.']['setKeywords'] ?? false) || ($this->conf['special.']['setKeywords.'] ?? false)) {
813  $kw = (string)$this->parent_cObj->stdWrapValue('setKeywords', $this->conf['special.'] ?? []);
814  } else {
815  // The page record of the 'value'.
816  $value_rec = $this->sys_page->getPage($specialValue);
817  $kfieldSrc = ($this->conf['special.']['keywordsField.']['sourceField'] ?? false) ? $this->conf['special.']['keywordsField.']['sourceField'] : 'keywords';
818  // keywords.
819  $kw = trim($this->parent_cObj->keywords($value_rec[$kfieldSrc] ?? ''));
820  }
821  // *'auto', 'manual', 'tstamp'
822  $mode = $this->conf['special.']['mode'] ?? '';
823  $sortField = $this->‪getMode($mode);
824  // Depth, limit, extra where
825  if (‪MathUtility::canBeInterpretedAsInteger($this->conf['special.']['depth'] ?? null)) {
826  $depth = ‪MathUtility::forceIntegerInRange($this->conf['special.']['depth'], 0, 20);
827  } else {
828  $depth = 20;
829  }
830  // Max number of items
831  $limit = ‪MathUtility::forceIntegerInRange(($this->conf['special.']['limit'] ?? 0), 0, 100);
832  // Start point
833  $eLevel = $this->parent_cObj->getKey(
834  $this->parent_cObj->stdWrapValue('entryLevel', $this->conf['special.'] ?? []),
835  $tsfe->config['rootLine'] ?? []
836  );
837  $startUid = (int)($tsfe->config['rootLine'][$eLevel]['uid'] ?? 0);
838  // Which field is for keywords
839  $kfield = 'keywords';
840  if ($this->conf['special.']['keywordsField'] ?? false) {
841  [$kfield] = explode(' ', trim($this->conf['special.']['keywordsField']));
842  }
843  // If there are keywords and the startUid is present
844  if ($kw && $startUid) {
845  $bA = ‪MathUtility::forceIntegerInRange(($this->conf['special.']['beginAtLevel'] ?? 0), 0, 100);
846  $id_list = $this->sys_page->getDescendantPageIdsRecursive($startUid, $depth - 1 + $bA, $bA - 1);
847  $id_list = array_merge([(int)$startUid], $id_list);
848  $kwArr = GeneralUtility::trimExplode(',', $kw, true);
849  $keyWordsWhereArr = [];
850  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
851  foreach ($kwArr as $word) {
852  $keyWordsWhereArr[] = $queryBuilder->expr()->like(
853  $kfield,
854  $queryBuilder->createNamedParameter(
855  '%' . $queryBuilder->escapeLikeWildcards($word) . '%'
856  )
857  );
858  }
859  $queryBuilder
860  ->select('*')
861  ->from('pages')
862  ->where(
863  $queryBuilder->expr()->in(
864  'uid',
865  $id_list
866  ),
867  $queryBuilder->expr()->neq(
868  'uid',
869  $queryBuilder->createNamedParameter($specialValue, ‪Connection::PARAM_INT)
870  )
871  );
872 
873  if (!empty($keyWordsWhereArr)) {
874  $queryBuilder->andWhere($queryBuilder->expr()->or(...$keyWordsWhereArr));
875  }
876 
877  if (!empty($this->excludedDoktypes)) {
878  $queryBuilder->andWhere(
879  $queryBuilder->expr()->notIn(
880  'pages.doktype',
881  $this->excludedDoktypes
882  )
883  );
884  }
885 
886  if (!$this->conf['includeNotInMenu']) {
887  $queryBuilder->andWhere($queryBuilder->expr()->eq('pages.nav_hide', 0));
888  }
889 
890  if ($this->conf['special.']['excludeNoSearchPages'] ?? false) {
891  $queryBuilder->andWhere($queryBuilder->expr()->eq('pages.no_search', 0));
892  }
893 
894  if ($limit > 0) {
895  $queryBuilder->setMaxResults($limit);
896  }
897 
898  if ($sortingField) {
899  $queryBuilder->orderBy($sortingField);
900  } else {
901  $queryBuilder->orderBy($sortField, 'desc');
902  }
903 
904  ‪$result = $queryBuilder->executeQuery();
905  while ($row = ‪$result->fetchAssociative()) {
906  $this->sys_page->versionOL('pages', $row, true);
907  if (is_array($row)) {
908  $menuItems[$row['uid']] = $this->sys_page->getPageOverlay($row);
909  }
910  }
911  }
912 
913  return $menuItems;
914  }
915 
921  protected function ‪prepareMenuItemsForRootlineMenu()
922  {
923  $tsfe = $this->‪getTypoScriptFrontendController();
924  $menuItems = [];
925  $range = (string)$this->parent_cObj->stdWrapValue('range', $this->conf['special.'] ?? []);
926  $begin_end = explode('|', $range);
927  $begin_end[0] = (int)$begin_end[0];
928  if (!‪MathUtility::canBeInterpretedAsInteger($begin_end[1] ?? '')) {
929  $begin_end[1] = -1;
930  }
931  $beginKey = $this->parent_cObj->getKey($begin_end[0], $tsfe->config['rootLine'] ?? []);
932  $endKey = $this->parent_cObj->getKey($begin_end[1], $tsfe->config['rootLine'] ?? []);
933  if ($endKey < $beginKey) {
934  $endKey = $beginKey;
935  }
936  $rl_MParray = [];
937  foreach (($tsfe->config['rootLine'] ?? []) as $k_rl => $v_rl) {
938  // For overlaid mount points, set the variable right now:
939  if (($v_rl['_MP_PARAM'] ?? false) && ($v_rl['_MOUNT_OL'] ?? false)) {
940  $rl_MParray[] = $v_rl['_MP_PARAM'];
941  }
942  // Traverse rootline:
943  if ($k_rl >= $beginKey && $k_rl <= $endKey) {
944  $temp_key = $k_rl;
945  $menuItems[$temp_key] = $this->sys_page->getPage($v_rl['uid']);
946  if (!empty($menuItems[$temp_key])) {
947  // If there are no specific target for the page, put the level specific target on.
948  if (!$menuItems[$temp_key]['target']) {
949  $menuItems[$temp_key]['target'] = $this->conf['special.']['targets.'][$k_rl] ?? '';
950  $menuItems[$temp_key]['_MP_PARAM'] = implode(',', $rl_MParray);
951  }
952  } else {
953  unset($menuItems[$temp_key]);
954  }
955  }
956  // For normal mount points, set the variable for next level.
957  if (($v_rl['_MP_PARAM'] ?? false) && !($v_rl['_MOUNT_OL'] ?? false)) {
958  $rl_MParray[] = $v_rl['_MP_PARAM'];
959  }
960  }
961  // Reverse order of elements (e.g. "1,2,3,4" gets "4,3,2,1"):
962  if (isset($this->conf['special.']['reverseOrder']) && $this->conf['special.']['reverseOrder']) {
963  $menuItems = array_reverse($menuItems);
964  }
965  return $menuItems;
966  }
967 
976  protected function ‪prepareMenuItemsForBrowseMenu($specialValue, $sortingField, $additionalWhere)
977  {
978  $tsfe = $this->‪getTypoScriptFrontendController();
979  $menuItems = [];
980  [$specialValue] = GeneralUtility::intExplode(',', $specialValue);
981  if (!$specialValue) {
982  $specialValue = $this->‪getTypoScriptFrontendController()->page['uid'];
983  }
984  // Will not work out of rootline
985  if ($specialValue != ($tsfe->config['rootLine'][0]['uid'] ?? null)) {
986  $recArr = [];
987  // The page record of the 'value'.
988  $value_rec = $this->sys_page->getPage($specialValue, $this->disableGroupAccessCheck);
989  // 'up' page cannot be outside rootline
990  if ($value_rec['pid']) {
991  // The page record of 'up'.
992  $recArr['up'] = $this->sys_page->getPage($value_rec['pid'], $this->disableGroupAccessCheck);
993  }
994  // If the 'up' item was NOT level 0 in rootline...
995  if (($recArr['up']['pid'] ?? 0) && $value_rec['pid'] != ($tsfe->config['rootLine'][0]['uid'] ?? null)) {
996  // The page record of "index".
997  $recArr['index'] = $this->sys_page->getPage($recArr['up']['pid']);
998  }
999  // check if certain pages should be excluded
1000  $additionalWhere .= ($this->conf['includeNotInMenu'] ? '' : ' AND pages.nav_hide=0') . $this->‪getDoktypeExcludeWhere();
1001  if ($this->conf['special.']['excludeNoSearchPages'] ?? false) {
1002  $additionalWhere .= ' AND pages.no_search=0';
1003  }
1004  // prev / next is found
1005  $prevnext_menu = $this->‪removeInaccessiblePages($this->sys_page->getMenu($value_rec['pid'], '*', $sortingField, $additionalWhere, true, $this->disableGroupAccessCheck));
1006  ‪$nextActive = false;
1007  foreach ($prevnext_menu as $k_b => $v_b) {
1008  if (‪$nextActive) {
1009  $recArr['next'] = $v_b;
1010  ‪$nextActive = false;
1011  }
1012  if ($v_b['uid'] == $specialValue) {
1013  if (isset($lastKey)) {
1014  $recArr['prev'] = $prevnext_menu[$lastKey];
1015  }
1016  ‪$nextActive = true;
1017  }
1018  $lastKey = $k_b;
1019  }
1020  unset($lastKey);
1021 
1022  $recArr['first'] = reset($prevnext_menu);
1023  $recArr['last'] = end($prevnext_menu);
1024  // prevsection / nextsection is found
1025  // You can only do this, if there is a valid page two levels up!
1026  if (!empty($recArr['index']['uid'])) {
1027  $prevnextsection_menu = $this->‪removeInaccessiblePages($this->sys_page->getMenu($recArr['index']['uid'], '*', $sortingField, $additionalWhere, true, $this->disableGroupAccessCheck));
1028  ‪$nextActive = false;
1029  foreach ($prevnextsection_menu as $k_b => $v_b) {
1030  if (‪$nextActive) {
1031  $sectionRec_temp = $this->‪removeInaccessiblePages($this->sys_page->getMenu($v_b['uid'], '*', $sortingField, $additionalWhere, true, $this->disableGroupAccessCheck));
1032  if (!empty($sectionRec_temp)) {
1033  $recArr['nextsection'] = reset($sectionRec_temp);
1034  $recArr['nextsection_last'] = end($sectionRec_temp);
1035  ‪$nextActive = false;
1036  }
1037  }
1038  if ($v_b['uid'] == $value_rec['pid']) {
1039  if (isset($lastKey)) {
1040  $sectionRec_temp = $this->‪removeInaccessiblePages($this->sys_page->getMenu($prevnextsection_menu[$lastKey]['uid'], '*', $sortingField, $additionalWhere, true, $this->disableGroupAccessCheck));
1041  if (!empty($sectionRec_temp)) {
1042  $recArr['prevsection'] = reset($sectionRec_temp);
1043  $recArr['prevsection_last'] = end($sectionRec_temp);
1044  }
1045  }
1046  ‪$nextActive = true;
1047  }
1048  $lastKey = $k_b;
1049  }
1050  unset($lastKey);
1051  }
1052  if ($this->conf['special.']['items.']['prevnextToSection'] ?? false) {
1053  if (!is_array($recArr['prev'] ?? false) && is_array($recArr['prevsection_last'] ?? false)) {
1054  $recArr['prev'] = $recArr['prevsection_last'];
1055  }
1056  if (!is_array($recArr['next'] ?? false) && is_array($recArr['nextsection'] ?? false)) {
1057  $recArr['next'] = $recArr['nextsection'];
1058  }
1059  }
1060  $items = explode('|', $this->conf['special.']['items']);
1061  $c = 0;
1062  foreach ($items as $k_b => $v_b) {
1063  $v_b = strtolower(trim($v_b));
1064  if ((int)($this->conf['special.'][$v_b . '.']['uid'] ?? false)) {
1065  $recArr[$v_b] = $this->sys_page->getPage((int)$this->conf['special.'][$v_b . '.']['uid'], $this->disableGroupAccessCheck);
1066  }
1067  if (is_array($recArr[$v_b] ?? false)) {
1068  $menuItems[$c] = $recArr[$v_b];
1069  if ($this->conf['special.'][$v_b . '.']['target'] ?? false) {
1070  $menuItems[$c]['target'] = $this->conf['special.'][$v_b . '.']['target'];
1071  }
1072  foreach ((array)($this->conf['special.'][$v_b . '.']['fields.'] ?? []) as $fk => $val) {
1073  $menuItems[$c][$fk] = $val;
1074  }
1075  $c++;
1076  }
1077  }
1078  }
1079  return $menuItems;
1080  }
1081 
1093  public function ‪filterMenuPages(&$data, $banUidArray, $isSpacerPage)
1094  {
1095  if ($data['_SAFE'] ?? false) {
1096  return true;
1097  }
1098  // If the spacer-function is not enabled, spacers will not enter the $menuArr
1099  if (!($this->mconf['SPC'] ?? false) && $isSpacerPage) {
1100  return false;
1101  }
1102  // Page may not be a 'Backend User Section' or any other excluded doktype
1103  if (in_array((int)($data['doktype'] ?? 0), $this->excludedDoktypes, true)) {
1104  return false;
1105  }
1106  $languageId = $this->‪getCurrentLanguageAspect()->getId();
1107  // PageID should not be banned (check for default language pages as well)
1108  if (($data['_PAGES_OVERLAY_UID'] ?? 0) > 0 && in_array((int)($data['_PAGES_OVERLAY_UID'] ?? 0), $banUidArray, true)) {
1109  return false;
1110  }
1111  if (in_array((int)($data['uid'] ?? 0), $banUidArray, true)) {
1112  return false;
1113  }
1114  // If the page is hide in menu, but the menu does not include them do not show the page
1115  if (($data['nav_hide'] ?? false) && !($this->conf['includeNotInMenu'] ?? false)) {
1116  return false;
1117  }
1118  // Checking if a page should be shown in the menu depending on whether a translation exists or if the default language is disabled
1119  if (!$this->sys_page->isPageSuitableForLanguage($data, $this->getCurrentLanguageAspect())) {
1120  return false;
1121  }
1122  // Checking if the link should point to the default language so links to non-accessible pages will not happen
1123  if ($languageId > 0 && !empty($this->conf['protectLvar'])) {
1124  $pageTranslationVisibility = new PageTranslationVisibility((int)($data['l18n_cfg'] ?? 0));
1125  if ($this->conf['protectLvar'] === 'all' || $pageTranslationVisibility->shouldHideTranslationIfNoTranslatedRecordExists()) {
1126  $olRec = $this->sys_page->getPageOverlay($data['uid'], $languageId);
1127  if (empty($olRec)) {
1128  // If no page translation record then page can NOT be accessed in
1129  // the language pointed to, therefore we protect the link by linking to the default language
1130  $data['_PAGES_OVERLAY_REQUESTEDLANGUAGE'] = '0';
1131  }
1132  }
1133  }
1134  return true;
1135  }
1136 
1150  protected function ‪processItemStates($splitCount)
1151  {
1152  // Prepare normal settings
1153  if (!is_array($this->mconf['NO.'] ?? null) && $this->mconf['NO']) {
1154  // Setting a blank array if NO=1 and there are no properties.
1155  $this->mconf['NO.'] = [];
1156  }
1157  $typoScriptService = GeneralUtility::makeInstance(TypoScriptService::class);
1158  $NOconf = $typoScriptService->explodeConfigurationForOptionSplit((array)$this->mconf['NO.'], $splitCount);
1159 
1160  // Prepare custom states settings, overriding normal settings
1161  foreach (self::customItemStates as $state) {
1162  if (empty($this->mconf[$state])) {
1163  continue;
1164  }
1165  $customConfiguration = null;
1166  foreach ($NOconf as $key => $val) {
1167  if ($this->‪isItemState($state, $key)) {
1168  // if this is the first element of type $state, we must generate the custom configuration.
1169  if ($customConfiguration === null) {
1170  $customConfiguration = $typoScriptService->explodeConfigurationForOptionSplit((array)$this->mconf[$state . '.'], $splitCount);
1171  }
1172  // Substitute normal with the custom (e.g. IFSUB)
1173  if (isset($customConfiguration[$key])) {
1174  $NOconf[$key] = $customConfiguration[$key];
1175  }
1176  }
1177  }
1178  }
1179 
1180  return $NOconf;
1181  }
1182 
1191  protected function ‪link($key, $altTarget, $typeOverride)
1192  {
1193  $runtimeCache = $this->‪getRuntimeCache();
1194  $MP_var = $this->‪getMPvar($key);
1195  $cacheId = 'menu-generated-links-' . md5(
1196  $key
1197  . ($altTarget ?: ($this->mconf['target'] ?? '') . (isset($this->mconf['target.']) ? json_encode($this->mconf['target.']) : ''))
1198  . $typeOverride
1199  . $MP_var
1200  . ($this->mconf['addParams'] ?? '')
1201  . ($this->I['val']['additionalParams'] ?? '')
1202  . ((string)($this->mconf['showAccessRestrictedPages'] ?? '_'))
1203  . (isset($this->mconf['showAccessRestrictedPages.']) ? json_encode($this->mconf['showAccessRestrictedPages.']) : '')
1204  . json_encode($this->menuArr[$key])
1205  . ($this->I['val']['ATagParams'] ?? '')
1206  . (isset($this->I['val']['ATagParams.']) ? json_encode($this->I['val']['ATagParams.']) : '')
1207  );
1208  $runtimeCachedLink = $runtimeCache->get($cacheId);
1209  if ($runtimeCachedLink !== false) {
1210  return $runtimeCachedLink;
1211  }
1212 
1213  $tsfe = $this->‪getTypoScriptFrontendController();
1214 
1215  $SAVED_link_to_restricted_pages = '';
1216  $SAVED_link_to_restricted_pages_additional_params = '';
1217  $SAVED_link_to_restricted_pages_tag_attributes = '';
1218  // links to a specific page
1219  if ($this->mconf['showAccessRestrictedPages'] ?? false) {
1220  $SAVED_link_to_restricted_pages = $tsfe->config['config']['typolinkLinkAccessRestrictedPages'] ?? false;
1221  $SAVED_link_to_restricted_pages_additional_params = $tsfe->config['config']['typolinkLinkAccessRestrictedPages_addParams'] ?? null;
1222  $SAVED_link_to_restricted_pages_tag_attributes = $tsfe->config['config']['typolinkLinkAccessRestrictedPages.']['ATagParams'] ?? '';
1223  $tsfe->config['config']['typolinkLinkAccessRestrictedPages'] = $this->mconf['showAccessRestrictedPages'];
1224  $tsfe->config['config']['typolinkLinkAccessRestrictedPages_addParams'] = $this->mconf['showAccessRestrictedPages.']['addParams'] ?? '';
1225  $tsfe->config['config']['typolinkLinkAccessRestrictedPages.']['ATagParams'] = $this->mconf['showAccessRestrictedPages.']['ATagParams'] ?? '';
1226  }
1227  // If a user script returned the value overrideId in the menu array we use that as page id
1228  if (($this->mconf['overrideId'] ?? false) || ($this->menuArr[$key]['overrideId'] ?? false)) {
1229  $overrideId = (int)($this->mconf['overrideId'] ?: $this->menuArr[$key]['overrideId']);
1230  $overrideId = $overrideId > 0 ? $overrideId : null;
1231  // Clear MP parameters since ID was changed.
1232  $MP_params = '';
1233  } else {
1234  $overrideId = null;
1235  // Mount points:
1236  $MP_params = $MP_var ? '&MP=' . rawurlencode($MP_var) : '';
1237  }
1238  // Setting main target
1239  $mainTarget = $altTarget ?: (string)$this->parent_cObj->stdWrapValue('target', $this->mconf);
1240  // Creating link
1241  $addParams = ($this->mconf['addParams'] ?? '') . ($this->I['val']['additionalParams'] ?? '') . $MP_params;
1242  try {
1243  $linkResult = $this->‪menuTypoLink($this->menuArr[$key], $mainTarget, $addParams, $typeOverride, $overrideId);
1244  // Overriding URL / Target if set to do so:
1245  if ($this->menuArr[$key]['_OVERRIDE_HREF'] ?? false) {
1246  $linkResult = $linkResult->withAttribute('href', $this->menuArr[$key]['_OVERRIDE_HREF']);
1247  if ($this->menuArr[$key]['_OVERRIDE_TARGET'] ?? false) {
1248  $linkResult = $linkResult->withAttribute('target', $this->menuArr[$key]['_OVERRIDE_TARGET']);
1249  }
1250  }
1251  } catch (UnableToLinkException $e) {
1252  $linkResult = null;
1253  }
1254  $runtimeCache->set($cacheId, $linkResult);
1255 
1256  // End showAccessRestrictedPages
1257  if ($this->mconf['showAccessRestrictedPages'] ?? false) {
1258  $tsfe->config['config']['typolinkLinkAccessRestrictedPages'] = $SAVED_link_to_restricted_pages;
1259  $tsfe->config['config']['typolinkLinkAccessRestrictedPages_addParams'] = $SAVED_link_to_restricted_pages_additional_params;
1260  $tsfe->config['config']['typolinkLinkAccessRestrictedPages.']['ATagParams'] = $SAVED_link_to_restricted_pages_tag_attributes;
1261  }
1262 
1263  return $linkResult;
1264  }
1265 
1273  protected function ‪subMenu(int ‪$uid, string $objSuffix, int $menuItemKey)
1274  {
1275  // Setting alternative menu item array if _SUB_MENU has been defined in the current ->menuArr
1276  $altArray = [];
1277  if (is_array($this->menuArr[$menuItemKey]['_SUB_MENU'] ?? null) && !empty($this->menuArr[$menuItemKey]['_SUB_MENU'])) {
1278  $altArray = $this->menuArr[$menuItemKey]['_SUB_MENU'];
1279  }
1280  // Make submenu if the page is the next active
1281  $menuType = $this->conf[($this->menuNumber + 1) . $objSuffix] ?? '';
1282  // stdWrap for expAll
1283  $this->mconf['expAll'] = $this->parent_cObj->stdWrapValue('expAll', $this->mconf);
1284  if (($this->mconf['expAll'] || $this->‪isNext($uid, $this->‪getMPvar($menuItemKey)) || $altArray !== []) && !($this->mconf['sectionIndex'] ?? false)) {
1285  try {
1286  $menuObjectFactory = GeneralUtility::makeInstance(MenuContentObjectFactory::class);
1288  $submenu = $menuObjectFactory->getMenuObjectByType($menuType);
1289  $submenu->entryLevel = $this->entryLevel + 1;
1290  $submenu->rL_uidRegister = ‪$this->rL_uidRegister;
1291  $submenu->MP_array = ‪$this->MP_array;
1292  if ($this->menuArr[$menuItemKey]['_MP_PARAM'] ?? false) {
1293  $submenu->MP_array[] = $this->menuArr[$menuItemKey]['_MP_PARAM'];
1294  }
1295  // Especially scripts that build the submenu needs the parent data
1296  $submenu->parent_cObj = ‪$this->parent_cObj;
1297  $submenu->setParentMenu($this->menuArr, $menuItemKey);
1298  // Setting alternativeMenuTempArray (will be effective only if an array and not empty)
1299  if ($altArray !== []) {
1300  $submenu->alternativeMenuTempArray = $altArray;
1301  }
1302  if ($submenu->start(null, $this->sys_page, ‪$uid, $this->conf, $this->menuNumber + 1, $objSuffix, $this->request)) {
1303  $submenu->makeMenu();
1304  // Memorize the current menu item count
1305  $tsfe = $this->‪getTypoScriptFrontendController();
1306  $tempCountMenuObj = $tsfe->register['count_MENUOBJ'];
1307  // Reset the menu item count for the submenu
1308  $tsfe->register['count_MENUOBJ'] = 0;
1309  $content = $submenu->writeMenu();
1310  // Restore the item count now that the submenu has been handled
1311  $tsfe->register['count_MENUOBJ'] = $tempCountMenuObj;
1312  $tsfe->register['count_menuItems'] = count($this->menuArr);
1313  return $content;
1314  }
1315  } catch (‪NoSuchMenuTypeException $e) {
1316  }
1317  }
1318  return '';
1319  }
1320 
1329  protected function ‪isNext(‪$uid, $MPvar)
1330  {
1331  // Check for always active PIDs:
1332  if (in_array((int)‪$uid, $this->alwaysActivePIDlist, true)) {
1333  return true;
1334  }
1335  $testUid = ‪$uid . ($MPvar ? ':' . $MPvar : '');
1336  if (‪$uid && $testUid == $this->nextActive) {
1337  return true;
1338  }
1339  return false;
1340  }
1341 
1349  protected function ‪isActive(array $page, $MPvar)
1350  {
1351  // Check for always active PIDs
1352  ‪$uid = (int)($page['uid'] ?? 0);
1353  if (in_array(‪$uid, $this->alwaysActivePIDlist, true)) {
1354  return true;
1355  }
1356  $testUid = ‪$uid . ($MPvar ? ':' . $MPvar : '');
1357  if (‪$uid && in_array('ITEM:' . $testUid, $this->rL_uidRegister, true)) {
1358  return true;
1359  }
1360  try {
1361  $page = $this->sys_page->resolveShortcutPage($page, $this->disableGroupAccessCheck);
1362  $shortcutPage = (int)($page['_SHORTCUT_ORIGINAL_PAGE_UID'] ?? 0);
1363  if ($shortcutPage) {
1364  if (in_array($shortcutPage, $this->alwaysActivePIDlist, true)) {
1365  return true;
1366  }
1367  $testUid = $shortcutPage . ($MPvar ? ':' . $MPvar : '');
1368  if (in_array('ITEM:' . $testUid, $this->rL_uidRegister, true)) {
1369  return true;
1370  }
1371  }
1372  } catch (\‪Exception $e) {
1373  // Shortcut could not be resolved
1374  return false;
1375  }
1376  return false;
1377  }
1378 
1386  protected function ‪isCurrent(array $page, $MPvar)
1387  {
1388  $testUid = ($page['uid'] ?? 0) . ($MPvar ? ':' . $MPvar : '');
1389  if (($page['uid'] ?? 0) && end($this->rL_uidRegister) === 'ITEM:' . $testUid) {
1390  return true;
1391  }
1392  try {
1393  $page = $this->sys_page->resolveShortcutPage($page);
1394  $shortcutPage = (int)($page['_SHORTCUT_ORIGINAL_PAGE_UID'] ?? 0);
1395  if ($shortcutPage) {
1396  $testUid = $shortcutPage . ($MPvar ? ':' . $MPvar : '');
1397  if (end($this->rL_uidRegister) === 'ITEM:' . $testUid) {
1398  return true;
1399  }
1400  }
1401  } catch (\‪Exception $e) {
1402  // Shortcut could not be resolved
1403  return false;
1404  }
1405  return false;
1406  }
1407 
1415  protected function ‪isSubMenu(‪$uid)
1416  {
1417  $cacheId = $this->‪getCacheIdentifierForSubMenuDecision($uid);
1418  $runtimeCache = $this->‪getRuntimeCache();
1419  $cachedDecision = $runtimeCache->get($cacheId);
1420  if (isset($cachedDecision['result'])) {
1421  return $cachedDecision['result'];
1422  }
1423  // Looking for a mount-pid for this UID since if that
1424  // exists we should look for a subpages THERE and not in the input $uid;
1425  $mount_info = $this->sys_page->getMountPointInfo(‪$uid);
1426  if (is_array($mount_info)) {
1427  ‪$uid = $mount_info['mount_pid'];
1428  }
1429 
1430  // Collect subpages for all pages on current level
1431  $pageIdsOnSameLevel = array_column($this->menuArr, 'uid');
1432  $cacheIdentifierPagesNextLevel = 'menucontentobject-is-submenu-pages-next-level-' . $this->menuNumber . '-' . sha1(json_encode($pageIdsOnSameLevel));
1433  $cachePagesNextLevel = $runtimeCache->get($cacheIdentifierPagesNextLevel);
1434  if (!is_array($cachePagesNextLevel)) {
1435  $cachePagesNextLevel = $this->sys_page->getMenu($pageIdsOnSameLevel, 'uid,pid,doktype,mount_pid,mount_pid_ol,nav_hide,shortcut,shortcut_mode,l18n_cfg');
1436  $runtimeCache->set($cacheIdentifierPagesNextLevel, $cachePagesNextLevel);
1437  }
1438 
1439  $recs = array_filter($cachePagesNextLevel, static fn(array $item) => (int)$item['pid'] === (int)‪$uid);
1440 
1441  $hasSubPages = false;
1442  $bannedUids = $this->‪getBannedUids();
1443  $languageId = $this->‪getCurrentLanguageAspect()->getId();
1444  foreach ($recs as $theRec) {
1445  // no valid subpage if the document type is excluded from the menu
1446  if (in_array((int)($theRec['doktype'] ?? 0), $this->excludedDoktypes, true)) {
1447  continue;
1448  }
1449  // No valid subpage if the page is hidden inside menus and
1450  // it wasn't forced to show such entries
1451  if (isset($theRec['nav_hide']) && $theRec['nav_hide']
1452  && (!isset($this->conf['includeNotInMenu']) || !$this->conf['includeNotInMenu'])
1453  ) {
1454  continue;
1455  }
1456  // No valid subpage if the default language should be shown and the page settings
1457  // are excluding the visibility of the default language
1458  $pageTranslationVisibility = new PageTranslationVisibility((int)($theRec['l18n_cfg'] ?? 0));
1459  if (!$languageId && $pageTranslationVisibility->shouldBeHiddenInDefaultLanguage()) {
1460  continue;
1461  }
1462  // No valid subpage if the alternative language should be shown and the page settings
1463  // are requiring a valid overlay but it doesn't exists
1464  if ($pageTranslationVisibility->shouldHideTranslationIfNoTranslatedRecordExists() && $languageId > 0 && !($theRec['_PAGES_OVERLAY'] ?? false)) {
1465  continue;
1466  }
1467  // No valid subpage if the subpage is banned by excludeUidList (check for default language pages as well)
1468  if (($theRec['_PAGES_OVERLAY_UID'] ?? 0) > 0 && in_array((int)($theRec['_PAGES_OVERLAY_UID'] ?? 0), $bannedUids, true)) {
1469  continue;
1470  }
1471  if (in_array((int)($theRec['uid'] ?? 0), $bannedUids, true)) {
1472  continue;
1473  }
1474  $hasSubPages = true;
1475  break;
1476  }
1477  $runtimeCache->set($cacheId, ['result' => $hasSubPages]);
1478  return $hasSubPages;
1479  }
1480 
1481  protected function ‪getCacheIdentifierForSubMenuDecision(‪$uid): string
1482  {
1483  return 'menucontentobject-is-submenu-decision-' . ‪$uid . '-' . (int)($this->conf['includeNotInMenu'] ?? 0);
1484  }
1485 
1494  protected function ‪isItemState($kind, $key)
1495  {
1496  $natVal = false;
1497  // If any value is set for ITEM_STATE the normal evaluation is discarded
1498  if ($this->menuArr[$key]['ITEM_STATE'] ?? false) {
1499  if ((string)$this->menuArr[$key]['ITEM_STATE'] === (string)$kind) {
1500  $natVal = true;
1501  }
1502  } else {
1503  switch ($kind) {
1504  case 'SPC':
1505  $natVal = (bool)$this->menuArr[$key]['isSpacer'];
1506  break;
1507  case 'IFSUB':
1508  $natVal = $this->‪isSubMenu($this->menuArr[$key]['uid'] ?? 0);
1509  break;
1510  case 'ACT':
1511  $natVal = $this->‪isActive(($this->menuArr[$key] ?? []), $this->‪getMPvar($key));
1512  break;
1513  case 'ACTIFSUB':
1514  $natVal = $this->‪isActive(($this->menuArr[$key] ?? []), $this->‪getMPvar($key)) && $this->‪isSubMenu($this->menuArr[$key]['uid']);
1515  break;
1516  case 'CUR':
1517  $natVal = $this->‪isCurrent(($this->menuArr[$key] ?? []), $this->‪getMPvar($key));
1518  break;
1519  case 'CURIFSUB':
1520  $natVal = $this->‪isCurrent(($this->menuArr[$key] ?? []), $this->‪getMPvar($key)) && $this->‪isSubMenu($this->menuArr[$key]['uid']);
1521  break;
1522  case 'USR':
1523  $natVal = (bool)$this->menuArr[$key]['fe_group'];
1524  break;
1525  }
1526  }
1527  return $natVal;
1528  }
1529 
1538  protected function ‪userProcess($mConfKey, $passVar)
1539  {
1540  if ($this->mconf[$mConfKey]) {
1541  $funcConf = (array)($this->mconf[$mConfKey . '.'] ?? []);
1542  $funcConf['parentObj'] = $this;
1543  $passVar = $this->parent_cObj->callUserFunction($this->mconf[$mConfKey], $funcConf, $passVar);
1544  }
1545  return $passVar;
1546  }
1551  protected function ‪setATagParts(?‪LinkResultInterface $linkResult)
1552  {
1553  $this->I['A1'] = $linkResult ? '<a ' . GeneralUtility::implodeAttributes($linkResult->‪getAttributes(), true) . '>' : '';
1554  $this->I['A2'] = $linkResult ? '</a>' : '';
1555  }
1556 
1564  protected function ‪getPageTitle($title, $nav_title)
1565  {
1566  return trim($nav_title) !== '' ? $nav_title : $title;
1567  }
1568 
1576  protected function ‪getMPvar($key)
1577  {
1578  if (‪$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1579  $localMP_array = ‪$this->MP_array;
1580  // NOTICE: "_MP_PARAM" is allowed to be a commalist of PID pairs!
1581  if ($this->menuArr[$key]['_MP_PARAM'] ?? false) {
1582  $localMP_array[] = $this->menuArr[$key]['_MP_PARAM'];
1583  }
1584  return !empty($localMP_array) ? implode(',', $localMP_array) : '';
1585  }
1586  return '';
1587  }
1588 
1594  protected function ‪getDoktypeExcludeWhere()
1595  {
1596  return !empty($this->excludedDoktypes) ? ' AND pages.doktype NOT IN (' . implode(',', $this->excludedDoktypes) . ')' : '';
1597  }
1598 
1604  protected function ‪getBannedUids()
1605  {
1606  $excludeUidList = (string)$this->parent_cObj->stdWrapValue('excludeUidList', $this->conf);
1607  if (!trim($excludeUidList)) {
1608  return [];
1609  }
1610 
1611  $banUidList = str_replace('current', (string)($this->‪getTypoScriptFrontendController()->page['uid'] ?? ''), $excludeUidList);
1612  return GeneralUtility::intExplode(',', $banUidList);
1613  }
1614 
1624  protected function ‪menuTypoLink(array $page, string $oTarget, $addParams, $typeOverride, ?int $overridePageId = null): ‪LinkResultInterface
1625  {
1626  ‪$conf = [
1627  'parameter' => $overridePageId ?? $page['uid'] ?? 0,
1628  ];
1629  if (‪MathUtility::canBeInterpretedAsInteger($typeOverride)) {
1630  ‪$conf['parameter'] .= ',' . (int)$typeOverride;
1631  }
1632  if ($addParams) {
1633  ‪$conf['additionalParams'] = $addParams;
1634  }
1635  // Used only for special=language
1636  if ($page['_ADD_GETVARS'] ?? false) {
1637  ‪$conf['addQueryString'] = $page['_ADD_GETVARS'];
1638  ‪$conf['addQueryString.'] = $this->conf['addQueryString.'] ?? [];
1639  }
1640 
1641  // Ensure that the typolink gets an info which language was actually requested. The $page record could be the record
1642  // from page translation language=1 as fallback but page translation language=2 was requested. Search for
1643  // "_PAGES_OVERLAY_REQUESTEDLANGUAGE" for more details
1644  if (isset($page['_PAGES_OVERLAY_REQUESTEDLANGUAGE'])) {
1645  ‪$conf['language'] = $page['_PAGES_OVERLAY_REQUESTEDLANGUAGE'];
1646  }
1647  if ($oTarget) {
1648  ‪$conf['target'] = $oTarget;
1649  }
1650  // $this->I['val'] contains the configuration of the ItemState (e.g. NO / SPC) etc, which should be handed in
1651  // to this method instead of accessed directly in the future.
1652  if (isset($this->I['val']['ATagParams']) || isset($this->I['val']['ATagParams.'])) {
1653  ‪$conf['ATagParams'] = $this->I['val']['ATagParams'] ?? '';
1654  ‪$conf['ATagParams.'] = $this->I['val']['ATagParams.'] ?? [];
1655  }
1656  if ($page['sectionIndex_uid'] ?? false) {
1657  ‪$conf['section'] = $page['sectionIndex_uid'];
1658  }
1659  ‪$conf['page'] = new ‪Page($page);
1660  return $this->parent_cObj->createLink('|', ‪$conf);
1661  }
1662 
1674  protected function ‪sectionIndex($altSortField, $pid = null)
1675  {
1676  $pid = (int)($pid ?: $this->id);
1677  $basePageRow = $this->sys_page->getPage($pid);
1678  if (!is_array($basePageRow)) {
1679  return [];
1680  }
1681  $useColPos = (int)$this->parent_cObj->stdWrapValue('useColPos', $this->mconf['sectionIndex.'] ?? [], 0);
1682  $selectSetup = [
1683  'pidInList' => $pid,
1684  'orderBy' => $altSortField,
1685  'languageField' => 'sys_language_uid',
1686  'where' => '',
1687  ];
1688 
1689  if ($useColPos >= 0) {
1690  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1691  ->getConnectionForTable('tt_content')
1692  ->getExpressionBuilder();
1693  $selectSetup['where'] = $expressionBuilder->eq('colPos', $useColPos);
1694  }
1695 
1696  if ($basePageRow['content_from_pid'] ?? false) {
1697  // If the page is configured to show content from a referenced page the sectionIndex contains only contents of
1698  // the referenced page
1699  $selectSetup['pidInList'] = $basePageRow['content_from_pid'];
1700  }
1701  $statement = $this->parent_cObj->exec_getQuery('tt_content', $selectSetup);
1702  if (!$statement) {
1703  $message = 'SectionIndex: Query to fetch the content elements failed!';
1704  throw new \UnexpectedValueException($message, 1337334849);
1705  }
1706  ‪$result = [];
1707  while ($row = $statement->fetchAssociative()) {
1708  $this->sys_page->versionOL('tt_content', $row);
1709  if ($this->‪getCurrentLanguageAspect()->doOverlays() && $basePageRow['_PAGES_OVERLAY_LANGUAGE']) {
1710  $languageAspect = new LanguageAspect($basePageRow['_PAGES_OVERLAY_LANGUAGE'], $basePageRow['_PAGES_OVERLAY_LANGUAGE'], $this->‪getCurrentLanguageAspect()->getOverlayType());
1711  $row = $this->sys_page->getLanguageOverlay(
1712  'tt_content',
1713  $row,
1714  $languageAspect
1715  );
1716  }
1717  if (is_array($row)) {
1718  $sectionIndexType = $this->mconf['sectionIndex.']['type'] ?? '';
1719  if ($sectionIndexType !== 'all') {
1720  $doIncludeInSectionIndex = $row['sectionIndex'] >= 1;
1721  $doHeaderCheck = $sectionIndexType === 'header';
1722  $isValidHeader = ((int)$row['header_layout'] !== 100 || !empty($this->mconf['sectionIndex.']['includeHiddenHeaders'])) && trim($row['header']) !== '';
1723  if (!$doIncludeInSectionIndex || ($doHeaderCheck && !$isValidHeader)) {
1724  continue;
1725  }
1726  }
1727  ‪$uid = $row['uid'] ?? null;
1728  ‪$result[‪$uid] = $basePageRow;
1729  ‪$result[‪$uid]['title'] = $row['header'];
1730  ‪$result[‪$uid]['nav_title'] = $row['header'];
1731  // Prevent false exclusion in filterMenuPages, thus: Always show tt_content records
1732  ‪$result[‪$uid]['nav_hide'] = 0;
1733  ‪$result[‪$uid]['subtitle'] = $row['subheader'] ?? '';
1734  ‪$result[‪$uid]['starttime'] = $row['starttime'] ?? '';
1735  ‪$result[‪$uid]['endtime'] = $row['endtime'] ?? '';
1736  ‪$result[‪$uid]['fe_group'] = $row['fe_group'] ?? '';
1737  ‪$result[‪$uid]['media'] = $row['media'] ?? '';
1738  ‪$result[‪$uid]['header_layout'] = $row['header_layout'] ?? '';
1739  ‪$result[‪$uid]['bodytext'] = $row['bodytext'] ?? '';
1740  ‪$result[‪$uid]['image'] = $row['image'] ?? '';
1741  ‪$result[‪$uid]['sectionIndex_uid'] = ‪$uid;
1742  }
1743  }
1744 
1745  return ‪$result;
1746  }
1747 
1753  public function ‪getSysPage()
1754  {
1755  return ‪$this->sys_page;
1756  }
1757 
1763  public function ‪getParentContentObject()
1764  {
1765  return ‪$this->parent_cObj;
1766  }
1767 
1772  {
1773  $frontendController = $this->parent_cObj->getTypoScriptFrontendController();
1774  if (!$frontendController instanceof ‪TypoScriptFrontendController) {
1775  throw new ‪ContentRenderingException('TypoScriptFrontendController is not available.', 1655725105);
1776  }
1777 
1778  return $frontendController;
1779  }
1780 
1781  protected function ‪getCurrentLanguageAspect(): ‪LanguageAspect
1782  {
1783  return GeneralUtility::makeInstance(Context::class)->getAspect('language');
1784  }
1785 
1786  protected function ‪getTimeTracker(): ‪TimeTracker
1787  {
1788  return GeneralUtility::makeInstance(TimeTracker::class);
1789  }
1790 
1791  protected function ‪getCache(): ‪FrontendInterface
1792  {
1793  return GeneralUtility::makeInstance(CacheManager::class)->getCache('hash');
1794  }
1795 
1796  protected function ‪getRuntimeCache(): FrontendInterface
1797  {
1798  return GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
1799  }
1800 
1804  protected function ‪getCurrentSite(): ‪Site
1805  {
1806  return $this->‪getTypoScriptFrontendController()->getSite();
1807  }
1808 
1816  public function ‪setParentMenu(array ‪$menuArr, $menuItemKey)
1817  {
1818  // check if menuArr is a valid array and that menuItemKey matches an existing menuItem in menuArr
1819  if (is_array(‪$menuArr)
1820  && (is_int($menuItemKey) && $menuItemKey >= 0 && isset(‪$menuArr[$menuItemKey]))
1821  ) {
1822  $this->parentMenuArr = ‪$menuArr;
1823  $this->parentMenuArrItemKey = $menuItemKey;
1824  }
1825  }
1826 
1832  protected function ‪hasParentMenuArr()
1833  {
1834  return
1835  $this->menuNumber > 1
1836  && is_array($this->parentMenuArr)
1837  && !empty($this->parentMenuArr)
1838  ;
1839  }
1840 
1844  protected function ‪hasParentMenuItemKey()
1845  {
1846  return $this->parentMenuArrItemKey !== null;
1847  }
1848 
1852  protected function ‪hasParentMenuItem()
1853  {
1854  return
1855  $this->‪hasParentMenuArr()
1856  && $this->‪hasParentMenuItemKey()
1857  && isset($this->‪getParentMenuArr()[$this->parentMenuArrItemKey])
1858  ;
1859  }
1860 
1866  public function ‪getParentMenuArr()
1867  {
1868  return $this->‪hasParentMenuArr() ? $this->parentMenuArr : [];
1869  }
1870 
1876  public function ‪getParentMenuItem()
1877  {
1878  // check if we have a parentMenuItem and if it is an array
1879  if ($this->‪hasParentMenuItem()
1880  && is_array($this->‪getParentMenuArr()[$this->parentMenuArrItemKey])
1881  ) {
1883  }
1884 
1885  return null;
1886  }
1887 
1888  private function ‪getMode(string $mode = ''): string
1889  {
1890  switch ($mode) {
1891  case 'starttime':
1892  $sortField = 'starttime';
1893  break;
1894  case 'lastUpdated':
1895  case 'manual':
1896  $sortField = 'lastUpdated';
1897  break;
1898  case 'tstamp':
1899  $sortField = 'tstamp';
1900  break;
1901  case 'crdate':
1902  $sortField = 'crdate';
1903  break;
1904  default:
1905  $sortField = 'SYS_LASTCHANGED';
1906  }
1907 
1908  return $sortField;
1909  }
1910 
1917  private function ‪getRootlineLevel(array $rootLine, string $list): int
1918  {
1919  $idx = 0;
1920  foreach ($rootLine as $page) {
1921  if (‪GeneralUtility::inList($list, $page['uid'])) {
1922  return $idx;
1923  }
1924  $idx++;
1925  }
1926  return 0;
1927  }
1928 }
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForListMenu
‪array prepareMenuItemsForListMenu($specialValue)
Definition: AbstractMenuContentObject.php:666
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getBannedUids
‪array getBannedUids()
Definition: AbstractMenuContentObject.php:1587
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getParentMenuItem
‪array null getParentMenuItem()
Definition: AbstractMenuContentObject.php:1859
‪TYPO3\CMS\Core\Domain\Page
Definition: Page.php:24
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\menuTypoLink
‪menuTypoLink(array $page, string $oTarget, $addParams, $typeOverride, ?int $overridePageId=null)
Definition: AbstractMenuContentObject.php:1607
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$MP_array
‪string[] $MP_array
Definition: AbstractMenuContentObject.php:85
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$parentMenuArrItemKey
‪int null $parentMenuArrItemKey
Definition: AbstractMenuContentObject.php:152
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\hasParentMenuArr
‪bool hasParentMenuArr()
Definition: AbstractMenuContentObject.php:1815
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getPageTitle
‪string getPageTitle($title, $nav_title)
Definition: AbstractMenuContentObject.php:1547
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\isNext
‪bool isNext($uid, $MPvar)
Definition: AbstractMenuContentObject.php:1312
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:50
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\writeMenu
‪string writeMenu()
Definition: AbstractMenuContentObject.php:410
‪TYPO3\CMS\Core\Context\LanguageAspectFactory
Definition: LanguageAspectFactory.php:27
‪TYPO3\CMS\Frontend\ContentObject\Menu\Exception\NoSuchMenuTypeException
Definition: NoSuchMenuTypeException.php:23
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getMode
‪getMode(string $mode='')
Definition: AbstractMenuContentObject.php:1871
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForRootlineMenu
‪array prepareMenuItemsForRootlineMenu()
Definition: AbstractMenuContentObject.php:904
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$parentMenuArr
‪array $parentMenuArr
Definition: AbstractMenuContentObject.php:156
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\hasParentMenuItem
‪hasParentMenuItem()
Definition: AbstractMenuContentObject.php:1835
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$nextActive
‪string $nextActive
Definition: AbstractMenuContentObject.php:114
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getCache
‪getCache()
Definition: AbstractMenuContentObject.php:1774
‪$languages
‪$languages
Definition: updateIsoDatabase.php:104
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$conf
‪array $conf
Definition: AbstractMenuContentObject.php:91
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\start
‪bool start($_, $sys_page, $id, $conf, int $menuNumber, $objSuffix='', ?ServerRequestInterface $request=null)
Definition: AbstractMenuContentObject.php:188
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItems
‪array prepareMenuItems()
Definition: AbstractMenuContentObject.php:448
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$alternativeMenuTempArray
‪array $alternativeMenuTempArray
Definition: AbstractMenuContentObject.php:146
‪TYPO3\CMS\Core\Context\LanguageAspectFactory\createFromSiteLanguage
‪static createFromSiteLanguage(SiteLanguage $language)
Definition: LanguageAspectFactory.php:31
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\sectionIndex
‪array sectionIndex($altSortField, $pid=null)
Definition: AbstractMenuContentObject.php:1657
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForUpdatedMenu
‪array prepareMenuItemsForUpdatedMenu($specialValue, $sortingField)
Definition: AbstractMenuContentObject.php:722
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\link
‪LinkResultInterface null link($key, $altTarget, $typeOverride)
Definition: AbstractMenuContentObject.php:1174
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForLanguageMenu
‪array prepareMenuItemsForLanguageMenu($specialValue)
Definition: AbstractMenuContentObject.php:541
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$disableGroupAccessCheck
‪bool $disableGroupAccessCheck
Definition: AbstractMenuContentObject.php:158
‪TYPO3\CMS\Core\Type\Bitmask\PageTranslationVisibility
Definition: PageTranslationVisibility.php:30
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\hasParentMenuItemKey
‪hasParentMenuItemKey()
Definition: AbstractMenuContentObject.php:1827
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject
Definition: AbstractMenuContentObject.php:53
‪TYPO3\CMS\Frontend\ContentObject\Exception\ContentRenderingException
Definition: ContentRenderingException.php:24
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:54
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForUserSpecificMenu
‪array prepareMenuItemsForUserSpecificMenu($specialValue, $sortingField)
Definition: AbstractMenuContentObject.php:525
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\filterMenuPages
‪bool filterMenuPages(&$data, $banUidArray, $isSpacerPage)
Definition: AbstractMenuContentObject.php:1076
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$result
‪array $result
Definition: AbstractMenuContentObject.php:128
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\userProcess
‪mixed userProcess($mConfKey, $passVar)
Definition: AbstractMenuContentObject.php:1521
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getDoktypeExcludeWhere
‪string getDoktypeExcludeWhere()
Definition: AbstractMenuContentObject.php:1577
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$sys_page
‪PageRepository $sys_page
Definition: AbstractMenuContentObject.php:101
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$I
‪mixed[] $I
Definition: AbstractMenuContentObject.php:139
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$menuArr
‪array[] $menuArr
Definition: AbstractMenuContentObject.php:120
‪TYPO3\CMS\Frontend\Exception
Definition: Exception.php:23
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\generate
‪generate()
Definition: AbstractMenuContentObject.php:397
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\isCurrent
‪bool isCurrent(array $page, $MPvar)
Definition: AbstractMenuContentObject.php:1369
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getCacheIdentifierForSubMenuDecision
‪getCacheIdentifierForSubMenuDecision($uid)
Definition: AbstractMenuContentObject.php:1464
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getRootlineLevel
‪int getRootlineLevel(array $rootLine, string $list)
Definition: AbstractMenuContentObject.php:1900
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$parent_cObj
‪ContentObjectRenderer $parent_cObj
Definition: AbstractMenuContentObject.php:79
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getRuntimeCache
‪getRuntimeCache()
Definition: AbstractMenuContentObject.php:1779
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\subMenu
‪string subMenu(int $uid, string $objSuffix, int $menuItemKey)
Definition: AbstractMenuContentObject.php:1256
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:113
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getTypoScriptFrontendController
‪getTypoScriptFrontendController()
Definition: AbstractMenuContentObject.php:1754
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_BE_USER_SECTION
‪const DOKTYPE_BE_USER_SECTION
Definition: PageRepository.php:111
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$id
‪int $id
Definition: AbstractMenuContentObject.php:107
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:114
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:57
‪TYPO3\CMS\Frontend\Event\FilterMenuItemsEvent
Definition: FilterMenuItemsEvent.php:27
‪TYPO3\CMS\Frontend\ContentObject\Menu
Definition: AbstractMenuContentObject.php:16
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForBrowseMenu
‪array prepareMenuItemsForBrowseMenu($specialValue, $sortingField, $additionalWhere)
Definition: AbstractMenuContentObject.php:959
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\makeMenu
‪makeMenu()
Definition: AbstractMenuContentObject.php:324
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\setATagParts
‪setATagParts(?LinkResultInterface $linkResult)
Definition: AbstractMenuContentObject.php:1534
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\customItemStates
‪const customItemStates
Definition: AbstractMenuContentObject.php:160
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$entryLevel
‪int $entryLevel
Definition: AbstractMenuContentObject.php:63
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\setParentMenu
‪setParentMenu(array $menuArr, $menuItemKey)
Definition: AbstractMenuContentObject.php:1799
‪TYPO3\CMS\Core\TypoScript\TypoScriptService
Definition: TypoScriptService.php:27
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getCurrentLanguageAspect
‪getCurrentLanguageAspect()
Definition: AbstractMenuContentObject.php:1764
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:39
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\isActive
‪bool isActive(array $page, $MPvar)
Definition: AbstractMenuContentObject.php:1332
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$rL_uidRegister
‪array $rL_uidRegister
Definition: AbstractMenuContentObject.php:135
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:102
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getTimeTracker
‪getTimeTracker()
Definition: AbstractMenuContentObject.php:1769
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getCurrentSite
‪getCurrentSite()
Definition: AbstractMenuContentObject.php:1787
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$menuNumber
‪int $menuNumber
Definition: AbstractMenuContentObject.php:57
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForKeywordsMenu
‪array prepareMenuItemsForKeywordsMenu($specialValue, $sortingField)
Definition: AbstractMenuContentObject.php:787
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
Definition: ContentObjectRenderer.php:91
‪TYPO3\CMS\Core\Utility\GeneralUtility\inList
‪static bool inList($list, $item)
Definition: GeneralUtility.php:421
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getParentContentObject
‪ContentObjectRenderer getParentContentObject()
Definition: AbstractMenuContentObject.php:1746
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$hash
‪string $hash
Definition: AbstractMenuContentObject.php:124
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\processItemStates
‪array processItemStates($splitCount)
Definition: AbstractMenuContentObject.php:1133
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$excludedDoktypes
‪int[] $excludedDoktypes
Definition: AbstractMenuContentObject.php:69
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:61
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$mconf
‪array $mconf
Definition: AbstractMenuContentObject.php:97
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:48
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getSysPage
‪PageRepository getSysPage()
Definition: AbstractMenuContentObject.php:1736
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$alwaysActivePIDlist
‪int[] $alwaysActivePIDlist
Definition: AbstractMenuContentObject.php:73
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange(mixed $theInt, int $min, int $max=2000000000, int $defaultValue=0)
Definition: MathUtility.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\removeInaccessiblePages
‪removeInaccessiblePages(array $pages)
Definition: AbstractMenuContentObject.php:418
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getParentMenuArr
‪array getParentMenuArr()
Definition: AbstractMenuContentObject.php:1849
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:32
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\$request
‪ServerRequestInterface $request
Definition: AbstractMenuContentObject.php:141
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\prepareMenuItemsForDirectoryMenu
‪array prepareMenuItemsForDirectoryMenu($specialValue, $sortingField)
Definition: AbstractMenuContentObject.php:624
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\getMPvar
‪string getMPvar($key)
Definition: AbstractMenuContentObject.php:1559
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\isItemState
‪bool isItemState($kind, $key)
Definition: AbstractMenuContentObject.php:1477
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\buildPageRepository
‪buildPageRepository(LanguageAspect $languageAspect=null)
Definition: AbstractMenuContentObject.php:603
‪TYPO3\CMS\Frontend\ContentObject\Menu\AbstractMenuContentObject\isSubMenu
‪bool isSubMenu($uid)
Definition: AbstractMenuContentObject.php:1398