‪TYPO3CMS  ‪main
TypoScriptFrontendController.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\ResponseInterface;
20 use Psr\Http\Message\ServerRequestInterface;
21 use Psr\Log\LoggerAwareInterface;
22 use Psr\Log\LoggerAwareTrait;
23 use Psr\Log\LogLevel;
52 use TYPO3\CMS\Core\Page\PageRenderer;
83 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
93 
104 class ‪TypoScriptFrontendController implements LoggerAwareInterface
105 {
106  use LoggerAwareTrait;
108 
109  protected array ‪$deprecatedPublicProperties = [
110  'intTarget' => '$TSFE->intTarget will be removed in TYPO3 v13.0. Use $TSFE->config[\'config\'][\'intTarget\'] instead.',
111  'extTarget' => '$TSFE->extTarget will be removed in TYPO3 v13.0. Use $TSFE->config[\'config\'][\'extTarget\'] instead.',
112  'fileTarget' => '$TSFE->fileTarget will be removed in TYPO3 v13.0. Use $TSFE->config[\'config\'][\'fileTarget\'] instead.',
113  'spamProtectEmailAddresses' => '$TSFE->spamProtectEmailAddresses will be removed in TYPO3 v13.0. Use $TSFE->config[\'config\'][\'spamProtectEmailAddresses\'] instead.',
114  'baseUrl' => '$TSFE->baseUrl will be removed in TYPO3 v13.0. Use $TSFE->config[\'config\'][\'baseURL\'] instead.',
115  'xhtmlDoctype' => '$TSFE->xhtmlDoctype will be removed in TYPO3 v13.0. Use PageRenderer->getDocType() instead.',
116  'xhtmlVersion' => '$TSFE->xhtmlVersion will be removed in TYPO3 v13.0. Use PageRenderer->getDocType() instead.',
117  ];
118 
122  public int ‪$id;
123 
128  public ‪$type = 0;
129 
130  protected ‪Site ‪$site;
131  protected ‪SiteLanguage ‪$language;
132 
137 
144  public ‪$no_cache = false;
145 
170  public array ‪$rootLine = [];
171 
176  public ‪$page = [];
177 
182  public int ‪$contentPid = 0;
183 
189  protected ?array ‪$originalMountPointPage = null;
190 
195  protected ?array ‪$originalShortcutPage = null;
196 
202  public ‪$sys_page = '';
203 
207  protected int ‪$pageNotFound = 0;
208 
212  protected array ‪$pageAccessFailureHistory = [];
213 
218  public ‪$MP = '';
219 
225  public ‪$fe_user;
226 
259  public $config = [];
260 
268  public $tmpl;
269 
275  protected int $cacheTimeOutDefault = 0;
276 
281  protected bool $pageContentWasLoadedFromCache = false;
282 
287  protected int $cacheExpires = 0;
288 
294  public $pSetup = '';
295 
301  public string $newHash = '';
302 
310  protected bool $no_cacheBeforePageGen = false;
311 
316  protected ?array $pagesTSconfig = null;
317 
331  public $additionalHeaderData = [];
332 
337  public $additionalFooterData = [];
338 
344  protected $intTarget = '';
345 
351  protected $extTarget = '';
352 
358  protected $fileTarget = '';
359 
364  protected int $spamProtectEmailAddresses = 0;
365 
370  public $absRefPrefix = '';
371 
378  public string $linkVars = '';
379 
384  public array $applicationData = [];
385 
386  public array $register = [];
387 
392  public array $registerStack = [];
393 
398  public array $recordRegister = [];
399 
406  public string $currentRecord = '';
407 
413  protected int $uniqueCounter = 0;
414 
418  protected string $uniqueString = '';
419 
425  protected $baseUrl = '';
426 
432  public $cObj;
433 
438  public $content = '';
439 
444  public ?array $lastImgResourceInfo = null;
445 
449  protected ?‪LanguageService $languageService = null;
450 
454  public ?‪ResourceMutex $lock = null;
455 
456  protected ?PageRenderer $pageRenderer = null;
457 
464  protected $pageCache;
465 
466  protected array $pageCacheTags = [];
467 
473  protected string $contentType = 'text/html; charset=utf-8';
474 
481  protected $xhtmlDoctype = '';
482 
487  protected $xhtmlVersion;
488 
492  protected int $requestedId = 0;
493 
498  protected ‪Context $context;
499 
504  protected string $debugInformationHeader = '';
505 
521  public function __construct(‪Context $context, ‪Site ‪$site, ‪SiteLanguage $siteLanguage, ‪PageArguments ‪$pageArguments, ‪FrontendUserAuthentication $frontendUser)
522  {
523  $this->‪initializeContext($context);
524  $this->‪site = ‪$site;
525  $this->‪language = $siteLanguage;
526  $this->‪setPageArguments($pageArguments);
527  $this->‪fe_user = $frontendUser;
528  $this->‪uniqueString = md5(microtime());
529  $this->‪initPageRenderer();
530  $this->‪initCaches();
531  }
532 
533  private function ‪initializeContext(‪Context $context): void
534  {
535  $this->context = $context;
536  if (!$this->context->hasAspect('frontend.preview')) {
537  $this->context->‪setAspect('frontend.preview', GeneralUtility::makeInstance(PreviewAspect::class));
538  }
539  }
540 
544  protected function ‪initPageRenderer()
545  {
546  if ($this->pageRenderer !== null) {
547  return;
548  }
549  $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
550  $this->pageRenderer->setTemplateFile('EXT:frontend/Resources/Private/Templates/MainPage.html');
551  // As initPageRenderer could be called in constructor and for USER_INTs, this information is only set
552  // once - in order to not override any previous settings of PageRenderer.
553  if ($this->‪language->hasCustomTypo3Language()) {
554  $locale = GeneralUtility::makeInstance(Locales::class)->createLocale($this->‪language->getTypo3Language());
555  } else {
556  $locale = $this->‪language->getLocale();
557  }
558  $this->pageRenderer->setLanguage($locale);
559  }
560 
565  public function ‪setContentType($contentType)
566  {
567  $this->contentType = $contentType;
568  }
569 
570  /********************************************
571  *
572  * Initializing, resolving page id
573  *
574  ********************************************/
578  protected function ‪initCaches()
579  {
580  $cacheManager = GeneralUtility::makeInstance(CacheManager::class);
581  $this->pageCache = $cacheManager->getCache('pages');
582  }
583 
589  public function ‪initUserGroups()
590  {
591  trigger_error('TSFE->initUserGroups() will be removed in TYPO3 v13.0. Use the Context API directly.', E_USER_DEPRECATED);
592  $this->context->setAspect('frontend.user', $this->‪fe_user->createUserAspect());
593  }
594 
601  public function ‪isUserOrGroupSet()
602  {
603  trigger_error('TSFE->isUserOrGroupSet() will be removed in TYPO3 v13.0. Use the Context API directly.', E_USER_DEPRECATED);
605  $userAspect = $this->context->getAspect('frontend.user');
606  return $userAspect->isUserOrGroupSet();
607  }
608 
615  public function ‪isBackendUserLoggedIn()
616  {
617  trigger_error('TSFE->isBackendUserLoggedIn() will be removed in TYPO3 v13.0. Use the Context API directly.', E_USER_DEPRECATED);
618  return (bool)$this->context->getPropertyFromAspect('backend.user', 'isLoggedIn', false);
619  }
620 
653  public function ‪determineId(ServerRequestInterface $request): ?ResponseInterface
654  {
655  $this->sys_page = GeneralUtility::makeInstance(PageRepository::class, $this->context);
656 
657  $eventDispatcher = GeneralUtility::makeInstance(EventDispatcherInterface::class);
658  $eventDispatcher->dispatch(new BeforePageIsResolvedEvent($this, $request));
659 
660  $timeTracker = $this->‪getTimeTracker();
661  $timeTracker->push('determineId rootLine/');
662  try {
663  // Sets ->page and ->rootline information based on ->id. ->id may change during this operation.
664  // If the found Page ID is not within the site, then pageNotFound is set.
665  $this->‪getPageAndRootline($request);
666  // Checks if the rootPageId of the site is in the resolved rootLine.
667  // This is necessary so that references to page-id's via ?id=123 from other sites are not possible.
668  $siteRootWithinRootlineFound = false;
669  foreach ($this->rootLine as $pageInRootLine) {
670  if ((int)$pageInRootLine['uid'] === $this->‪site->getRootPageId()) {
671  $siteRootWithinRootlineFound = true;
672  break;
673  }
674  }
675  // Page is 'not found' in case the id was outside the domain, code 3
676  // This can only happen if there was a shortcut. So $this->page is now the shortcut target
677  // But the original page is in $this->originalShortcutPage.
678  // This only happens if people actually call TYPO3 with index.php?id=123 where 123 is in a different
679  // page tree. This is not allowed.
680  $directlyRequestedId = (int)($request->getQueryParams()['id'] ?? 0);
681  if (!$siteRootWithinRootlineFound && $directlyRequestedId && (int)($this->originalShortcutPage['uid'] ?? 0) !== $directlyRequestedId) {
682  $this->pageNotFound = 3;
683  $this->id = $this->‪site->getRootPageId();
684  // re-get the page and rootline if the id was not found.
685  $this->‪getPageAndRootline($request);
686  }
687  } catch (ShortcutTargetPageNotFoundException $e) {
688  $this->pageNotFound = 1;
689  }
690  $timeTracker->pull();
691 
692  $event = new AfterPageWithRootLineIsResolvedEvent($this, $request);
693  $event = $eventDispatcher->dispatch($event);
694  if ($event->getResponse()) {
695  return $event->getResponse();
696  }
697 
698  $response = null;
699  try {
700  $this->‪evaluatePageNotFound($this->pageNotFound, $request);
701 
702  // Setting language and fetch translated page
703  $this->‪settingLanguage($request);
704  // Check the "content_from_pid" field of the resolved page
705  $this->contentPid = $this->‪resolveContentPid($request);
706 
707  // Update SYS_LASTCHANGED at the very last, when $this->page might be changed
708  // by settingLanguage() and the $this->page was finally resolved
709  $this->‪setRegisterValueForSysLastChanged($this->page);
710  } catch (‪PropagateResponseException $e) {
711  $response = $e->‪getResponse();
712  }
713 
714  $event = new AfterPageAndLanguageIsResolvedEvent($this, $request, $response);
715  $eventDispatcher->dispatch($event);
716  return $event->getResponse();
717  }
718 
722  protected function ‪evaluatePageNotFound(int $pageNotFoundNumber, ServerRequestInterface $request): void
723  {
724  if (!$pageNotFoundNumber) {
725  return;
726  }
727  $response = match ($pageNotFoundNumber) {
728  1 => GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction(
729  $request,
730  'ID was not an accessible page',
732  ),
733  2 => GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction(
734  $request,
735  'Subsection was found and not accessible',
737  ),
738  3 => GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
739  $request,
740  'ID was outside the domain',
742  ),
743  default => GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
744  $request,
745  'Unspecified error',
747  ),
748  };
749  throw new PropagateResponseException($response, 1533931329);
750  }
751 
797  protected function ‪getPageAndRootline(ServerRequestInterface $request)
798  {
799  $requestedPageRowWithoutGroupCheck = [];
800  $this->page = $this->sys_page->getPage($this->id);
801  if (empty($this->page)) {
802  // If no page, we try to find the page above in the rootLine.
803  // Page is 'not found' in case the id itself was not an accessible page. code 1
804  $this->pageNotFound = 1;
805  $requestedPageIsHidden = false;
806  try {
807  $hiddenField = ‪$GLOBALS['TCA']['pages']['ctrl']['enablecolumns']['disabled'] ?? '';
808  $includeHiddenPages = $this->context->getPropertyFromAspect('visibility', 'includeHiddenPages') || $this->context->getPropertyFromAspect('backend.user', 'isLoggedIn', false);
809  if (!empty($hiddenField) && !$includeHiddenPages) {
810  // Page is "hidden" => 404 (deliberately done in default language, as this cascades to language overlays)
811  $rawPageRecord = $this->sys_page->getPage_noCheck($this->id);
812 
813  // If page record could not be resolved throw exception
814  if ($rawPageRecord === []) {
815  $message = 'The requested page does not exist!';
816  try {
817  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
818  $request,
819  $message,
821  );
822  throw new PropagateResponseException($response, 1674144383);
823  } catch (PageNotFoundException $e) {
824  throw new PageNotFoundException($message, 1674539331);
825  }
826  }
827 
828  $requestedPageIsHidden = (bool)$rawPageRecord[$hiddenField];
829  }
830 
831  $requestedPageRowWithoutGroupCheck = $this->sys_page->getPage($this->id, true);
832  if (!empty($requestedPageRowWithoutGroupCheck)) {
833  $this->pageAccessFailureHistory['direct_access'][] = $requestedPageRowWithoutGroupCheck;
834  }
835  $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
836  if (!empty($this->rootLine)) {
837  $c = count($this->rootLine) - 1;
838  while ($c > 0) {
839  // Add to page access failure history:
840  $this->pageAccessFailureHistory['direct_access'][] = $this->rootLine[$c];
841  // Decrease to next page in rootline and check the access to that, if OK, set as page record and ID value.
842  $c--;
843  $this->id = (int)$this->rootLine[$c]['uid'];
844  $this->page = $this->sys_page->getPage($this->id);
845  if (!empty($this->page)) {
846  break;
847  }
848  }
849  }
850  } catch (RootLineException $e) {
851  $this->rootLine = [];
852  }
853  // If still no page...
854  if ($requestedPageIsHidden || (empty($requestedPageRowWithoutGroupCheck) && empty($this->page))) {
855  $message = 'The requested page does not exist!';
856  try {
857  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
858  $request,
859  $message,
861  );
862  throw new PropagateResponseException($response, 1533931330);
863  } catch (PageNotFoundException $e) {
864  throw new PageNotFoundException($message, 1301648780);
865  }
866  }
867  }
868  // Spacer and sysfolders is not accessible in frontend
869  $pageDoktype = (int)($this->page['doktype'] ?? 0);
870  $isSpacerOrSysfolder = $pageDoktype === ‪PageRepository::DOKTYPE_SPACER || $pageDoktype === ‪PageRepository::DOKTYPE_SYSFOLDER;
871  // Page itself is not accessible, but the parent page is a spacer/sysfolder
872  if ($isSpacerOrSysfolder && !empty($requestedPageRowWithoutGroupCheck)) {
873  try {
874  $response = GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction(
875  $request,
876  'Subsection was found and not accessible',
878  );
879  throw new PropagateResponseException($response, 1633171038);
880  } catch (PageNotFoundException $e) {
881  throw new PageNotFoundException('Subsection was found and not accessible', 1633171172);
882  }
883  }
884 
885  if ($isSpacerOrSysfolder) {
886  $message = 'The requested page does not exist!';
887  try {
888  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
889  $request,
890  $message,
892  );
893  throw new PropagateResponseException($response, 1533931343);
894  } catch (PageNotFoundException $e) {
895  throw new PageNotFoundException($message, 1301648781);
896  }
897  }
898  // Is the ID a link to another page??
899  if ($pageDoktype === ‪PageRepository::DOKTYPE_SHORTCUT) {
900  // We need to clear MP if the page is a shortcut. Reason is if the shortcut goes to another page, then we LEAVE the rootline which the MP expects.
901  $this->MP = '';
902  // saving the page so that we can check later - when we know
903  // about languages - whether we took the correct shortcut or
904  // whether a translation of the page overwrites the shortcut
905  // target and we need to follow the new target
906  $this->originalShortcutPage = ‪$this->page;
907  $this->page = $this->sys_page->resolveShortcutPage($this->page, true);
908  $this->id = (int)$this->page['uid'];
909  $pageDoktype = (int)($this->page['doktype'] ?? 0);
910  }
911  // If the page is a mountpoint which should be overlaid with the contents of the mounted page,
912  // it must never be accessible directly, but only in the mountpoint context. Therefore we change
913  // the current ID and the user is redirected by checkPageForMountpointRedirect().
914  if ($pageDoktype === ‪PageRepository::DOKTYPE_MOUNTPOINT && $this->page['mount_pid_ol']) {
915  $this->originalMountPointPage = ‪$this->page;
916  $this->page = $this->sys_page->getPage($this->page['mount_pid']);
917  if (empty($this->page)) {
918  $message = 'This page (ID ' . $this->originalMountPointPage['uid'] . ') is of type "Mount point" and '
919  . 'mounts a page which is not accessible (ID ' . $this->originalMountPointPage['mount_pid'] . ').';
920  throw new PageNotFoundException($message, 1402043263);
921  }
922  // If the current page is a shortcut, the MP parameter will be replaced
923  if ($this->MP === '' || !empty($this->originalShortcutPage)) {
924  $this->MP = $this->page['uid'] . '-' . $this->originalMountPointPage['uid'];
925  } else {
926  $this->MP .= ',' . $this->page['uid'] . '-' . $this->originalMountPointPage['uid'];
927  }
928  $this->id = (int)$this->page['uid'];
929  $pageDoktype = (int)($this->page['doktype'] ?? 0);
930  }
931  // Gets the rootLine
932  try {
933  $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
934  } catch (RootLineException $e) {
935  $this->rootLine = [];
936  }
937  // If not rootline we're off...
938  if (empty($this->rootLine)) {
939  $message = 'The requested page didn\'t have a proper connection to the tree-root!';
940  $this->‪logPageAccessFailure($message, $request);
941  try {
942  $response = GeneralUtility::makeInstance(ErrorController::class)->internalErrorAction(
943  $request,
944  $message,
946  );
947  throw new PropagateResponseException($response, 1533931350);
948  } catch (AbstractServerErrorException $e) {
949  $this->logger->error($message, ['exception' => $e]);
950  $exceptionClass = get_class($e);
951  throw new $exceptionClass($message, 1301648167);
952  }
953  }
954  // Checking for include section regarding the hidden/starttime/endtime/fe_user (that is access control of a whole subbranch!)
955  if ($this->‪checkRootlineForIncludeSection()) {
956  if (empty($this->rootLine)) {
957  $message = 'The requested page does not exist!';
958  try {
959  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
960  $request,
961  $message,
963  );
964  throw new PropagateResponseException($response, 1533931351);
965  } catch (AbstractServerErrorException $e) {
966  $this->logger->warning($message);
967  $exceptionClass = get_class($e);
968  throw new $exceptionClass($message, 1301648234);
969  }
970  } else {
971  $el = reset($this->rootLine);
972  $this->id = (int)$el['uid'];
973  $this->page = $this->sys_page->getPage($this->id);
974  try {
975  $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
976  } catch (RootLineException $e) {
977  $this->rootLine = [];
978  }
979  }
980  }
981  }
982 
1005  protected function ‪checkRootlineForIncludeSection(): bool
1006  {
1007  $c = count($this->rootLine);
1008  $removeTheRestFlag = false;
1009  $accessVoter = GeneralUtility::makeInstance(RecordAccessVoter::class);
1010  for ($a = 0; $a < $c; $a++) {
1011  if (!$accessVoter->accessGrantedForPageInRootLine($this->rootLine[$a], $this->context)) {
1012  // Add to page access failure history and mark the page as not found
1013  // Keep the rootline however to trigger an access denied error instead of a service unavailable error
1014  $this->pageAccessFailureHistory['sub_section'][] = $this->rootLine[$a];
1015  $this->pageNotFound = 2;
1016  }
1017 
1018  if ((int)$this->rootLine[$a]['doktype'] === ‪PageRepository::DOKTYPE_BE_USER_SECTION) {
1019  // If there is a backend user logged in, check if they have read access to the page:
1020  if ($this->context->getPropertyFromAspect('backend.user', 'isLoggedIn', false)) {
1021  // If there was no page selected, the user apparently did not have read access to the
1022  // current page (not position in rootline) and we set the remove-flag...
1023  if (!$this->‪getBackendUser()->doesUserHaveAccess($this->page, ‪Permission::PAGE_SHOW)) {
1024  $removeTheRestFlag = true;
1025  }
1026  } else {
1027  // Don't go here, if there is no backend user logged in.
1028  $removeTheRestFlag = true;
1029  }
1030  } elseif ((int)$this->rootLine[$a]['doktype'] === ‪PageRepository::DOKTYPE_RECYCLER) {
1031  // page is in a recycler
1032  $removeTheRestFlag = true;
1033  }
1034  if ($removeTheRestFlag) {
1035  // Page is 'not found' in case a subsection was found and not accessible, code 2
1036  $this->pageNotFound = 2;
1037  unset($this->rootLine[$a]);
1038  }
1039  }
1040  return $removeTheRestFlag;
1041  }
1042 
1053  public function ‪checkEnableFields($row, $bypassGroupCheck = false)
1054  {
1055  trigger_error(
1056  'Method ' . __METHOD__ . ' has been deprecated in v12 and will be removed with v13. Use RecordAccessVoter instead.',
1057  E_USER_DEPRECATED
1058  );
1059  return GeneralUtility::makeInstance(RecordAccessVoter::class)->accessGranted('pages', $row, $this->context);
1060  }
1061 
1068  public function ‪getPageAccessFailureReasons(string $failureReasonCode = null)
1069  {
1070  ‪$output = [];
1071  if ($failureReasonCode) {
1072  ‪$output['code'] = $failureReasonCode;
1073  }
1074  $combinedRecords = array_merge(
1075  is_array($this->pageAccessFailureHistory['direct_access'] ?? false) ? $this->pageAccessFailureHistory['direct_access'] : [['fe_group' => 0]],
1076  is_array($this->pageAccessFailureHistory['sub_section'] ?? false) ? $this->pageAccessFailureHistory['sub_section'] : []
1077  );
1078  if (!empty($combinedRecords)) {
1079  $accessVoter = GeneralUtility::makeInstance(RecordAccessVoter::class);
1080  foreach ($combinedRecords as $k => $pagerec) {
1081  // If $k=0 then it is the very first page the original ID was pointing at and that will get a full check of course
1082  // If $k>0 it is parent pages being tested. They are only significant for the access to the first page IF they had the extendToSubpages flag set, hence checked only then!
1083  if (!$k || $pagerec['extendToSubpages']) {
1084  if ($pagerec['hidden'] ?? false) {
1085  ‪$output['hidden'][$pagerec['uid']] = true;
1086  }
1087  if (isset($pagerec['starttime']) && $pagerec['starttime'] > ‪$GLOBALS['SIM_ACCESS_TIME']) {
1088  ‪$output['starttime'][$pagerec['uid']] = $pagerec['starttime'];
1089  }
1090  if (isset($pagerec['endtime']) && $pagerec['endtime'] != 0 && $pagerec['endtime'] <= ‪$GLOBALS['SIM_ACCESS_TIME']) {
1091  ‪$output['endtime'][$pagerec['uid']] = $pagerec['endtime'];
1092  }
1093  if (!$accessVoter->groupAccessGranted('pages', $pagerec, $this->context)) {
1094  ‪$output['fe_group'][$pagerec['uid']] = $pagerec['fe_group'];
1095  }
1096  }
1097  }
1098  }
1099  return ‪$output;
1100  }
1101 
1102  /********************************************
1103  *
1104  * Template and caching related functions.
1105  *
1106  *******************************************/
1107 
1108  protected function ‪setPageArguments(‪PageArguments ‪$pageArguments): void
1109  {
1110  $this->pageArguments = ‪$pageArguments;
1111  $this->id = $pageArguments->‪getPageId();
1112  // We store the originally requested id
1113  $this->requestedId = ‪$this->id;
1114  $this->type = (int)(‪$pageArguments->‪getPageType() ?: 0);
1115  if (‪$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1116  $this->MP = (string)(‪$pageArguments->getArguments()['MP'] ?? '');
1117  // Ensure no additional arguments are given via the &MP=123-345,908-172 (e.g. "/")
1118  $this->MP = preg_replace('/[^0-9,-]/', '', $this->MP);
1119  }
1120  }
1121 
1127  {
1128  $queryParams = ‪$pageArguments->getDynamicArguments();
1129  if (!empty($queryParams) && (‪$pageArguments->getArguments()['cHash'] ?? false)) {
1130  $queryParams['id'] = ‪$pageArguments->‪getPageId();
1131  return GeneralUtility::makeInstance(CacheHashCalculator::class)
1132  ->getRelevantParameters(‪HttpUtility::buildQueryString($queryParams));
1133  }
1134  return [];
1135  }
1136 
1155  public function ‪getFromCache(ServerRequestInterface $request): ServerRequestInterface
1156  {
1157  // Reset some state.
1158  // @todo: Find out which resets are really needed here - Since this is called from a
1159  // relatively early middleware, we can expect these properties to be not set already?!
1160  $this->content = '';
1161  $this->config = [];
1162  $this->pageContentWasLoadedFromCache = false;
1163 
1164  // Very first thing, *always* executed: TypoScript is one factor that influences page content.
1165  // There can be multiple cache entries per page, when TypoScript conditions on the same page
1166  // create different TypoScript. We thus need the sys_template rows relevant for this page.
1167  // @todo: Even though all rootline sys_template records are fetched with only one query
1168  // in below implementation, we could potentially join or sub select sys_template
1169  // records already when pages rootline is queried. This will save one query
1170  // and needs an implementation in getPageAndRootline() which is called via determineId()
1171  // in TypoScriptFrontendInitialization. This could be done when getPageAndRootline()
1172  // switches to a CTE query instead of using RootlineUtility.
1173  $sysTemplateRepository = GeneralUtility::makeInstance(SysTemplateRepository::class);
1174  $sysTemplateRows = $sysTemplateRepository->getSysTemplateRowsByRootline($this->rootLine, $request);
1175  // Needed for cache calculations. Put into a variable here to not serialize multiple times.
1176  $serializedSysTemplateRows = serialize($sysTemplateRows);
1177 
1178  // Early exception if there is no sys_template at all.
1179  if (empty($sysTemplateRows)) {
1180  $message = 'No TypoScript record found!';
1181  $this->logger->alert($message);
1182  try {
1183  $response = GeneralUtility::makeInstance(ErrorController::class)->internalErrorAction(
1184  $request,
1185  $message,
1187  );
1188  throw new ‪PropagateResponseException($response, 1533931380);
1189  } catch (‪AbstractServerErrorException $e) {
1190  $exceptionClass = get_class($e);
1191  throw new $exceptionClass($message, 1294587218);
1192  }
1193  }
1194 
1195  if (!$this->tmpl instanceof TemplateService) {
1196  // @deprecated since v12, will be removed in v13: b/w compat. Remove when TemplateService is dropped.
1197  $this->tmpl = GeneralUtility::makeInstance(TemplateService::class, $this->context, null, $this);
1198  }
1199 
1200  // Calculate "local" rootLine that stops at first root=1 template, will be set as $this->config['rootLine']
1201  $sysTemplateRowsIndexedByPid = array_combine(array_column($sysTemplateRows, 'pid'), $sysTemplateRows);
1202  $localRootline = [];
1203  foreach ($this->rootLine as $rootlinePage) {
1204  array_unshift($localRootline, $rootlinePage);
1205  if ((int)($rootlinePage['uid'] ?? 0) > 0
1206  && (int)($sysTemplateRowsIndexedByPid[$rootlinePage['uid']]['root'] ?? 0) === 1
1207  ) {
1208  break;
1209  }
1210  }
1211  // @deprecated: since v12, will be removed in v13: b/w compat. Remove when TemplateService is dropped.
1212  $this->tmpl->rootLine = $localRootline;
1213 
1214  ‪$site = $this->‪getSite();
1215 
1216  $tokenizer = new LossyTokenizer();
1217  $treeBuilder = GeneralUtility::makeInstance(SysTemplateTreeBuilder::class);
1218  $includeTreeTraverser = new IncludeTreeTraverser();
1219  $includeTreeTraverserConditionVerdictAware = new ConditionVerdictAwareIncludeTreeTraverser();
1220  $cacheManager = GeneralUtility::makeInstance(CacheManager::class);
1222  $typoscriptCache = null;
1223  if (!$this->no_cache) {
1224  // $this->no_cache = true might have been set by earlier TypoScriptFrontendInitialization middleware.
1225  // This means we don't do fancy cache stuff, calculate full TypoScript and ignore page cache.
1227  $typoscriptCache = $cacheManager->getCache('typoscript');
1228  }
1229 
1230  $topDownRootLine = ‪$this->rootLine;
1231  ksort($topDownRootLine);
1232  $expressionMatcherVariables = [
1233  'request' => $request,
1234  'pageId' => ‪$this->id,
1235  'page' => $this->rootLine[array_key_first($this->rootLine)],
1236  'fullRootLine' => $topDownRootLine,
1237  'localRootLine' => $localRootline,
1238  'site' => ‪$site,
1239  'siteLanguage' => $request->‪getAttribute('language'),
1240  'tsfe' => $this,
1241  ];
1242 
1243  // We *always* need the TypoScript constants, one way or the other: Setup conditions can use constants,
1244  // so we need the constants to substitute their values within setup conditions.
1245  $constantConditionIncludeListCacheIdentifier = 'constant-condition-include-list-' . sha1($serializedSysTemplateRows);
1246  $constantConditionList = [];
1247  $constantsAst = new RootNode();
1248  $flatConstants = [];
1249  $serializedConstantConditionList = '';
1250  $gotConstantFromCache = false;
1251  if (!$this->no_cache && $constantConditionIncludeTree = $typoscriptCache->require($constantConditionIncludeListCacheIdentifier)) {
1252  // We got the flat list of all constants conditions for this TypoScript combination from cache. Good. We traverse
1253  // this list to calculate "current" condition verdicts. With a hash of this list together with a hash of the
1254  // TypoScript sys_templates, we try to retrieve the full constants TypoScript from cache.
1255  $conditionMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
1256  $conditionMatcherVisitor->initializeExpressionMatcherWithVariables($expressionMatcherVariables);
1257  $includeTreeTraverser->addVisitor($conditionMatcherVisitor);
1258  // It does not matter if we use IncludeTreeTraverser or ConditionVerdictAwareIncludeTreeTraverser here:
1259  // Condition list is flat, not nested. IncludeTreeTraverser has an if() less, so we use that one.
1260  $includeTreeTraverser->traverse($constantConditionIncludeTree);
1261  $constantConditionList = $conditionMatcherVisitor->getConditionListWithVerdicts();
1262  // Needed for cache identifier calculations. Put into a variable here to not serialize multiple times.
1263  $serializedConstantConditionList = serialize($constantConditionList);
1264  $constantCacheEntryIdentifier = 'constant-' . sha1($serializedSysTemplateRows . $serializedConstantConditionList);
1265  $constantsCacheEntry = $typoscriptCache->require($constantCacheEntryIdentifier);
1266  if (is_array($constantsCacheEntry)) {
1267  $constantsAst = $constantsCacheEntry['ast'];
1268  $flatConstants = $constantsCacheEntry['flatConstants'];
1269  $gotConstantFromCache = true;
1270  }
1271  }
1272  if ($this->no_cache || !$gotConstantFromCache) {
1273  // We did not get constants from cache, or are not allowed to use cache. We have to build constants from scratch.
1274  // This means we'll fetch the full constants include tree (from cache if possible), register the condition
1275  // matcher and register the AST builder and traverse include tree to retrieve constants AST and calculate
1276  // 'flat constants' from it. Both are cached if allowed afterwards for the 'if' above to kick in next time.
1277  if ($this->no_cache) {
1278  // Note $typoscriptCache *is not* hand over here: IncludeTree is calculated from scratch, we're not allowed to use cache.
1279  $constantIncludeTree = $treeBuilder->getTreeBySysTemplateRowsAndSite('constants', $sysTemplateRows, $tokenizer, ‪$site);
1280  } else {
1281  // Note $typoscriptCache *is* hand over here, we can potentially grab the fully cached includeTree here, or cache entry will be created.
1282  $constantIncludeTree = $treeBuilder->getTreeBySysTemplateRowsAndSite('constants', $sysTemplateRows, $tokenizer, ‪$site, $typoscriptCache);
1283  }
1284  $conditionMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
1285  $conditionMatcherVisitor->initializeExpressionMatcherWithVariables($expressionMatcherVariables);
1286  $includeTreeTraverserConditionVerdictAware->addVisitor($conditionMatcherVisitor);
1287  $constantAstBuilderVisitor = GeneralUtility::makeInstance(IncludeTreeAstBuilderVisitor::class);
1288  $includeTreeTraverserConditionVerdictAware->addVisitor($constantAstBuilderVisitor);
1289  // We must use ConditionVerdictAwareIncludeTreeTraverser here: This one does not walk into
1290  // children for not matching conditions, which is important to create the correct AST.
1291  $includeTreeTraverserConditionVerdictAware->traverse($constantIncludeTree);
1292  $constantsAst = $constantAstBuilderVisitor->getAst();
1293  $flatConstants = $constantsAst->flatten();
1294  if (!$this->no_cache) {
1295  // We are allowed to cache and can create both the full list of conditions, plus the constant AST and flat constant
1296  // list cache entry. To do that, we need all (!) conditions, but the above ConditionVerdictAwareIncludeTreeTraverser
1297  // did not find nested conditions if an upper condition did not match. We thus have to traverse include tree a
1298  // second time with the IncludeTreeTraverser that does traverse into not matching conditions as well.
1299  $includeTreeTraverser->resetVisitors();
1300  $conditionMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
1301  $conditionMatcherVisitor->initializeExpressionMatcherWithVariables($expressionMatcherVariables);
1302  $includeTreeTraverser->addVisitor($conditionMatcherVisitor);
1303  $constantConditionIncludeListAccumulatorVisitor = new IncludeTreeConditionIncludeListAccumulatorVisitor();
1304  $includeTreeTraverser->addVisitor($constantConditionIncludeListAccumulatorVisitor);
1305  $includeTreeTraverser->traverse($constantIncludeTree);
1306  $constantConditionList = $conditionMatcherVisitor->getConditionListWithVerdicts();
1307  // Needed for cache identifier calculations. Put into a variable here to not serialize multiple times.
1308  $serializedConstantConditionList = serialize($constantConditionList);
1309  $typoscriptCache->set($constantConditionIncludeListCacheIdentifier, 'return unserialize(\'' . addcslashes(serialize($constantConditionIncludeListAccumulatorVisitor->getConditionIncludes()), '\'\\') . '\');');
1310  $constantCacheEntryIdentifier = 'constant-' . sha1($serializedSysTemplateRows . $serializedConstantConditionList);
1311  $typoscriptCache->set($constantCacheEntryIdentifier, 'return unserialize(\'' . addcslashes(serialize(['ast' => $constantsAst, 'flatConstants' => $flatConstants]), '\'\\') . '\');');
1312  }
1313  }
1314 
1315  $frontendTypoScript = new FrontendTypoScript($constantsAst, $flatConstants);
1316 
1317  // Next step: We have constants and fetch the setup include tree now. We then calculate setup condition verdicts
1318  // and set the constants to allow substitution of constants within conditions. Next, we traverse include tree
1319  // to calculate conditions verdicts and gather them along the way. A hash of these conditions with their verdicts
1320  // is then part of the page cache identifier hash: When a condition on a page creates a different result, the hash
1321  // is different from an existing page cache entry and a new one is created later.
1322  $setupConditionIncludeListCacheIdentifier = 'setup-condition-include-list-' . sha1($serializedSysTemplateRows . $serializedConstantConditionList);
1323  $setupConditionList = [];
1324  $gotSetupConditionsFromCache = false;
1325  if (!$this->no_cache && $setupConditionIncludeTree = $typoscriptCache->require($setupConditionIncludeListCacheIdentifier)) {
1326  // We got the flat list of all setup conditions for this TypoScript combination from cache. Good. We traverse
1327  // this list to calculate "current" condition verdicts, which we need as hash to be part of page cache identifier.
1328  $includeTreeTraverser->resetVisitors();
1329  $setupConditionConstantSubstitutionVisitor = new IncludeTreeSetupConditionConstantSubstitutionVisitor();
1330  $setupConditionConstantSubstitutionVisitor->setFlattenedConstants($flatConstants);
1331  $includeTreeTraverser->addVisitor($setupConditionConstantSubstitutionVisitor);
1332  $setupMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
1333  $setupMatcherVisitor->initializeExpressionMatcherWithVariables($expressionMatcherVariables);
1334  $includeTreeTraverser->addVisitor($setupMatcherVisitor);
1335  // It does not matter if we use IncludeTreeTraverser or ConditionVerdictAwareIncludeTreeTraverser here:
1336  // Condition list is flat, not nested. IncludeTreeTraverser has an if() less, so we use that one.
1337  $includeTreeTraverser->traverse($setupConditionIncludeTree);
1338  $setupConditionList = $setupMatcherVisitor->getConditionListWithVerdicts();
1339  $gotSetupConditionsFromCache = true;
1340  }
1341  if ($this->no_cache || !$gotSetupConditionsFromCache) {
1342  // We did not get setup condition list from cache, or are not allowed to use cache. We have to build setup
1343  // condition list from scratch. This means we'll fetch the full setup include tree (from cache if possible),
1344  // register the constant substitution visitor, and register condition matcher and register the condition
1345  // accumulator visitor.
1346  if ($this->no_cache) {
1347  // Note $typoscriptCache *is not* hand over here: IncludeTree is calculated from scratch, we're not allowed to use cache.
1348  $setupIncludeTree = $treeBuilder->getTreeBySysTemplateRowsAndSite('setup', $sysTemplateRows, $tokenizer, ‪$site);
1349  } else {
1350  // Note $typoscriptCache *is* hand over here, we can potentially grab the fully cached includeTree here, or cache entry will be created.
1351  $setupIncludeTree = $treeBuilder->getTreeBySysTemplateRowsAndSite('setup', $sysTemplateRows, $tokenizer, ‪$site, $typoscriptCache);
1352  }
1353  $includeTreeTraverser->resetVisitors();
1354  $setupConditionConstantSubstitutionVisitor = new IncludeTreeSetupConditionConstantSubstitutionVisitor();
1355  $setupConditionConstantSubstitutionVisitor->setFlattenedConstants($flatConstants);
1356  $includeTreeTraverser->addVisitor($setupConditionConstantSubstitutionVisitor);
1357  $setupMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
1358  $setupMatcherVisitor->initializeExpressionMatcherWithVariables($expressionMatcherVariables);
1359  $includeTreeTraverser->addVisitor($setupMatcherVisitor);
1360  $setupConditionIncludeListAccumulatorVisitor = new IncludeTreeConditionIncludeListAccumulatorVisitor();
1361  $includeTreeTraverser->addVisitor($setupConditionIncludeListAccumulatorVisitor);
1362  // It is important we use IncludeTreeTraverser here: We to have the condition verdicts of *all* conditions, plus
1363  // want to accumulate all of them. The ConditionVerdictAwareIncludeTreeTraverser wouldn't walk into nested
1364  // conditions if an upper one does not match.
1365  $includeTreeTraverser->traverse($setupIncludeTree);
1366  $setupConditionList = $setupMatcherVisitor->getConditionListWithVerdicts();
1367  if (!$this->no_cache) {
1368  $typoscriptCache->set($setupConditionIncludeListCacheIdentifier, 'return unserialize(\'' . addcslashes(serialize($setupConditionIncludeListAccumulatorVisitor->getConditionIncludes()), '\'\\') . '\');');
1369  }
1370  }
1371 
1372  // We now gathered everything to calculate the page cache identifier: It depends on sys_template rows, the calculated
1373  // constant condition verdicts, the setup condition verdicts, plus various not TypoScript related details like
1374  // obviously the page id.
1375  $this->lock = GeneralUtility::makeInstance(ResourceMutex::class);
1376  $this->newHash = $this->‪createHashBase($sysTemplateRows, $constantConditionList, $setupConditionList);
1377  if (!$this->no_cache) {
1378  if ($this->‪shouldAcquireCacheData($request)) {
1379  // Try to get a page cache row.
1380  $this->‪getTimeTracker()->‪push('Cache Row');
1381  $pageCacheRow = $this->pageCache->get($this->newHash);
1382  if (!is_array($pageCacheRow)) {
1383  // Nothing in the cache, we acquire an exclusive lock now.
1384  // There are two scenarios when locking: We're either the first process acquiring this lock. This means we'll
1385  // "immediately" get it and can continue with page rendering. Or, another process acquired the lock already. In
1386  // this case, the below call will wait until the lock is released again. The other process then probably wrote
1387  // a page cache entry, which we can use.
1388  // To handle the second case - if our process had to wait for another one creating the content for us - we
1389  // simply query the page cache again to see if there is a page cache now.
1390  $hadToWaitForLock = $this->lock->acquireLock('pages', $this->newHash);
1391  // From this point on we're the only one working on that page.
1392  if ($hadToWaitForLock) {
1393  // Query the cache again to see if the data is there meanwhile: We did not get the lock
1394  // immediately, chances are high the other process created a page cache for us.
1395  // There is a small chance the other process actually pageCache->set() the content,
1396  // but pageCache->get() still returns false, for instance when a database returned "done"
1397  // for the INSERT, but SELECT still does not return the new row - may happen in multi-head
1398  // DB instances, and with some other distributed cache backends as well. The worst that
1399  // can happen here is the page generation is done too often, which we accept as trade-off.
1400  $pageCacheRow = $this->pageCache->get($this->newHash);
1401  if (is_array($pageCacheRow)) {
1402  // We have the content, some other process did the work for us, release our lock again.
1403  $this->‪releaseLocks();
1404  }
1405  }
1406  // We keep the lock set, because we are the ones generating the page now and filling the cache.
1407  // This indicates that we have to release the lock later in releaseLocks()!
1408  }
1409  if (is_array($pageCacheRow)) {
1410  // Note this especially populates $this->config!
1411  $this->‪populatePageDataFromCache($pageCacheRow);
1412  }
1413  $this->‪getTimeTracker()->‪pull();
1414  } else {
1415  // User forced page cache rebuilding. Get a lock for the page content so other processes can't interfere.
1416  $this->lock->acquireLock('pages', $this->newHash);
1417  }
1418  } else {
1419  // Caching is not allowed. We'll rebuild the page. Lock this.
1420  $this->lock->acquireLock('pages', $this->newHash);
1421  }
1422 
1423  $forceTemplateParsing = $this->context->getPropertyFromAspect('typoscript', 'forcedTemplateParsing');
1424  if ($this->no_cache || empty($this->config) || $this->‪isINTincScript() || $forceTemplateParsing) {
1425  // We don't need the full setup AST in many cached scenarios. However, if no_cache is set, if no page cache
1426  // entry could be loaded, if the page cache entry has _INT object, or if the user forced template
1427  // parsing (adminpanel), then we still need the full setup AST. If there is "just" an _INT object, we can
1428  // use a possible cache entry for the setup AST, which speeds up _INT parsing quite a bit. In other cases
1429  // we calculate full setup AST and cache it if allowed.
1430  $setupTypoScriptCacheIdentifier = 'setup-' . sha1($serializedSysTemplateRows . $serializedConstantConditionList . serialize($setupConditionList));
1431  $gotSetupFromCache = false;
1432  $setupArray = [];
1433  if (!$this->no_cache && !$forceTemplateParsing) {
1434  // We need AST, but we are allowed to potentially get it from cache.
1435  if ($setupTypoScriptCache = $typoscriptCache->require($setupTypoScriptCacheIdentifier)) {
1436  $frontendTypoScript->setSetupTree($setupTypoScriptCache['ast']);
1437  $setupArray = $setupTypoScriptCache['array'];
1438  $gotSetupFromCache = true;
1439  }
1440  }
1441  if ($this->no_cache || $forceTemplateParsing || !$gotSetupFromCache) {
1442  // We need AST and couldn't get it from cache or are now allowed to. We thus need the full setup
1443  // IncludeTree, which we can get from cache again if allowed, or is calculated a-new if not.
1444  if ($this->no_cache || $forceTemplateParsing) {
1445  // Note $typoscriptCache *is not* hand over here: IncludeTree is calculated from scratch, we're not allowed to use cache.
1446  $setupIncludeTree = $treeBuilder->getTreeBySysTemplateRowsAndSite('setup', $sysTemplateRows, $tokenizer, ‪$site);
1447  } else {
1448  // Note $typoscriptCache *is* hand over here, we can potentially grab the fully cached includeTree here, or cache entry will be created.
1449  $setupIncludeTree = $treeBuilder->getTreeBySysTemplateRowsAndSite('setup', $sysTemplateRows, $tokenizer, ‪$site, $typoscriptCache);
1450  }
1451  $includeTreeTraverserConditionVerdictAware->resetVisitors();
1452  $setupConditionConstantSubstitutionVisitor = new IncludeTreeSetupConditionConstantSubstitutionVisitor();
1453  $setupConditionConstantSubstitutionVisitor->setFlattenedConstants($flatConstants);
1454  $includeTreeTraverserConditionVerdictAware->addVisitor($setupConditionConstantSubstitutionVisitor);
1455  $setupMatcherVisitor = GeneralUtility::makeInstance(IncludeTreeConditionMatcherVisitor::class);
1456  $setupMatcherVisitor->initializeExpressionMatcherWithVariables($expressionMatcherVariables);
1457  $includeTreeTraverserConditionVerdictAware->addVisitor($setupMatcherVisitor);
1458  $setupAstBuilderVisitor = GeneralUtility::makeInstance(IncludeTreeAstBuilderVisitor::class);
1459  $setupAstBuilderVisitor->setFlatConstants($flatConstants);
1460  $includeTreeTraverserConditionVerdictAware->addVisitor($setupAstBuilderVisitor);
1461  $includeTreeTraverserConditionVerdictAware->traverse($setupIncludeTree);
1462  $setupAst = $setupAstBuilderVisitor->getAst();
1463  $frontendTypoScript->setSetupTree($setupAst);
1464 
1465  // Create top-level setup AST 'types' node from all top-level PAGE objects.
1466  // This is essentially a preparation for type-lookup below and should vanish later.
1467  $typesNode = new ChildNode('types');
1468  $gotTypeNumZero = false;
1469  foreach ($setupAst->getNextChild() as $setupChild) {
1470  if ($setupChild->getValue() === 'PAGE') {
1471  $typeNumChild = $setupChild->getChildByName('typeNum');
1472  if ($typeNumChild) {
1473  $typeNumValue = $typeNumChild->getValue();
1474  $typesSubNode = new ChildNode($typeNumValue);
1475  $typesSubNode->setValue($setupChild->getName());
1476  $typesNode->addChild($typesSubNode);
1477  if ($typeNumValue === '0') {
1478  $gotTypeNumZero = true;
1479  }
1480  } elseif (!$gotTypeNumZero) {
1481  // The first PAGE node that has no typeNum = 0 is considered '0' automatically.
1482  $typesSubNode = new ChildNode('0');
1483  $typesSubNode->setValue($setupChild->getName());
1484  $typesNode->addChild($typesSubNode);
1485  $gotTypeNumZero = true;
1486  }
1487  }
1488  }
1489  if ($typesNode->hasChildren()) {
1490  $setupAst->addChild($typesNode);
1491  }
1492  $setupArray = $setupAst->toArray();
1493  if (!$this->no_cache && !$forceTemplateParsing) {
1494  // Write cache entry for AST and its array representation, we're allowed to do it.
1495  $typoscriptCache->set($setupTypoScriptCacheIdentifier, 'return unserialize(\'' . addcslashes(serialize(['ast' => $setupAst, 'array' => $setupArray]), '\'\\') . '\');');
1496  }
1497  }
1498 
1499  $typoScriptPageTypeName = $setupArray['types.'][‪$this->type] ?? '';
1500  $this->pSetup = $setupArray[$typoScriptPageTypeName . '.'] ?? '';
1501 
1502  if (!is_array($this->pSetup)) {
1503  $this->logger->alert('The page is not configured! [type={type}][{type_name}].', ['type' => $this->type, 'type_name' => $typoScriptPageTypeName]);
1504  try {
1505  $message = 'The page is not configured! [type=' . $this->type . '][' . $typoScriptPageTypeName . '].';
1506  $response = GeneralUtility::makeInstance(ErrorController::class)->internalErrorAction(
1507  $request,
1508  $message,
1510  );
1511  throw new PropagateResponseException($response, 1533931374);
1512  } catch (AbstractServerErrorException $e) {
1513  $explanation = 'This means that there is no TypoScript object of type PAGE with typeNum=' . $this->type . ' configured.';
1514  $exceptionClass = get_class($e);
1515  throw new $exceptionClass($message . ' ' . $explanation, 1294587217);
1516  }
1517  }
1518 
1519  if (!isset($this->config['config'])) {
1520  $this->config['config'] = [];
1521  }
1522  // Filling the config-array, first with the main "config." part
1523  if (is_array($setupArray['config.'] ?? null)) {
1524  // @todo: These operations should happen on AST instead and array is exported (and cached) afterwards
1525  $setupArray['config.'] = array_replace_recursive($setupArray['config.'], $this->config['config']);
1526  $this->config['config'] = $setupArray['config.'];
1527  }
1528  // Override it with the page/type-specific "config."
1529  if (is_array($this->pSetup['config.'] ?? null)) {
1530  $this->config['config'] = array_replace_recursive($this->config['config'], $this->pSetup['config.']);
1531  }
1532  $this->config['rootLine'] = $localRootline;
1533  $frontendTypoScript->setSetupArray($setupArray);
1534 
1535  // @deprecated: since v12, will be removed in v13: b/w compat. Remove when TemplateService is dropped.
1536  $this->tmpl->setup = $setupArray;
1537  $this->tmpl->loaded = true;
1538  $this->tmpl->flatSetup = $flatConstants;
1539  }
1540 
1541  // Set $this->no_cache TRUE if the config.no_cache value is set!
1542  if (!$this->no_cache && ($this->config['config']['no_cache'] ?? false)) {
1543  $this->‪set_no_cache('config.no_cache is set', true);
1544  }
1545 
1546  // Auto-configure settings when a site is configured
1547  $this->config['config']['absRefPrefix'] = $this->config['config']['absRefPrefix'] ?? 'auto';
1549  // Hook for postProcessing the configuration array
1550  $params = ['config' => &$this->config['config']];
1551  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'] ?? [] as $funcRef) {
1552  GeneralUtility::callUserFunction($funcRef, $params, $this);
1553  }
1554 
1555  return $request->withAttribute('frontend.typoscript', $frontendTypoScript);
1556  }
1557 
1568  protected function ‪populatePageDataFromCache(array $cachedData): void
1569  {
1570  // Call hook when a page is retrieved from cache
1571  $_params = ['pObj' => &$this, 'cache_pages_row' => &$cachedData];
1572  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'] ?? [] as $_funcRef) {
1573  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1574  }
1575  // Fetches the lowlevel config stored with the cached data
1576  $this->config = $cachedData['cache_data'];
1577  // Getting the content
1578  $this->content = $cachedData['content'];
1579  // Getting the content type
1580  $this->contentType = $cachedData['contentType'] ?? $this->contentType;
1581  // Setting flag, so we know, that some cached content has been loaded
1582  $this->pageContentWasLoadedFromCache = true;
1583  $this->cacheExpires = $cachedData['expires'];
1584  // Restore the current tags as they can be retrieved by getPageCacheTags()
1585  $this->pageCacheTags = $cachedData['cacheTags'] ?? [];
1586 
1587  if (isset($this->config['config']['debug'])) {
1588  $debugCacheTime = (bool)$this->config['config']['debug'];
1589  } else {
1590  $debugCacheTime = !empty(‪$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']);
1591  }
1592  if ($debugCacheTime) {
1593  $dateFormat = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
1594  $timeFormat = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
1595  $this->debugInformationHeader = 'Cached page generated ' . date($dateFormat . ' ' . $timeFormat, $cachedData['tstamp'])
1596  . '. Expires ' . date($dateFormat . ' ' . $timeFormat, $cachedData['expires']);
1597  }
1598  }
1599 
1608  protected function ‪shouldAcquireCacheData(ServerRequestInterface $request): bool
1609  {
1610  // Trigger event for possible by-pass of requiring of page cache (for re-caching purposes)
1611  $event = new ShouldUseCachedPageDataIfAvailableEvent($request, $this, !$this->no_cache);
1612  GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch($event);
1613  return $event->shouldUseCachedPageData();
1614  }
1615 
1627  protected function ‪createHashBase(array $sysTemplateRows, array $constantConditionList, array $setupConditionList): string
1628  {
1629  // Fetch the list of user groups
1631  $userAspect = $this->context->getAspect('frontend.user');
1632  $hashParameters = [
1633  'id' => ‪$this->id,
1634  'type' => ‪$this->type,
1635  'groupIds' => (string)implode(',', $userAspect->getGroupIds()),
1636  'MP' => (string)‪$this->MP,
1637  'site' => $this->‪site->getIdentifier(),
1638  // Ensure the language base is used for the hash base calculation as well, otherwise TypoScript and page-related rendering
1639  // is not cached properly as we don't have any language-specific conditions anymore
1640  'siteBase' => (string)$this->‪language->getBase(),
1641  // additional variation trigger for static routes
1642  'staticRouteArguments' => $this->pageArguments->getStaticArguments(),
1643  // dynamic route arguments (if route was resolved)
1644  'dynamicArguments' => $this->‪getRelevantParametersForCachingFromPageArguments($this->pageArguments),
1645  'sysTemplateRows' => $sysTemplateRows,
1646  'constantConditionList' => $constantConditionList,
1647  'setupConditionList' => $setupConditionList,
1648  ];
1649  // Call hook to influence the hash calculation
1650  $_params = [
1651  'hashParameters' => &$hashParameters,
1652  ];
1653  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'] ?? [] as $_funcRef) {
1654  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1655  }
1656  return $this->id . '_' . sha1(serialize($hashParameters));
1657  }
1658 
1659  /********************************************
1660  *
1661  * Further initialization and data processing
1662  *
1663  *******************************************/
1670  protected function ‪settingLanguage(ServerRequestInterface $request)
1671  {
1672  // Get values from site language
1674 
1675  $languageId = $languageAspect->getId();
1676  $languageContentId = $languageAspect->getContentId();
1677 
1678  $pageTranslationVisibility = new PageTranslationVisibility((int)($this->page['l18n_cfg'] ?? 0));
1679  // If the incoming language is set to another language than default
1680  if ($languageAspect->getId() > 0) {
1681  // Request the translation for the requested language
1682  $olRec = $this->sys_page->getPageOverlay($this->page, $languageAspect);
1683  $overlaidLanguageId = (int)($olRec['sys_language_uid'] ?? 0);
1684  if ($overlaidLanguageId !== $languageAspect->getId()) {
1685  // If requested translation is not available
1686  if ($pageTranslationVisibility->shouldHideTranslationIfNoTranslatedRecordExists()) {
1687  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
1688  $request,
1689  'Page is not available in the requested language.',
1691  );
1692  throw new PropagateResponseException($response, 1533931388);
1693  }
1694  switch ($languageAspect->getLegacyLanguageMode()) {
1695  case 'strict':
1696  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
1697  $request,
1698  'Page is not available in the requested language (strict).',
1700  );
1701  throw new PropagateResponseException($response, 1533931395);
1702  case 'content_fallback':
1703  // Setting content uid (but leaving the sys_language_uid) when a content_fallback
1704  // value was found.
1705  foreach ($languageAspect->getFallbackChain() as $orderValue) {
1706  if ($orderValue === '0' || $orderValue === 0 || $orderValue === '') {
1707  $languageContentId = 0;
1708  break;
1709  }
1710  if (‪MathUtility::canBeInterpretedAsInteger($orderValue) && $overlaidLanguageId === (int)$orderValue) {
1711  $languageContentId = (int)$orderValue;
1712  break;
1713  }
1714  if ($orderValue === 'pageNotFound') {
1715  // The existing fallbacks have not been found, but instead of continuing
1716  // page rendering with default language, a "page not found" message should be shown
1717  // instead.
1718  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
1719  $request,
1720  'Page is not available in the requested language (fallbacks did not apply).',
1722  );
1723  throw new PropagateResponseException($response, 1533931402);
1724  }
1725  }
1726  break;
1727  default:
1728  // Default is that everything defaults to the default language...
1729  $languageId = ($languageContentId = 0);
1730  }
1731  }
1732 
1733  // Define the language aspect again now
1734  $languageAspect = GeneralUtility::makeInstance(
1735  LanguageAspect::class,
1736  $languageId,
1737  $languageContentId,
1738  $languageAspect->getOverlayType(),
1739  $languageAspect->getFallbackChain()
1740  );
1741 
1742  // Setting the $this->page if an overlay record was found (which it is only if a language is used)
1743  // Doing this ensures that page properties like the page title are resolved in the correct language
1744  $this->page = $olRec;
1745  }
1746 
1747  // Set the language aspect
1748  $this->context->setAspect('language', $languageAspect);
1749 
1750  // Setting sys_language_uid inside sys-page by creating a new page repository
1751  $this->sys_page = GeneralUtility::makeInstance(PageRepository::class, $this->context);
1752  // If default language is not available
1753  if ((!$languageAspect->getContentId() || !$languageAspect->getId())
1754  && $pageTranslationVisibility->shouldBeHiddenInDefaultLanguage()
1755  ) {
1756  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
1757  $request,
1758  'Page is not available in default language.',
1760  );
1761  throw new ‪PropagateResponseException($response, 1533931423);
1762  }
1763 
1764  if ($languageAspect->getId() > 0) {
1766  }
1767  }
1768 
1772  protected function ‪updateRootLinesWithTranslations()
1773  {
1774  try {
1775  $this->rootLine = GeneralUtility::makeInstance(RootlineUtility::class, $this->id, $this->MP, $this->context)->get();
1776  } catch (RootLineException $e) {
1777  $this->rootLine = [];
1778  }
1779  }
1780 
1787  public function ‪calculateLinkVars(array $queryParams)
1788  {
1789  $this->linkVars = GeneralUtility::makeInstance(LinkVarsCalculator::class)
1790  ->getAllowedLinkVarsFromRequest(
1791  (string)($this->config['config']['linkVars'] ?? ''),
1792  $queryParams,
1793  $this->context
1794  );
1795  }
1796 
1805  public function ‪getRedirectUriForMountPoint(ServerRequestInterface $request): ?string
1806  {
1807  if (!empty($this->originalMountPointPage) && (int)$this->originalMountPointPage['doktype'] === ‪PageRepository::DOKTYPE_MOUNTPOINT) {
1808  return $this->‪getUriToCurrentPageForRedirect($request);
1809  }
1810 
1811  return null;
1812  }
1813 
1823  public function ‪getRedirectUriForShortcut(ServerRequestInterface $request): ?string
1824  {
1825  if (!empty($this->originalShortcutPage) && $this->originalShortcutPage['doktype'] == ‪PageRepository::DOKTYPE_SHORTCUT) {
1826  // Check if the shortcut page is actually on the current site, if not, this is a "page not found"
1827  // because the request was www.mydomain.com/?id=23 where page ID 23 (which is a shortcut) is on another domain/site.
1828  if ((int)($request->getQueryParams()['id'] ?? 0) > 0) {
1829  try {
1830  ‪$site = GeneralUtility::makeInstance(SiteFinder::class)->getSiteByPageId($this->originalShortcutPage['l10n_parent'] ?: $this->originalShortcutPage['uid']);
1831  } catch (SiteNotFoundException $e) {
1832  ‪$site = null;
1833  }
1834  if (‪$site !== $this->‪site) {
1835  $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
1836  $request,
1837  'ID was outside the domain',
1839  );
1840  throw new ‪ImmediateResponseException($response, 1638022483);
1841  }
1842  }
1843  return $this->‪getUriToCurrentPageForRedirect($request);
1844  }
1845 
1846  return null;
1847  }
1848 
1852  protected function ‪getUriToCurrentPageForRedirect(ServerRequestInterface $request): string
1853  {
1854  $this->‪calculateLinkVars($request->getQueryParams());
1855  $parameter = $this->page['uid'];
1856  if ($this->type) {
1857  $parameter .= ',' . ‪$this->type;
1858  }
1859  return GeneralUtility::makeInstance(ContentObjectRenderer::class, $this)->createUrl([
1860  'parameter' => $parameter,
1861  'addQueryString' => 'untrusted',
1862  'addQueryString.' => ['exclude' => 'id,type'],
1863  'forceAbsoluteUrl' => true,
1864  ]);
1865  }
1866 
1867  /********************************************
1868  *
1869  * Page generation; cache handling
1870  *
1871  *******************************************/
1875  public function ‪isGeneratePage(): bool
1876  {
1877  return !$this->pageContentWasLoadedFromCache;
1878  }
1879 
1888  protected function ‪setPageCacheContent(string $content, array $data, int $expirationTstamp): array
1889  {
1890  $cacheData = [
1891  'page_id' => ‪$this->id,
1892  'content' => $content,
1893  'contentType' => $this->contentType,
1894  'cache_data' => $data,
1895  'expires' => $expirationTstamp,
1896  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
1897  ];
1898  $this->cacheExpires = $expirationTstamp;
1899  $this->pageCacheTags[] = 'pageId_' . ‪$this->id;
1900  // Respect the page cache when content of pid is shown
1901  if ($this->id !== $this->contentPid) {
1902  $this->pageCacheTags[] = 'pageId_' . ‪$this->contentPid;
1903  }
1904  if (!empty($this->page['cache_tags'])) {
1905  $tags = ‪GeneralUtility::trimExplode(',', $this->page['cache_tags'], true);
1906  $this->pageCacheTags = array_merge($this->pageCacheTags, $tags);
1907  }
1908  $this->pageCacheTags = array_unique($this->pageCacheTags);
1909  // Add the cache themselves as well, because they are fetched by getPageCacheTags()
1910  $cacheData['cacheTags'] = $this->pageCacheTags;
1911  $this->pageCache->set($this->newHash, $cacheData, $this->pageCacheTags, $expirationTstamp - ‪$GLOBALS['EXEC_TIME']);
1912  return $cacheData;
1913  }
1914 
1920  public function ‪clearPageCacheContent()
1921  {
1922  $this->pageCache->remove($this->newHash);
1923  }
1924 
1935  protected function ‪setSysLastChanged()
1936  {
1937  // We only update the info if browsing the live workspace
1938  $isInWorkspace = $this->context->getPropertyFromAspect('workspace', 'isOffline', false);
1939  if ($isInWorkspace) {
1940  return;
1941  }
1942  if ($this->page['SYS_LASTCHANGED'] < (int)($this->register['SYS_LASTCHANGED'] ?? 0)) {
1943  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
1944  ->getConnectionForTable('pages');
1945  $pageId = $this->page['_PAGES_OVERLAY_UID'] ?? ‪$this->id;
1946  $connection->update(
1947  'pages',
1948  [
1949  'SYS_LASTCHANGED' => (int)$this->register['SYS_LASTCHANGED'],
1950  ],
1951  [
1952  'uid' => (int)$pageId,
1953  ]
1954  );
1955  }
1956  }
1957 
1965  protected function ‪setRegisterValueForSysLastChanged(array ‪$page): void
1966  {
1967  $this->register['SYS_LASTCHANGED'] = (int)‪$page['tstamp'];
1968  if ($this->register['SYS_LASTCHANGED'] < (int)$page['SYS_LASTCHANGED']) {
1969  $this->register['SYS_LASTCHANGED'] = (int)‪$page['SYS_LASTCHANGED'];
1970  }
1971  }
1972 
1979  public function ‪addCacheTags(array $tags)
1980  {
1981  $this->pageCacheTags = array_merge($this->pageCacheTags, $tags);
1982  }
1983 
1984  public function ‪getPageCacheTags(): array
1985  {
1986  return $this->pageCacheTags;
1987  }
1988 
1989  /********************************************
1990  *
1991  * Page generation; rendering and inclusion
1992  *
1993  *******************************************/
1997  public function ‪generatePage_preProcessing()
1998  {
1999  // Used as a safety check in case a PHP script is falsely disabling $this->no_cache during page generation.
2000  $this->no_cacheBeforePageGen = ‪$this->no_cache;
2001  }
2002 
2013  protected function ‪resolveContentPid(ServerRequestInterface $request): int
2014  {
2015  if (!isset($this->page['content_from_pid']) || empty($this->page['content_from_pid'])) {
2016  return ‪$this->id;
2017  }
2018  // make REAL copy of TSFE object - not reference!
2019  $temp_copy_TSFE = clone $this;
2020  // Set ->id to the content_from_pid value - we are going to evaluate this pid as was it a given id for a page-display!
2021  $temp_copy_TSFE->id = (int)$this->page['content_from_pid'];
2022  $temp_copy_TSFE->MP = '';
2023  $temp_copy_TSFE->getPageAndRootline($request);
2024  return $temp_copy_TSFE->id;
2025  }
2029  public function ‪preparePageContentGeneration(ServerRequestInterface $request)
2030  {
2031  $this->‪getTimeTracker()->‪push('Prepare page content generation');
2032  // @deprecated: these properties can be removed in TYPO3 v13.0
2033  $this->baseUrl = (string)($this->config['config']['baseURL'] ?? '');
2034  // Internal and External target defaults
2035  $this->intTarget = (string)($this->config['config']['intTarget'] ?? '');
2036  $this->extTarget = (string)($this->config['config']['extTarget'] ?? '');
2037  $this->fileTarget = (string)($this->config['config']['fileTarget'] ?? '');
2038  if (($this->config['config']['spamProtectEmailAddresses'] ?? '') === 'ascii') {
2039  $this->‪logDeprecatedTyposcript('config.spamProtectEmailAddresses = ascii', 'This setting has no effect anymore. Change it to a number between -10 and 10 or remove it completely');
2040  $this->config['config']['spamProtectEmailAddresses'] = 0;
2041  }
2042  // @deprecated: these properties can be removed in TYPO3 v13.0
2043  $this->spamProtectEmailAddresses = (int)($this->config['config']['spamProtectEmailAddresses'] ?? 0);
2044  $this->spamProtectEmailAddresses = ‪MathUtility::forceIntegerInRange($this->spamProtectEmailAddresses, -10, 10, 0);
2045  // calculate the absolute path prefix
2046  if (!empty($this->absRefPrefix = trim($this->config['config']['absRefPrefix'] ?? ''))) {
2047  if ($this->absRefPrefix === 'auto') {
2048  $normalizedParams = $request->getAttribute('normalizedParams');
2049  $this->absRefPrefix = $normalizedParams->getSitePath();
2050  }
2051  }
2052  // config.forceAbsoluteUrls will override absRefPrefix
2053  if ($this->config['config']['forceAbsoluteUrls'] ?? false) {
2054  $normalizedParams = $request->getAttribute('normalizedParams');
2055  $this->absRefPrefix = $normalizedParams->getSiteUrl();
2056  }
2058  // linkVars
2059  $this->‪calculateLinkVars($request->getQueryParams());
2060  // Setting XHTML-doctype from doctype
2061  $this->config['config']['xhtmlDoctype'] = $this->config['config']['xhtmlDoctype'] ?? $this->config['config']['doctype'] ?? '';
2062  $docType = DocType::createFromConfigurationKey($this->config['config']['xhtmlDoctype']);
2063  $this->xhtmlDoctype = $docType->getXhtmlDocType();
2064  $this->xhtmlVersion = $docType->getXhtmlVersion();
2065  $this->pageRenderer->setDocType($docType);
2066 
2067  // Global content object
2068  $this->‪newCObj($request);
2069  $this->‪getTimeTracker()->‪pull();
2070  }
2071 
2077  public function ‪generatePage_postProcessing(ServerRequestInterface $request)
2078  {
2079  $this->‪setAbsRefPrefix();
2080  // This is to ensure, that the page is NOT cached if the no_cache parameter was set before the page was generated.
2081  // This is a safety precaution, as it could have been unset by some script.
2082  if ($this->no_cacheBeforePageGen) {
2083  $this->‪set_no_cache('no_cache has been set before the page was generated - safety check', true);
2084  }
2085  $eventDispatcher = GeneralUtility::makeInstance(EventDispatcherInterface::class);
2086  $event = new AfterCacheableContentIsGeneratedEvent($request, $this, $this->newHash, !$this->no_cache);
2087  $event = $eventDispatcher->dispatch($event);
2088 
2089  // Processing if caching is enabled
2090  if ($event->isCachingEnabled()) {
2091  // Seconds until a cached page is too old
2092  $cacheTimeout = $this->‪get_cache_timeout();
2093  $timeOutTime = ‪$GLOBALS['EXEC_TIME'] + $cacheTimeout;
2094  // Write the page to cache
2095  $cachedInformation = $this->‪setPageCacheContent($this->content, $this->config, $timeOutTime);
2096 
2097  // Event for cache post processing (eg. writing static files)
2098  $event = new ‪AfterCachedPageIsPersistedEvent($request, $this, $this->newHash, $cachedInformation, $cacheTimeout);
2099  $eventDispatcher->dispatch($event);
2100  }
2101  $this->‪setSysLastChanged();
2102  }
2103 
2110  public function ‪generatePageTitle(): string
2111  {
2112  // Check for a custom pageTitleSeparator, and perform stdWrap on it
2113  $pageTitleSeparator = (string)$this->cObj->stdWrapValue('pageTitleSeparator', $this->config['config'] ?? []);
2114  if ($pageTitleSeparator !== '' && $pageTitleSeparator === ($this->config['config']['pageTitleSeparator'] ?? '')) {
2115  $pageTitleSeparator .= ' ';
2116  }
2117 
2118  $titleProvider = GeneralUtility::makeInstance(PageTitleProviderManager::class);
2119  if (!empty($this->config['config']['pageTitleCache'])) {
2120  $titleProvider->setPageTitleCache($this->config['config']['pageTitleCache']);
2121  }
2122  $pageTitle = $titleProvider->getTitle();
2123  $this->config['config']['pageTitleCache'] = $titleProvider->getPageTitleCache();
2124 
2125  $titleTagContent = $this->‪printTitle(
2126  $pageTitle,
2127  (bool)($this->config['config']['noPageTitle'] ?? false),
2128  (bool)($this->config['config']['pageTitleFirst'] ?? false),
2129  $pageTitleSeparator,
2130  (bool)($this->config['config']['showWebsiteTitle'] ?? true)
2131  );
2132  $this->config['config']['pageTitle'] = $titleTagContent;
2133  // stdWrap around the title tag
2134  $titleTagContent = $this->cObj->stdWrapValue('pageTitle', $this->config['config']);
2135 
2136  // config.noPageTitle = 2 - means do not render the page title
2137  if (isset($this->config['config']['noPageTitle']) && (int)$this->config['config']['noPageTitle'] === 2) {
2138  $titleTagContent = '';
2139  }
2140  if ($titleTagContent !== '') {
2141  $this->pageRenderer->setTitle($titleTagContent);
2142  }
2143  return (string)$titleTagContent;
2144  }
2145 
2157  protected function ‪printTitle(string $pageTitle, bool $noPageTitle = false, bool $showPageTitleFirst = false, string $pageTitleSeparator = '', bool $showWebsiteTitle = true): string
2158  {
2159  $websiteTitle = $showWebsiteTitle ? $this->‪getWebsiteTitle() : '';
2160  $pageTitle = $noPageTitle ? '' : $pageTitle;
2161  // only show a separator if there are both site title and page title
2162  if ($pageTitle === '' || $websiteTitle === '') {
2163  $pageTitleSeparator = '';
2164  } elseif (empty($pageTitleSeparator)) {
2165  // use the default separator if non given
2166  $pageTitleSeparator = ': ';
2167  }
2168  if ($showPageTitleFirst) {
2169  return $pageTitle . $pageTitleSeparator . $websiteTitle;
2170  }
2171  return $websiteTitle . $pageTitleSeparator . $pageTitle;
2172  }
2173 
2174  protected function ‪getWebsiteTitle(): string
2175  {
2176  if (trim($this->‪language->getWebsiteTitle()) !== '') {
2177  return trim($this->‪language->getWebsiteTitle());
2178  }
2179  if (trim($this->‪site->getConfiguration()['websiteTitle'] ?? '') !== '') {
2180  return trim($this->‪site->getConfiguration()['websiteTitle']);
2181  }
2182 
2183  return '';
2184  }
2185 
2189  public function ‪INTincScript(ServerRequestInterface $request): void
2190  {
2191  $this->additionalHeaderData = $this->config['INTincScript_ext']['additionalHeaderData'] ?? [];
2192  $this->additionalFooterData = $this->config['INTincScript_ext']['additionalFooterData'] ?? [];
2193  if (empty($this->config['INTincScript_ext']['pageRendererState'])) {
2194  $this->‪initPageRenderer();
2195  } else {
2196  $pageRendererState = unserialize($this->config['INTincScript_ext']['pageRendererState'], ['allowed_classes' => [Locale::class]]);
2197  $this->pageRenderer->updateState($pageRendererState);
2198  }
2199  if (!empty($this->config['INTincScript_ext']['assetCollectorState'])) {
2200  $assetCollectorState = unserialize($this->config['INTincScript_ext']['assetCollectorState'], ['allowed_classes' => false]);
2201  GeneralUtility::makeInstance(AssetCollector::class)->updateState($assetCollectorState);
2202  }
2203 
2205  $this->‪getTimeTracker()->‪push('Substitute header section');
2206  $this->‪INTincScript_loadJSCode();
2207  $this->‪generatePageTitle();
2208 
2209  $this->content = str_replace(
2210  [
2211  '<!--HD_' . $this->config['INTincScript_ext']['divKey'] . '-->',
2212  '<!--FD_' . $this->config['INTincScript_ext']['divKey'] . '-->',
2213  ],
2214  [
2215  implode(LF, $this->additionalHeaderData),
2216  implode(LF, $this->additionalFooterData),
2217  ],
2218  $this->pageRenderer->renderJavaScriptAndCssForProcessingOfUncachedContentObjects($this->content, $this->config['INTincScript_ext']['divKey'])
2219  );
2220  // Replace again, because header and footer data and page renderer replacements may introduce additional placeholders (see #44825)
2222  $this->‪setAbsRefPrefix();
2223  $this->‪getTimeTracker()->‪pull();
2224  }
2225 
2231  protected function ‪recursivelyReplaceIntPlaceholdersInContent(ServerRequestInterface $request)
2232  {
2233  do {
2234  $nonCacheableData = $this->config['INTincScript'];
2235  $this->‪processNonCacheableContentPartsAndSubstituteContentMarkers($nonCacheableData, $request);
2236  // Check if there were new items added to INTincScript during the previous execution:
2237  // array_diff_assoc throws notices if values are arrays but not strings. We suppress this here.
2238  $nonCacheableData = @array_diff_assoc($this->config['INTincScript'], $nonCacheableData);
2239  $reprocess = count($nonCacheableData) > 0;
2240  } while ($reprocess);
2241  }
2242 
2252  protected function ‪processNonCacheableContentPartsAndSubstituteContentMarkers(array $nonCacheableData, ServerRequestInterface $request)
2253  {
2254  $timeTracker = $this->‪getTimeTracker();
2255  $timeTracker->push('Split content');
2256  // Splits content with the key.
2257  $contentSplitByUncacheableMarkers = explode('<!--INT_SCRIPT.', $this->content);
2258  $this->content = '';
2259  $timeTracker->setTSlogMessage('Parts: ' . count($contentSplitByUncacheableMarkers), LogLevel::INFO);
2260  $timeTracker->pull();
2261  foreach ($contentSplitByUncacheableMarkers as $counter => $contentPart) {
2262  // If the split had a comment-end after 32 characters it's probably a split-string
2263  if (substr($contentPart, 32, 3) === '-->') {
2264  $nonCacheableKey = 'INT_SCRIPT.' . substr($contentPart, 0, 32);
2265  if (is_array($nonCacheableData[$nonCacheableKey])) {
2266  $label = 'Include ' . $nonCacheableData[$nonCacheableKey]['type'];
2267  $timeTracker->push($label);
2268  $nonCacheableContent = '';
2269  $contentObjectRendererForNonCacheable = unserialize($nonCacheableData[$nonCacheableKey]['cObj']);
2270  /* @var ContentObjectRenderer $contentObjectRendererForNonCacheable */
2271  $contentObjectRendererForNonCacheable->setRequest($request);
2272  switch ($nonCacheableData[$nonCacheableKey]['type']) {
2273  case 'COA':
2274  $nonCacheableContent = $contentObjectRendererForNonCacheable->cObjGetSingle('COA', $nonCacheableData[$nonCacheableKey]['conf']);
2275  break;
2276  case 'FUNC':
2277  $nonCacheableContent = $contentObjectRendererForNonCacheable->cObjGetSingle('USER', $nonCacheableData[$nonCacheableKey]['conf']);
2278  break;
2279  case 'POSTUSERFUNC':
2280  $nonCacheableContent = $contentObjectRendererForNonCacheable->callUserFunction($nonCacheableData[$nonCacheableKey]['postUserFunc'], $nonCacheableData[$nonCacheableKey]['conf'], $nonCacheableData[$nonCacheableKey]['content']);
2281  break;
2282  }
2283  $this->content .= $nonCacheableContent;
2284  $this->content .= substr($contentPart, 35);
2285  $timeTracker->pull($nonCacheableContent);
2286  } else {
2287  $this->content .= substr($contentPart, 35);
2288  }
2289  } elseif ($counter) {
2290  // If it's not the first entry (which would be "0" of the array keys), then re-add the INT_SCRIPT part
2291  $this->content .= '<!--INT_SCRIPT.' . $contentPart;
2292  } else {
2293  $this->content .= $contentPart;
2294  }
2295  }
2296  }
2297 
2304  public function ‪INTincScript_loadJSCode()
2305  {
2306  // Prepare code and placeholders for additional header and footer files (and make sure that this isn't called twice)
2307  if ($this->‪isINTincScript() && !isset($this->config['INTincScript_ext'])) {
2308  $substituteHash = $this->‪uniqueHash();
2309  $this->config['INTincScript_ext']['divKey'] = $substituteHash;
2310  // Storing the header-data array
2311  $this->config['INTincScript_ext']['additionalHeaderData'] = $this->additionalHeaderData;
2312  // Storing the footer-data array
2313  $this->config['INTincScript_ext']['additionalFooterData'] = $this->additionalFooterData;
2314  // Clearing the array
2315  $this->additionalHeaderData = ['<!--HD_' . $substituteHash . '-->'];
2316  // Clearing the array
2317  $this->additionalFooterData = ['<!--FD_' . $substituteHash . '-->'];
2318  }
2319  }
2320 
2326  public function ‪isINTincScript()
2327  {
2328  return !empty($this->config['INTincScript']) && is_array($this->config['INTincScript']);
2329  }
2330 
2334  public function ‪applyHttpHeadersToResponse(ResponseInterface $response): ResponseInterface
2335  {
2336  $response = $response->withHeader('Content-Type', $this->contentType);
2337  // Set header for content language unless disabled
2338  $contentLanguage = (string)$this->‪language->getLocale();
2339  if (empty($this->config['config']['disableLanguageHeader'])) {
2340  $response = $response->withHeader('Content-Language', $contentLanguage);
2341  }
2342 
2343  // Add a Response header to show debug information if a page was fetched from cache
2344  if ($this->debugInformationHeader) {
2345  $response = $response->withHeader('X-TYPO3-Debug-Cache', $this->debugInformationHeader);
2346  }
2347 
2348  // Set cache related headers to client (used to enable proxy / client caching!)
2349  if (!empty($this->config['config']['sendCacheHeaders'])) {
2350  $headers = $this->‪getCacheHeaders();
2351  foreach ($headers as $header => $value) {
2352  $response = $response->withHeader($header, $value);
2353  }
2354  }
2355  // Set additional headers if any have been configured via TypoScript
2356  $additionalHeaders = $this->‪getAdditionalHeaders();
2357  foreach ($additionalHeaders as $headerConfig) {
2358  [$header, $value] = ‪GeneralUtility::trimExplode(':', $headerConfig['header'], false, 2);
2359  if ($headerConfig['statusCode']) {
2360  $response = $response->withStatus((int)$headerConfig['statusCode']);
2361  }
2362  if ($headerConfig['replace']) {
2363  $response = $response->withHeader($header, $value);
2364  } else {
2365  $response = $response->withAddedHeader($header, $value);
2366  }
2367  }
2368  return $response;
2369  }
2370 
2374  protected function ‪getCacheHeaders(): array
2375  {
2376  // Getting status whether we can send cache control headers for proxy caching:
2377  $doCache = $this->‪isStaticCacheble();
2378  $isBackendUserLoggedIn = $this->context->getPropertyFromAspect('backend.user', 'isLoggedIn', false);
2379  $isInWorkspace = $this->context->getPropertyFromAspect('workspace', 'isOffline', false);
2380  // Finally, when backend users are logged in, do not send cache headers at all (Admin Panel might be displayed for instance).
2381  $isClientCachable = $doCache && !$isBackendUserLoggedIn && !$isInWorkspace;
2382  if ($isClientCachable) {
2383  $headers = [
2384  'Expires' => gmdate('D, d M Y H:i:s T', $this->cacheExpires),
2385  'ETag' => '"' . md5($this->content) . '"',
2386  'Cache-Control' => 'max-age=' . ($this->cacheExpires - ‪$GLOBALS['EXEC_TIME']),
2387  // no-cache
2388  'Pragma' => 'public',
2389  ];
2390  } else {
2391  // "no-store" is used to ensure that the client HAS to ask the server every time, and is not allowed to store anything at all
2392  $headers = [
2393  'Cache-Control' => 'private, no-store',
2394  ];
2395  // Now, if a backend user is logged in, tell him in the Admin Panel log what the caching status would have been:
2396  if ($isBackendUserLoggedIn) {
2397  if ($doCache) {
2398  $this->‪getTimeTracker()->‪setTSlogMessage('Cache-headers with max-age "' . ($this->cacheExpires - ‪$GLOBALS['EXEC_TIME']) . '" would have been sent');
2399  } else {
2400  $reasonMsg = [];
2401  if ($this->no_cache) {
2402  $reasonMsg[] = 'Caching disabled (no_cache).';
2403  }
2404  if ($this->‪isINTincScript()) {
2405  $reasonMsg[] = '*_INT object(s) on page.';
2406  }
2407  if ($this->context->getPropertyFromAspect('frontend.user', 'isLoggedIn', false)) {
2408  $reasonMsg[] = 'Frontend user logged in.';
2409  }
2410  $this->‪getTimeTracker()->‪setTSlogMessage('Cache-headers would disable proxy caching! Reason(s): "' . implode(' ', $reasonMsg) . '"', LogLevel::NOTICE);
2411  }
2412  }
2413  }
2414  return $headers;
2415  }
2416 
2427  public function ‪isStaticCacheble()
2428  {
2429  return !$this->no_cache && !$this->‪isINTincScript() && !$this->context->getAspect('frontend.user')->isUserOrGroupSet();
2430  }
2431 
2432  /********************************************
2433  *
2434  * Various internal API functions
2435  *
2436  *******************************************/
2443  public function ‪newCObj(ServerRequestInterface $request = null)
2444  {
2445  $this->cObj = GeneralUtility::makeInstance(ContentObjectRenderer::class, $this);
2446  $this->cObj->start($this->page, 'pages', $request);
2447  }
2448 
2456  protected function ‪setAbsRefPrefix()
2457  {
2458  if (!$this->absRefPrefix) {
2459  return;
2460  }
2461  $encodedAbsRefPrefix = htmlspecialchars($this->absRefPrefix, ENT_QUOTES | ENT_HTML5);
2462  $search = [
2463  '"_assets/',
2464  '"typo3temp/',
2467  ];
2468  $replace = [
2469  '"' . $encodedAbsRefPrefix . '_assets/',
2470  '"' . $encodedAbsRefPrefix . 'typo3temp/',
2471  '"' . $encodedAbsRefPrefix . ‪PathUtility::stripPathSitePrefix(‪Environment::getExtensionsPath()) . '/',
2472  '"' . $encodedAbsRefPrefix . ‪PathUtility::stripPathSitePrefix(‪Environment::getFrameworkBasePath()) . '/',
2473  ];
2474  // Process additional directories
2475  $directories = ‪GeneralUtility::trimExplode(',', ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['additionalAbsRefPrefixDirectories'], true);
2476  foreach ($directories as $directory) {
2477  $search[] = '"' . $directory;
2478  $replace[] = '"' . $encodedAbsRefPrefix . $directory;
2479  }
2480  $this->content = str_replace(
2481  $search,
2482  $replace,
2483  $this->content
2484  );
2485  }
2486 
2497  public function ‪baseUrlWrap(‪$url, bool $internal = false)
2498  {
2499  if (!$internal) {
2500  trigger_error('Calling $TSFE->baseUrlWrap will not work anymore in TYPO3 v13.0. Use SiteHandling and config.forceAbsoluteUrls anymore, or build your own <base> tag via TypoScript headerData.', E_USER_DEPRECATED);
2501  }
2502  if ($this->config['config']['baseURL'] ?? false) {
2503  $urlParts = parse_url(‪$url);
2504  if (empty($urlParts['scheme']) && ‪$url[0] !== '/') {
2505  ‪$url = $this->config['config']['baseURL'] . ‪$url;
2506  }
2507  }
2508  return ‪$url;
2509  }
2510 
2519  public function ‪logDeprecatedTyposcript($typoScriptProperty, $explanation = '')
2520  {
2521  $explanationText = $explanation !== '' ? ' - ' . $explanation : '';
2522  $this->‪getTimeTracker()->‪setTSlogMessage($typoScriptProperty . ' is deprecated.' . $explanationText, LogLevel::WARNING);
2523  trigger_error('TypoScript property ' . $typoScriptProperty . ' is deprecated' . $explanationText, E_USER_DEPRECATED);
2524  }
2525 
2526  /********************************************
2527  * PUBLIC ACCESSIBLE WORKSPACES FUNCTIONS
2528  *******************************************/
2529 
2536  public function ‪doWorkspacePreview()
2537  {
2538  trigger_error('TSFE->doWorkspacePreview() will be removed in TYPO3 v13.0. Use the Context API directly.', E_USER_DEPRECATED);
2539  return $this->context->getPropertyFromAspect('workspace', 'isOffline', false);
2540  }
2541 
2548  public function ‪whichWorkspace(): int
2549  {
2550  trigger_error('TSFE->whichWorkspace() will be removed in TYPO3 v13.0. Use the Context API directly.', E_USER_DEPRECATED);
2551  return $this->context->getPropertyFromAspect('workspace', 'id', 0);
2552  }
2553 
2554  /********************************************
2555  *
2556  * Various external API functions - for use in plugins etc.
2557  *
2558  *******************************************/
2566  public function ‪getPagesTSconfig(): array
2567  {
2568  trigger_error('Method getPagesTSconfig() is deprecated since TYPO3 v12 and will be removed with TYPO3 v13.0.', E_USER_DEPRECATED);
2569  if (!is_array($this->pagesTSconfig)) {
2570  $matcher = GeneralUtility::makeInstance(\‪TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching\ConditionMatcher::class, $this->context, $this->id, $this->rootLine);
2571  $this->pagesTSconfig = GeneralUtility::makeInstance(PageTsConfig::class)
2572  ->getForRootLine(
2573  array_reverse($this->rootLine),
2574  $this->‪site,
2575  $matcher
2576  );
2577  }
2578  return $this->pagesTSconfig;
2579  }
2580 
2588  public function ‪uniqueHash($str = '')
2589  {
2590  return md5($this->‪uniqueString . '_' . $str . $this->uniqueCounter++);
2591  }
2592 
2599  public function ‪set_no_cache($reason = '', $internalRequest = false)
2600  {
2601  $warning = '';
2602  $context = [];
2603  if ($reason !== '') {
2604  $warning = '$TSFE->set_no_cache() was triggered. Reason: {reason}.';
2605  $context['reason'] = $reason;
2606  } else {
2607  $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
2608  if (isset($trace[0]['class'])) {
2609  $context['class'] = $trace[0]['class'];
2610  $warning = '$GLOBALS[\'TSFE\']->set_no_cache() was triggered by {class} on line {line}.';
2611  }
2612  if (isset($trace[0]['function'])) {
2613  $context['function'] = $trace[0]['function'];
2614  $warning = '$GLOBALS[\'TSFE\']->set_no_cache() was triggered by {class}->{function} on line {line}.';
2615  }
2616  if ($context === []) {
2617  // Only store the filename, not the full path for safety reasons
2618  $context['file'] = basename($trace[0]['file']);
2619  $warning = '$GLOBALS[\'TSFE\']->set_no_cache() was triggered by {file} on line {line}.';
2620  }
2621  $context['line'] = $trace[0]['line'];
2622  }
2623  if (!$internalRequest && ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['disableNoCacheParameter']) {
2624  $warning .= ' However, $TYPO3_CONF_VARS[\'FE\'][\'disableNoCacheParameter\'] is set, so it will be ignored!';
2625  $this->‪getTimeTracker()->‪setTSlogMessage($warning, LogLevel::NOTICE);
2626  } else {
2627  $warning .= ' Caching is disabled!';
2629  }
2630  $this->logger->notice($warning, $context);
2631  }
2632 
2638  protected function ‪disableCache()
2639  {
2640  $this->no_cache = true;
2641  }
2642 
2648  public function ‪set_cache_timeout_default($seconds)
2649  {
2650  $seconds = (int)$seconds;
2651  if ($seconds > 0) {
2652  $this->cacheTimeOutDefault = $seconds;
2653  }
2654  }
2655 
2659  public function ‪get_cache_timeout(): int
2660  {
2661  return GeneralUtility::makeInstance(CacheLifetimeCalculator::class)
2662  ->calculateLifetimeForPage(
2663  (int)$this->id,
2664  $this->page,
2665  $this->config['config'] ?? [],
2666  $this->cacheTimeOutDefault,
2667  $this->context
2668  );
2669  }
2670 
2671  /*********************************************
2672  *
2673  * Localization and character set conversion
2674  *
2675  *********************************************/
2682  public function ‪sL($input)
2683  {
2684  if ($this->languageService === null) {
2685  $this->languageService = GeneralUtility::makeInstance(LanguageServiceFactory::class)->createFromSiteLanguage($this->‪language);
2686  }
2687  return $this->languageService->sL($input);
2688  }
2689 
2693  public function ‪getRequestedId(): int
2694  {
2695  return $this->requestedId;
2696  }
2697 
2705  public function ‪releaseLocks(): void
2706  {
2707  $this->lock?->releaseLock('pages');
2708  }
2709 
2713  protected function ‪getAdditionalHeaders(): array
2714  {
2715  if (!isset($this->config['config']['additionalHeaders.'])) {
2716  return [];
2717  }
2718  $additionalHeaders = [];
2719  ksort($this->config['config']['additionalHeaders.']);
2720  foreach ($this->config['config']['additionalHeaders.'] as $options) {
2721  if (!is_array($options)) {
2722  continue;
2723  }
2724  $header = trim($options['header'] ?? '');
2725  if ($header === '') {
2726  continue;
2727  }
2728  $additionalHeaders[] = [
2729  'header' => $header,
2730  // "replace existing headers" is turned on by default, unless turned off
2731  'replace' => ($options['replace'] ?? '') !== '0',
2732  'statusCode' => (int)($options['httpResponseCode'] ?? 0) ?: null,
2733  ];
2734  }
2735  return $additionalHeaders;
2736  }
2741  protected function ‪logPageAccessFailure(string $message, ServerRequestInterface $request): void
2742  {
2743  $context = ['pageId' => ‪$this->id];
2744  if (($normalizedParams = $request->getAttribute('normalizedParams')) instanceof ‪NormalizedParams) {
2745  $context['requestUrl'] = $normalizedParams->getRequestUrl();
2746  }
2747  $this->logger->error($message, $context);
2748  }
2749 
2757  protected function ‪getBackendUser()
2758  {
2759  return ‪$GLOBALS['BE_USER'] ?? null;
2760  }
2761 
2765  protected function ‪getTimeTracker()
2766  {
2767  return GeneralUtility::makeInstance(TimeTracker::class);
2768  }
2769 
2770  public function ‪getLanguage(): ‪SiteLanguage
2771  {
2772  return ‪$this->language;
2773  }
2774 
2775  public function ‪getSite(): Site
2776  {
2777  return ‪$this->site;
2778  }
2779 
2780  public function ‪getContext(): Context
2781  {
2782  return $this->context;
2783  }
2784 
2785  public function ‪getPageArguments(): PageArguments
2786  {
2787  return ‪$this->pageArguments;
2788  }
2789 }
‪TYPO3\CMS\Core\Localization\LanguageServiceFactory
Definition: LanguageServiceFactory.php:25
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getRedirectUriForMountPoint
‪getRedirectUriForMountPoint(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1785
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\LANGUAGE_AND_FALLBACKS_NOT_AVAILABLE
‪const LANGUAGE_AND_FALLBACKS_NOT_AVAILABLE
Definition: PageAccessFailureReasons.php:44
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\initPageRenderer
‪initPageRenderer()
Definition: TypoScriptFrontendController.php:524
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setAbsRefPrefix
‪setAbsRefPrefix()
Definition: TypoScriptFrontendController.php:2436
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:916
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateRepository
Definition: SysTemplateRepository.php:39
‪TYPO3\CMS\Core\Routing\PageArguments
Definition: PageArguments.php:26
‪TYPO3\CMS\Core\Page\AssetCollector
Definition: AssetCollector.php:44
‪TYPO3\CMS\Core\Utility\PathUtility\stripPathSitePrefix
‪static stripPathSitePrefix(string $path)
Definition: PathUtility.php:428
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\doWorkspacePreview
‪bool doWorkspacePreview()
Definition: TypoScriptFrontendController.php:2516
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeSetupConditionConstantSubstitutionVisitor
Definition: IncludeTreeSetupConditionConstantSubstitutionVisitor.php:36
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\fe_user
‪$this fe_user
Definition: TypoScriptFrontendController.php:507
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\Context\LanguageAspectFactory
Definition: LanguageAspectFactory.php:27
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\recursivelyReplaceIntPlaceholdersInContent
‪recursivelyReplaceIntPlaceholdersInContent(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:2211
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getAdditionalHeaders
‪getAdditionalHeaders()
Definition: TypoScriptFrontendController.php:2693
‪TYPO3\CMS\Core\Locking\ResourceMutex
Definition: ResourceMutex.php:54
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\sL
‪string sL($input)
Definition: TypoScriptFrontendController.php:2662
‪TYPO3\CMS\Backend\FrontendBackendUserAuthentication
Definition: FrontendBackendUserAuthentication.php:32
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\generatePageTitle
‪string generatePageTitle()
Definition: TypoScriptFrontendController.php:2090
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\generatePage_preProcessing
‪generatePage_preProcessing()
Definition: TypoScriptFrontendController.php:1977
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\checkEnableFields
‪bool checkEnableFields($row, $bypassGroupCheck=false)
Definition: TypoScriptFrontendController.php:1033
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getPageAccessFailureReasons
‪array getPageAccessFailureReasons(string $failureReasonCode=null)
Definition: TypoScriptFrontendController.php:1048
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getSite
‪getSite()
Definition: TypoScriptFrontendController.php:2755
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$no_cache
‪bool $no_cache
Definition: TypoScriptFrontendController.php:142
‪TYPO3
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setContentType
‪setContentType($contentType)
Definition: TypoScriptFrontendController.php:545
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$MP
‪string $MP
Definition: TypoScriptFrontendController.php:213
‪TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
Definition: PhpFrontend.php:25
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\disableCache
‪disableCache()
Definition: TypoScriptFrontendController.php:2618
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\isGeneratePage
‪isGeneratePage()
Definition: TypoScriptFrontendController.php:1855
‪TYPO3\CMS\Core\Routing\PageArguments\getPageId
‪getPageId()
Definition: PageArguments.php:95
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\uniqueHash
‪string uniqueHash($str='')
Definition: TypoScriptFrontendController.php:2568
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Traverser\IncludeTreeTraverser
Definition: IncludeTreeTraverser.php:30
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\populatePageDataFromCache
‪populatePageDataFromCache(array $cachedData)
Definition: TypoScriptFrontendController.php:1548
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SHORTCUT
‪const DOKTYPE_SHORTCUT
Definition: PageRepository.php:128
‪TYPO3\CMS\Core\Context\LanguageAspectFactory\createFromSiteLanguage
‪static createFromSiteLanguage(SiteLanguage $language)
Definition: LanguageAspectFactory.php:31
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$pageArguments
‪PageArguments $pageArguments
Definition: TypoScriptFrontendController.php:135
‪TYPO3\CMS\Core\Utility\RootlineUtility
Definition: RootlineUtility.php:40
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:26
‪TYPO3\CMS\Core\Site\Entity\Site\getAttribute
‪mixed getAttribute(string $attributeName)
Definition: Site.php:310
‪TYPO3\CMS\Frontend\Event\BeforePageIsResolvedEvent
Definition: BeforePageIsResolvedEvent.php:31
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Core\Environment\getExtensionsPath
‪static getExtensionsPath()
Definition: Environment.php:264
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getContext
‪getContext()
Definition: TypoScriptFrontendController.php:2760
‪TYPO3\CMS\Core\Localization\Locales
Definition: Locales.php:36
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeAstBuilderVisitor
Definition: IncludeTreeAstBuilderVisitor.php:39
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setRegisterValueForSysLastChanged
‪setRegisterValueForSysLastChanged(array $page)
Definition: TypoScriptFrontendController.php:1945
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$type
‪int string $type
Definition: TypoScriptFrontendController.php:127
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\uniqueString
‪$this uniqueString
Definition: TypoScriptFrontendController.php:508
‪TYPO3\CMS\Core\Type\Bitmask\PageTranslationVisibility
Definition: PageTranslationVisibility.php:30
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\isUserOrGroupSet
‪bool isUserOrGroupSet()
Definition: TypoScriptFrontendController.php:581
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$pageAccessFailureHistory
‪array $pageAccessFailureHistory
Definition: TypoScriptFrontendController.php:208
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\ACCESS_DENIED_INVALID_PAGETYPE
‪const ACCESS_DENIED_INVALID_PAGETYPE
Definition: PageAccessFailureReasons.php:52
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:55
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getRequestedId
‪getRequestedId()
Definition: TypoScriptFrontendController.php:2673
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:26
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\isStaticCacheble
‪bool isStaticCacheble()
Definition: TypoScriptFrontendController.php:2407
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getFromCache
‪ServerRequestInterface getFromCache(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1135
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\settingLanguage
‪settingLanguage(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1650
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$page
‪array $page
Definition: TypoScriptFrontendController.php:173
‪TYPO3\CMS\Core\Context\Context\setAspect
‪setAspect(string $name, AspectInterface $aspect)
Definition: Context.php:152
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\clearPageCacheContent
‪clearPageCacheContent()
Definition: TypoScriptFrontendController.php:1900
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:27
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\generatePage_postProcessing
‪generatePage_postProcessing(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:2057
‪TYPO3\CMS\Frontend\Event\AfterCacheableContentIsGeneratedEvent
Definition: AfterCacheableContentIsGeneratedEvent.php:29
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_MOUNTPOINT
‪const DOKTYPE_MOUNTPOINT
Definition: PageRepository.php:130
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getLanguage
‪getLanguage()
Definition: TypoScriptFrontendController.php:2750
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\isINTincScript
‪bool isINTincScript()
Definition: TypoScriptFrontendController.php:2306
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\processNonCacheableContentPartsAndSubstituteContentMarkers
‪processNonCacheableContentPartsAndSubstituteContentMarkers(array $nonCacheableData, ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:2232
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\pull
‪pull(string $content='')
Definition: TimeTracker.php:153
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionIncludeListAccumulatorVisitor
Definition: IncludeTreeConditionIncludeListAccumulatorVisitor.php:32
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\initUserGroups
‪initUserGroups()
Definition: TypoScriptFrontendController.php:569
‪TYPO3\CMS\Core\Error\Http\PageNotFoundException
Definition: PageNotFoundException.php:24
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\ACCESS_DENIED_HOST_PAGE_MISMATCH
‪const ACCESS_DENIED_HOST_PAGE_MISMATCH
Definition: PageAccessFailureReasons.php:51
‪TYPO3\CMS\Core\Http\ImmediateResponseException\getResponse
‪Response getResponse()
Definition: ImmediateResponseException.php:49
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$fe_user
‪FrontendUserAuthentication $fe_user
Definition: TypoScriptFrontendController.php:219
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$deprecatedPublicProperties
‪array $deprecatedPublicProperties
Definition: TypoScriptFrontendController.php:109
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\determineId
‪determineId(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:633
‪TYPO3\CMS\Frontend\Cache\CacheLifetimeCalculator
Definition: CacheLifetimeCalculator.php:39
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getPageArguments
‪getPageArguments()
Definition: TypoScriptFrontendController.php:2765
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\ACCESS_DENIED_PAGE_NOT_RESOLVED
‪const ACCESS_DENIED_PAGE_NOT_RESOLVED
Definition: PageAccessFailureReasons.php:49
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$originalShortcutPage
‪array $originalShortcutPage
Definition: TypoScriptFrontendController.php:192
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\calculateLinkVars
‪calculateLinkVars(array $queryParams)
Definition: TypoScriptFrontendController.php:1767
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\LANGUAGE_DEFAULT_NOT_AVAILABLE
‪const LANGUAGE_DEFAULT_NOT_AVAILABLE
Definition: PageAccessFailureReasons.php:45
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getBackendUser
‪FrontendBackendUserAuthentication null getBackendUser()
Definition: TypoScriptFrontendController.php:2737
‪TYPO3\CMS\Frontend\Event\AfterPageAndLanguageIsResolvedEvent
Definition: AfterPageAndLanguageIsResolvedEvent.php:32
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getPagesTSconfig
‪getPagesTSconfig()
Definition: TypoScriptFrontendController.php:2546
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getPageCacheTags
‪getPageCacheTags()
Definition: TypoScriptFrontendController.php:1964
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\baseUrlWrap
‪string baseUrlWrap($url, bool $internal=false)
Definition: TypoScriptFrontendController.php:2477
‪TYPO3\CMS\Core\Utility\HttpUtility\buildQueryString
‪static string buildQueryString(array $parameters, string $prependCharacter='', bool $skipEmptyParameters=false)
Definition: HttpUtility.php:124
‪TYPO3\CMS\Core\PageTitle\PageTitleProviderManager
Definition: PageTitleProviderManager.php:31
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\LANGUAGE_NOT_AVAILABLE
‪const LANGUAGE_NOT_AVAILABLE
Definition: PageAccessFailureReasons.php:42
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\PAGE_NOT_FOUND
‪const PAGE_NOT_FOUND
Definition: PageAccessFailureReasons.php:28
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$pageNotFound
‪int $pageNotFound
Definition: TypoScriptFrontendController.php:203
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:131
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\RENDERING_INSTRUCTIONS_NOT_CONFIGURED
‪const RENDERING_INSTRUCTIONS_NOT_CONFIGURED
Definition: PageAccessFailureReasons.php:34
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\evaluatePageNotFound
‪evaluatePageNotFound(int $pageNotFoundNumber, ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:702
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\initializeContext
‪initializeContext(Context $context)
Definition: TypoScriptFrontendController.php:513
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setPageCacheContent
‪setPageCacheContent(string $content, array $data, int $expirationTstamp)
Definition: TypoScriptFrontendController.php:1868
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$contentPid
‪int $contentPid
Definition: TypoScriptFrontendController.php:179
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_BE_USER_SECTION
‪const DOKTYPE_BE_USER_SECTION
Definition: PageRepository.php:129
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:36
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\initializeContext
‪array< string, $config=array();public $tmpl;protected int $cacheTimeOutDefault=0;protected bool $pageContentWasLoadedFromCache=false;protected int $cacheExpires=0;public array|string $pSetup='';public string $newHash='';protected bool $no_cacheBeforePageGen=false;protected ?array $pagesTSconfig=null;public array $additionalHeaderData=array();public array $additionalFooterData=array();protected string $intTarget='';protected string $extTarget='';protected string $fileTarget='';protected int $spamProtectEmailAddresses=0;public string $absRefPrefix='';public string $linkVars='';public array $applicationData=[];public array $register=[];public array $registerStack=[];public array $recordRegister=[];public string $currentRecord='';protected int $uniqueCounter=0;protected string $uniqueString='';protected string $baseUrl='';public ContentObjectRenderer $cObj;public string $content='';public ?array $lastImgResourceInfo=null;protected ?LanguageService $languageService=null;public ?ResourceMutex $lock=null;protected ?PageRenderer $pageRenderer=null;protected FrontendInterface $pageCache;protected array $pageCacheTags=[];protected string $contentType='text/html;charset=utf-8';protected string $xhtmlDoctype='';protected int $xhtmlVersion;protected int $requestedId=0;protected Context $context;protected string $debugInformationHeader='';public __construct(Context $context, Site $site, SiteLanguage $siteLanguage, PageArguments $pageArguments, FrontendUserAuthentication $frontendUser) { $this-> initializeContext($context)
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\preparePageContentGeneration
‪preparePageContentGeneration(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:2009
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$site
‪Site $site
Definition: TypoScriptFrontendController.php:129
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\ACCESS_DENIED_SUBSECTION_NOT_RESOLVED
‪const ACCESS_DENIED_SUBSECTION_NOT_RESOLVED
Definition: PageAccessFailureReasons.php:50
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\shouldAcquireCacheData
‪bool shouldAcquireCacheData(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1588
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$originalMountPointPage
‪array $originalMountPointPage
Definition: TypoScriptFrontendController.php:186
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:35
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:132
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getPageAndRootline
‪getPageAndRootline(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:777
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:57
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\get_cache_timeout
‪get_cache_timeout()
Definition: TypoScriptFrontendController.php:2639
‪TYPO3\CMS\Frontend\Event\AfterPageWithRootLineIsResolvedEvent
Definition: AfterPageWithRootLineIsResolvedEvent.php:31
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getRedirectUriForShortcut
‪getRedirectUriForShortcut(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1803
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\releaseLocks
‪releaseLocks()
Definition: TypoScriptFrontendController.php:2685
‪TYPO3\CMS\Core\Http\PropagateResponseException
Definition: PropagateResponseException.php:48
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getRelevantParametersForCachingFromPageArguments
‪getRelevantParametersForCachingFromPageArguments(PageArguments $pageArguments)
Definition: TypoScriptFrontendController.php:1106
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\LANGUAGE_NOT_AVAILABLE_STRICT_MODE
‪const LANGUAGE_NOT_AVAILABLE_STRICT_MODE
Definition: PageAccessFailureReasons.php:43
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getWebsiteTitle
‪getWebsiteTitle()
Definition: TypoScriptFrontendController.php:2154
‪$output
‪$output
Definition: annotationChecker.php:119
‪TYPO3\CMS\Core\Configuration\PageTsConfig
Definition: PageTsConfig.php:34
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\whichWorkspace
‪int whichWorkspace()
Definition: TypoScriptFrontendController.php:2528
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\createHashBase
‪string createHashBase(array $sysTemplateRows, array $constantConditionList, array $setupConditionList)
Definition: TypoScriptFrontendController.php:1607
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\printTitle
‪string printTitle(string $pageTitle, bool $noPageTitle=false, bool $showPageTitleFirst=false, string $pageTitleSeparator='', bool $showWebsiteTitle=true)
Definition: TypoScriptFrontendController.php:2137
‪TYPO3\CMS\Core\Cache\Frontend\FrontendInterface
Definition: FrontendInterface.php:22
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\logDeprecatedTyposcript
‪logDeprecatedTyposcript($typoScriptProperty, $explanation='')
Definition: TypoScriptFrontendController.php:2499
‪TYPO3\CMS\Core\Core\Environment\getFrameworkBasePath
‪static getFrameworkBasePath()
Definition: Environment.php:256
‪TYPO3\CMS\Core\TypoScript\TemplateService
Definition: TemplateService.php:46
‪TYPO3\CMS\Core\Error\Http\ShortcutTargetPageNotFoundException
Definition: ShortcutTargetPageNotFoundException.php:24
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$id
‪int $id
Definition: TypoScriptFrontendController.php:122
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getCacheHeaders
‪getCacheHeaders()
Definition: TypoScriptFrontendController.php:2354
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\logPageAccessFailure
‪logPageAccessFailure(string $message, ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:2721
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\addCacheTags
‪addCacheTags(array $tags)
Definition: TypoScriptFrontendController.php:1959
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:105
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\setTSlogMessage
‪setTSlogMessage(string $content, string $logLevel=LogLevel::INFO)
Definition: TimeTracker.php:173
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\TypoScript\AST\Node\ChildNode
Definition: ChildNode.php:24
‪TYPO3\CMS\Core\Error\Http\AbstractServerErrorException
Definition: AbstractServerErrorException.php:22
‪TYPO3\CMS\Core\TypoScript\AST\Node\RootNode
Definition: RootNode.php:26
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getUriToCurrentPageForRedirect
‪getUriToCurrentPageForRedirect(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1832
‪TYPO3\CMS\Core\Localization\Locale
Definition: Locale.php:30
‪TYPO3\CMS\Frontend\Page\CacheHashCalculator
Definition: CacheHashCalculator.php:25
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\INTincScript_loadJSCode
‪INTincScript_loadJSCode()
Definition: TypoScriptFrontendController.php:2284
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Traverser\ConditionVerdictAwareIncludeTreeTraverser
Definition: ConditionVerdictAwareIncludeTreeTraverser.php:38
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setSysLastChanged
‪setSysLastChanged()
Definition: TypoScriptFrontendController.php:1915
‪TYPO3\CMS\Core\Routing\PageArguments\getPageType
‪getPageType()
Definition: PageArguments.php:100
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\set_cache_timeout_default
‪set_cache_timeout_default($seconds)
Definition: TypoScriptFrontendController.php:2628
‪TYPO3\CMS\Frontend\Controller
Definition: ErrorController.php:18
‪TYPO3\CMS\Core\Exception\Page\RootLineException
Definition: RootLineException.php:25
‪TYPO3\CMS\Core\Type\DocType
‪DocType
Definition: DocType.php:27
‪TYPO3\CMS\Core\Utility\HttpUtility
Definition: HttpUtility.php:24
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\updateRootLinesWithTranslations
‪updateRootLinesWithTranslations()
Definition: TypoScriptFrontendController.php:1752
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
Definition: FrontendUserAuthentication.php:33
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\newCObj
‪newCObj(ServerRequestInterface $request=null)
Definition: TypoScriptFrontendController.php:2423
‪TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait
Definition: PublicPropertyDeprecationTrait.php:67
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:63
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:51
‪TYPO3\CMS\Core\TypoScript\FrontendTypoScript
Definition: FrontendTypoScript.php:29
‪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\Frontend\Event\ShouldUseCachedPageDataIfAvailableEvent
Definition: ShouldUseCachedPageDataIfAvailableEvent.php:28
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\applyHttpHeadersToResponse
‪applyHttpHeadersToResponse(ResponseInterface $response)
Definition: TypoScriptFrontendController.php:2314
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$language
‪SiteLanguage $language
Definition: TypoScriptFrontendController.php:130
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\setPageArguments
‪setPageArguments(PageArguments $pageArguments)
Definition: TypoScriptFrontendController.php:1088
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\getTimeTracker
‪TimeTracker getTimeTracker()
Definition: TypoScriptFrontendController.php:2745
‪TYPO3\CMS\Core\Http\ImmediateResponseException
Definition: ImmediateResponseException.php:35
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\resolveContentPid
‪int resolveContentPid(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:1993
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$rootLine
‪array $rootLine
Definition: TypoScriptFrontendController.php:168
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\set_no_cache
‪set_no_cache($reason='', $internalRequest=false)
Definition: TypoScriptFrontendController.php:2579
‪TYPO3\CMS\Frontend\Aspect\PreviewAspect
Definition: PreviewAspect.php:30
‪TYPO3\CMS\Core\TimeTracker\TimeTracker
Definition: TimeTracker.php:32
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\isBackendUserLoggedIn
‪bool isBackendUserLoggedIn()
Definition: TypoScriptFrontendController.php:595
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\language
‪$this language
Definition: TypoScriptFrontendController.php:505
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\site
‪$this site
Definition: TypoScriptFrontendController.php:504
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\initCaches
‪initCaches()
Definition: TypoScriptFrontendController.php:558
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_RECYCLER
‪const DOKTYPE_RECYCLER
Definition: PageRepository.php:133
‪TYPO3\CMS\Core\TypoScript\Tokenizer\LossyTokenizer
Definition: LossyTokenizer.php:57
‪TYPO3\CMS\Core\TypoScript\IncludeTree\SysTemplateTreeBuilder
Definition: SysTemplateTreeBuilder.php:72
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons
Definition: PageAccessFailureReasons.php:25
‪TYPO3\CMS\Core\Domain\Access\RecordAccessVoter
Definition: RecordAccessVoter.php:29
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\ROOTLINE_BROKEN
‪const ROOTLINE_BROKEN
Definition: PageAccessFailureReasons.php:29
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\$sys_page
‪PageRepository string $sys_page
Definition: TypoScriptFrontendController.php:198
‪TYPO3\CMS\Core\TimeTracker\TimeTracker\push
‪push(string $tslabel, string $value='')
Definition: TimeTracker.php:126
‪TYPO3\CMS\Core\Context\UserAspect
Definition: UserAspect.php:37
‪TYPO3\CMS\Core\Http\NormalizedParams
Definition: NormalizedParams.php:38
‪TYPO3\CMS\Frontend\Event\AfterCachedPageIsPersistedEvent
Definition: AfterCachedPageIsPersistedEvent.php:32
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\checkRootlineForIncludeSection
‪checkRootlineForIncludeSection()
Definition: TypoScriptFrontendController.php:985
‪TYPO3\CMS\Core\TypoScript\IncludeTree\Visitor\IncludeTreeConditionMatcherVisitor
Definition: IncludeTreeConditionMatcherVisitor.php:44
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController\INTincScript
‪INTincScript(ServerRequestInterface $request)
Definition: TypoScriptFrontendController.php:2169
‪TYPO3\CMS\Frontend\Page\PageAccessFailureReasons\RENDERING_INSTRUCTIONS_NOT_FOUND
‪const RENDERING_INSTRUCTIONS_NOT_FOUND
Definition: PageAccessFailureReasons.php:33