TYPO3 CMS  TYPO3_8-7
TemplateService.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
34 
41 {
49  protected $verbose = false;
50 
56  public $tt_track = true;
57 
63  public $forceTemplateParsing = false;
64 
72  public $matchAlternative = [];
73 
79  public $matchAll = false;
80 
86  public $ext_constants_BRP = 0;
87 
91  public $ext_config_BRP = 0;
92 
96  public $ext_regLinenumbers = false;
97 
101  public $ext_regComments = false;
102 
108  public $whereClause = '';
109 
113  public $debug = false;
114 
121  public $allowedPaths = [];
122 
129 
135  public $loaded = false;
136 
140  public $setup = [];
141 
145  public $flatSetup = [];
146 
154  public $config = [];
155 
161  public $constants = [];
162 
168  protected $templateIncludePaths = [];
169 
175  public $hierarchyInfo = [];
176 
182  public $hierarchyInfoToRoot = [];
183 
189  public $nextLevel = 0;
190 
196  public $rootId;
197 
203  public $rootLine;
204 
211 
218 
224  public $rowSum;
225 
231  public $sitetitle = '';
232 
238  public $sections;
239 
246 
250  public $clearList_const = [];
251 
257  public $clearList_setup = [];
258 
262  public $parserErrors = [];
263 
267  public $setup_constants = [];
268 
274  public $fileCache = [];
275 
281  public $frames = [];
282 
288  public $MPmap = '';
289 
299  protected $extensionStaticsProcessed = false;
300 
306  protected $processExtensionStatics = false;
307 
315  protected $isDefaultTypoScriptAdded = false;
316 
325  protected $processIncludesHasBeenRun = false;
326 
332 
336  public function getProcessExtensionStatics()
337  {
339  }
340 
345  {
346  $this->processExtensionStatics = (bool)$processExtensionStatics;
347  }
348 
353  public function setVerbose($verbose)
354  {
355  $this->verbose = (bool)$verbose;
356  }
357 
364  public function init()
365  {
367 
368  if ($this->getTypoScriptFrontendController()->showHiddenRecords || $GLOBALS['SIM_ACCESS_TIME'] !== $GLOBALS['ACCESS_TIME']) {
369  // Set the simulation flag, if simulation is detected!
370  $this->simulationHiddenOrTime = 1;
371  }
372 
373  // Sets the paths from where TypoScript resources are allowed to be used:
374  $this->allowedPaths = [
375  $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'],
376  // fileadmin/ path
377  'uploads/',
378  'typo3temp/',
379  TYPO3_mainDir . 'ext/',
380  TYPO3_mainDir . 'sysext/',
381  'typo3conf/ext/'
382  ];
383  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['addAllowedPaths']) {
384  $pathArr = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['addAllowedPaths'], true);
385  foreach ($pathArr as $p) {
386  // Once checked for path, but as this may run from typo3/mod/web/ts/ dir, that'll not work!! So the paths ar uncritically included here.
387  $this->allowedPaths[] = $p;
388  }
389  }
390  }
391 
396  {
397  // $this->whereClause is used only to select templates from sys_template.
398  // $GLOBALS['SIM_ACCESS_TIME'] is used so that we're able to simulate a later time as a test...
399  $this->whereClause = 'AND deleted=0 ';
400  if (!$this->getTypoScriptFrontendController()->showHiddenRecords) {
401  $this->whereClause .= 'AND hidden=0 ';
402  }
403  $this->whereClause .= 'AND (starttime<=' . $GLOBALS['SIM_ACCESS_TIME'] . ') AND (endtime=0 OR endtime>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
404 
405  // set up the query builder restrictions
406  $this->queryBuilderRestrictions = GeneralUtility::makeInstance(DefaultRestrictionContainer::class);
407 
408  if ($this->getTypoScriptFrontendController()->showHiddenRecords) {
409  $this->queryBuilderRestrictions
410  ->removeByType(HiddenRestriction::class);
411  }
412  }
413 
430  public function getCurrentPageData()
431  {
432  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pagesection')->get((int)$this->getTypoScriptFrontendController()->id . '_' . GeneralUtility::md5int($this->getTypoScriptFrontendController()->MP));
433  }
434 
441  public function matching($cc)
442  {
443  if (is_array($cc['all'])) {
445  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
446  $matchObj->setRootline((array)$cc['rootLine']);
447  $sectionsMatch = [];
448  foreach ($cc['all'] as $key => $pre) {
449  if ($matchObj->match($pre)) {
450  $sectionsMatch[$key] = $pre;
451  }
452  }
453  $cc['match'] = $sectionsMatch;
454  }
455  return $cc;
456  }
457 
466  public function start($theRootLine)
467  {
468  if (is_array($theRootLine)) {
469  $constantsData = [];
470  $setupData = [];
471  $cacheIdentifier = '';
472  // Flag that indicates that the existing data in cache_pagesection
473  // could be used (this is the case if $TSFE->all is set, and the
474  // rowSum still matches). Based on this we decide if cache_pagesection
475  // needs to be updated...
476  $isCached = false;
477  $this->runThroughTemplates($theRootLine);
478  if ($this->getTypoScriptFrontendController()->all) {
479  $cc = $this->getTypoScriptFrontendController()->all;
480  // The two rowSums must NOT be different from each other - which they will be if start/endtime or hidden has changed!
481  if (serialize($this->rowSum) !== serialize($cc['rowSum'])) {
482  unset($cc);
483  } else {
484  // If $TSFE->all contains valid data, we don't need to update cache_pagesection (because this data was fetched from there already)
485  if (serialize($this->rootLine) === serialize($cc['rootLine'])) {
486  $isCached = true;
487  }
488  // When the data is serialized below (ROWSUM hash), it must not contain the rootline by concept. So this must be removed (and added again later)...
489  unset($cc['rootLine']);
490  }
491  }
492  // This is about getting the hash string which is used to fetch the cached TypoScript template.
493  // If there was some cached currentPageData ($cc) then that's good (it gives us the hash).
494  if (isset($cc) && is_array($cc)) {
495  // If currentPageData was actually there, we match the result (if this wasn't done already in $TSFE->getFromCache()...)
496  if (!$cc['match']) {
497  // @todo check if this can ever be the case - otherwise remove
498  $cc = $this->matching($cc);
499  ksort($cc);
500  }
501  $cacheIdentifier = md5(serialize($cc));
502  } else {
503  // If currentPageData was not there, we first find $rowSum (freshly generated). After that we try to see, if it is stored with a list of all conditions. If so we match the result.
504  $rowSumHash = md5('ROWSUM:' . serialize($this->rowSum));
505  $result = $this->getCacheEntry($rowSumHash);
506  if (is_array($result)) {
507  $cc = [];
508  $cc['all'] = $result;
509  $cc['rowSum'] = $this->rowSum;
510  $cc = $this->matching($cc);
511  ksort($cc);
512  $cacheIdentifier = md5(serialize($cc));
513  }
514  }
515  if ($cacheIdentifier) {
516  // Get TypoScript setup array
517  $cachedData = $this->getCacheEntry($cacheIdentifier);
518  if (is_array($cachedData)) {
519  $constantsData = $cachedData['constants'];
520  $setupData = $cachedData['setup'];
521  }
522  }
523  if (!empty($setupData) && !$this->forceTemplateParsing) {
524  // TypoScript constants + setup are found in the cache
525  $this->setup_constants = $constantsData;
526  $this->setup = $setupData;
527  if ($this->tt_track) {
528  $this->getTimeTracker()->setTSlogMessage('Using cached TS template data');
529  }
530  } else {
531  if ($this->tt_track) {
532  $this->getTimeTracker()->setTSlogMessage('Not using any cached TS data');
533  }
534 
535  // Make configuration
536  $this->generateConfig();
537  // This stores the template hash thing
538  $cc = [];
539  // All sections in the template at this point is found
540  $cc['all'] = $this->sections;
541  // The line of templates is collected
542  $cc['rowSum'] = $this->rowSum;
543  $cc = $this->matching($cc);
544  ksort($cc);
545  $cacheIdentifier = md5(serialize($cc));
546  // This stores the data.
547  $this->setCacheEntry($cacheIdentifier, ['constants' => $this->setup_constants, 'setup' => $this->setup], 'TS_TEMPLATE');
548  if ($this->tt_track) {
549  $this->getTimeTracker()->setTSlogMessage('TS template size, serialized: ' . strlen(serialize($this->setup)) . ' bytes');
550  }
551  $rowSumHash = md5('ROWSUM:' . serialize($this->rowSum));
552  $this->setCacheEntry($rowSumHash, $cc['all'], 'TMPL_CONDITIONS_ALL');
553  }
554  // Add rootLine
555  $cc['rootLine'] = $this->rootLine;
556  ksort($cc);
557  // Make global and save
558  $this->getTypoScriptFrontendController()->all = $cc;
559  // Matching must be executed for every request, so this must never be part of the pagesection cache!
560  unset($cc['match']);
561  if (!$isCached && !$this->simulationHiddenOrTime && !$this->getTypoScriptFrontendController()->no_cache) {
562  // Only save the data if we're not simulating by hidden/starttime/endtime
563  $mpvarHash = GeneralUtility::md5int($this->getTypoScriptFrontendController()->MP);
565  $pageSectionCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pagesection');
566  $pageSectionCache->set((int)$this->getTypoScriptFrontendController()->id . '_' . $mpvarHash, $cc, [
567  'pageId_' . (int)$this->getTypoScriptFrontendController()->id,
568  'mpvarHash_' . $mpvarHash
569  ]);
570  }
571  // If everything OK.
572  if ($this->rootId && $this->rootLine && $this->setup) {
573  $this->loaded = true;
574  }
575  }
576  }
577 
578  /*******************************************************************
579  *
580  * Fetching TypoScript code text for the Template Hierarchy
581  *
582  *******************************************************************/
592  public function runThroughTemplates($theRootLine, $start_template_uid = 0)
593  {
594  $this->constants = [];
595  $this->config = [];
596  $this->rowSum = [];
597  $this->hierarchyInfoToRoot = [];
598  $this->absoluteRootLine = $theRootLine;
599  $this->isDefaultTypoScriptAdded = false;
600 
601  reset($this->absoluteRootLine);
602  $c = count($this->absoluteRootLine);
603  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template');
604  for ($a = 0; $a < $c; $a++) {
605  // If some template loaded before has set a template-id for the next level, then load this template first!
606  if ($this->nextLevel) {
607  $queryBuilder->setRestrictions($this->queryBuilderRestrictions);
608  $queryResult = $queryBuilder
609  ->select('*')
610  ->from('sys_template')
611  ->where(
612  $queryBuilder->expr()->eq(
613  'uid',
614  $queryBuilder->createNamedParameter($this->nextLevel, \PDO::PARAM_INT)
615  )
616  )
617  ->execute();
618  $this->nextLevel = 0;
619  if ($row = $queryResult->fetch()) {
620  $this->versionOL($row);
621  if (is_array($row)) {
622  $this->processTemplate($row, 'sys_' . $row['uid'], $this->absoluteRootLine[$a]['uid'], 'sys_' . $row['uid']);
623  $this->outermostRootlineIndexWithTemplate = $a;
624  }
625  }
626  }
627 
628  $where = [
629  $queryBuilder->expr()->eq(
630  'pid',
631  $queryBuilder->createNamedParameter($this->absoluteRootLine[$a]['uid'], \PDO::PARAM_INT)
632  )
633  ];
634  // If first loop AND there is set an alternative template uid, use that
635  if ($a === $c - 1 && $start_template_uid) {
636  $where[] = $queryBuilder->expr()->eq(
637  'uid',
638  $queryBuilder->createNamedParameter($start_template_uid, \PDO::PARAM_INT)
639  );
640  }
641  $queryBuilder->setRestrictions($this->queryBuilderRestrictions);
642  $queryResult = $queryBuilder
643  ->select('*')
644  ->from('sys_template')
645  ->where(...$where)
646  ->orderBy('root', 'DESC')
647  ->addOrderBy('sorting')
648  ->setMaxResults(1)
649  ->execute();
650  if ($row = $queryResult->fetch()) {
651  $this->versionOL($row);
652  if (is_array($row)) {
653  $this->processTemplate($row, 'sys_' . $row['uid'], $this->absoluteRootLine[$a]['uid'], 'sys_' . $row['uid']);
654  $this->outermostRootlineIndexWithTemplate = $a;
655  }
656  }
657  $this->rootLine[] = $this->absoluteRootLine[$a];
658  }
659 
660  // Hook into the default TypoScript to add custom typoscript logic
661  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Core/TypoScript/TemplateService']['runThroughTemplatesPostProcessing'])) {
662  $hookParameters = [
663  'extensionStaticsProcessed' => &$this->extensionStaticsProcessed,
664  'isDefaultTypoScriptAdded' => &$this->isDefaultTypoScriptAdded,
665  'absoluteRootLine' => &$this->absoluteRootLine,
666  'rootLine' => &$this->rootLine,
667  'startTemplateUid' => $start_template_uid,
668  ];
669  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Core/TypoScript/TemplateService']['runThroughTemplatesPostProcessing'] as $listener) {
670  GeneralUtility::callUserFunction($listener, $hookParameters, $this);
671  }
672  }
673 
674  // Process extension static files if not done yet, but explicitly requested
675  if (!$this->extensionStaticsProcessed && $this->processExtensionStatics) {
676  $this->addExtensionStatics('sys_0', 'sys_0', 0, []);
677  }
678 
679  // Add the global default TypoScript from the TYPO3_CONF_VARS
680  $this->addDefaultTypoScript();
681 
682  $this->processIncludes();
683  }
684 
697  public function processTemplate($row, $idList, $pid, $templateID = '', $templateParent = '', $includePath = '')
698  {
699  // Adding basic template record information to rowSum array
700  $this->rowSum[] = [$row['uid'], $row['title'], $row['tstamp']];
701  // Processing "Clear"-flags
702  $clConst = 0;
703  $clConf = 0;
704  if ($row['clear']) {
705  $clConst = $row['clear'] & 1;
706  $clConf = $row['clear'] & 2;
707  if ($clConst) {
708  // Keep amount of items to stay in sync with $this->templateIncludePaths so processIncludes() does not break
709  foreach ($this->constants as &$constantConfiguration) {
710  $constantConfiguration = '';
711  }
712  unset($constantConfiguration);
713  $this->clearList_const = [];
714  }
715  if ($clConf) {
716  // Keep amount of items to stay in sync with $this->templateIncludePaths so processIncludes() does not break
717  foreach ($this->config as &$configConfiguration) {
718  $configConfiguration = '';
719  }
720  unset($configConfiguration);
721  $this->hierarchyInfoToRoot = [];
722  $this->clearList_setup = [];
723  }
724  }
725  // Include static records (static_template) or files (from extensions) (#1/2)
726  // NORMAL inclusion, The EXACT same code is found below the basedOn inclusion!!!
727  if (!$row['includeStaticAfterBasedOn']) {
728  $this->includeStaticTypoScriptSources($idList, $templateID, $pid, $row);
729  }
730  // Include "Based On" sys_templates:
731  // 'basedOn' is a list of templates to include
732  if (trim($row['basedOn'])) {
733  // Normal Operation, which is to include the "based-on" sys_templates,
734  // if they are not already included, and maintaining the sorting of the templates
735  $basedOnIds = GeneralUtility::intExplode(',', $row['basedOn'], true);
736  // skip template if it's already included
737  foreach ($basedOnIds as $key => $basedOnId) {
738  if (GeneralUtility::inList($idList, 'sys_' . $basedOnId)) {
739  unset($basedOnIds[$key]);
740  }
741  }
742  if (!empty($basedOnIds)) {
743  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template');
744  $queryBuilder->setRestrictions($this->queryBuilderRestrictions);
745  $queryResult = $queryBuilder
746  ->select('*')
747  ->from('sys_template')
748  ->where(
749  $queryBuilder->expr()->in(
750  'uid',
751  $queryBuilder->createNamedParameter($basedOnIds, Connection::PARAM_INT_ARRAY)
752  )
753  )
754  ->execute();
755  // make it an associative array with the UID as key
756  $subTemplates = [];
757  while ($rowItem = $queryResult->fetch()) {
758  $subTemplates[(int)$rowItem['uid']] = $rowItem;
759  }
760  // Traversing list again to ensure the sorting of the templates
761  foreach ($basedOnIds as $id) {
762  if (is_array($subTemplates[$id])) {
763  $this->versionOL($subTemplates[$id]);
764  $this->processTemplate($subTemplates[$id], $idList . ',sys_' . $id, $pid, 'sys_' . $id, $templateID);
765  }
766  }
767  }
768  }
769  // Include static records (static_template) or files (from extensions) (#2/2)
770  if ($row['includeStaticAfterBasedOn']) {
771  $this->includeStaticTypoScriptSources($idList, $templateID, $pid, $row);
772  }
773  // Creating hierarchy information; Used by backend analysis tools
774  $this->hierarchyInfo[] = ($this->hierarchyInfoToRoot[] = [
775  'root' => trim($row['root']),
776  'next' => $row['nextLevel'],
777  'clConst' => $clConst,
778  'clConf' => $clConf,
779  'templateID' => $templateID,
780  'templateParent' => $templateParent,
781  'title' => $row['title'],
782  'uid' => $row['uid'],
783  'pid' => $row['pid'],
784  'configLines' => substr_count($row['config'], LF) + 1
785  ]);
786  // Adding the content of the fields constants (Constants) and config (Setup)
787  $this->constants[] = $row['constants'];
788  $this->config[] = $row['config'];
789  $this->templateIncludePaths[] = $includePath;
790  // For backend analysis (Template Analyser) provide the order of added constants/config template IDs
791  $this->clearList_const[] = $templateID;
792  $this->clearList_setup[] = $templateID;
793  if (trim($row['sitetitle'])) {
794  $this->sitetitle = $row['sitetitle'];
795  }
796  // If the template record is a Rootlevel record, set the flag and clear the template rootLine (so it starts over from this point)
797  if (trim($row['root'])) {
798  $this->rootId = $pid;
799  $this->rootLine = [];
800  }
801  // If a template is set to be active on the next level set this internal value to point to this UID. (See runThroughTemplates())
802  if ($row['nextLevel']) {
803  $this->nextLevel = $row['nextLevel'];
804  } else {
805  $this->nextLevel = 0;
806  }
807  }
808 
819  public function updateRootlineData($fullRootLine)
820  {
821  if (!is_array($this->rootLine) || empty($this->rootLine)) {
822  return;
823  }
824 
825  $fullRootLineByUid = [];
826  foreach ($fullRootLine as $rootLineData) {
827  $fullRootLineByUid[$rootLineData['uid']] = $rootLineData;
828  }
829 
830  foreach ($this->rootLine as $level => $dataArray) {
831  $currentUid = $dataArray['uid'];
832 
833  if (!array_key_exists($currentUid, $fullRootLineByUid)) {
834  throw new \RuntimeException(sprintf('The full rootLine does not contain data for the page with the uid %d that is contained in the template rootline.', $currentUid), 1370419654);
835  }
836 
837  $this->rootLine[$level] = $fullRootLineByUid[$currentUid];
838  }
839  }
840 
850  public function includeStaticTypoScriptSources($idList, $templateID, $pid, $row)
851  {
852  // Static Template Records (static_template): include_static is a list of static templates to include
853  // Call function for link rendering:
854  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources'])) {
855  $_params = [
856  'idList' => &$idList,
857  'templateId' => &$templateID,
858  'pid' => &$pid,
859  'row' => &$row
860  ];
861  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources'] as $_funcRef) {
862  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
863  }
864  }
865  // If "Include before all static templates if root-flag is set" is set:
866  if ($row['static_file_mode'] == 3 && strpos($templateID, 'sys_') === 0 && $row['root']) {
867  $this->addExtensionStatics($idList, $templateID, $pid, $row);
868  }
869  // Static Template Files (Text files from extensions): include_static_file is a list of static files to include (from extensions)
870  if (trim($row['include_static_file'])) {
871  $include_static_fileArr = GeneralUtility::trimExplode(',', $row['include_static_file'], true);
872  // Traversing list
873  foreach ($include_static_fileArr as $ISF_file) {
874  if (strpos($ISF_file, 'EXT:') === 0) {
875  list($ISF_extKey, $ISF_localPath) = explode('/', substr($ISF_file, 4), 2);
876  if ((string)$ISF_extKey !== '' && ExtensionManagementUtility::isLoaded($ISF_extKey) && (string)$ISF_localPath !== '') {
877  $ISF_localPath = rtrim($ISF_localPath, '/') . '/';
878  $ISF_filePath = ExtensionManagementUtility::extPath($ISF_extKey) . $ISF_localPath;
879  if (@is_dir($ISF_filePath)) {
880  $mExtKey = str_replace('_', '', $ISF_extKey . '/' . $ISF_localPath);
881  $subrow = [
882  'constants' => $this->getTypoScriptSourceFileContent($ISF_filePath, 'constants'),
883  'config' => $this->getTypoScriptSourceFileContent($ISF_filePath, 'setup'),
884  'include_static' => @file_exists(($ISF_filePath . 'include_static.txt')) ? implode(',', array_unique(GeneralUtility::intExplode(',', file_get_contents($ISF_filePath . 'include_static.txt')))) : '',
885  'include_static_file' => @file_exists(($ISF_filePath . 'include_static_file.txt')) ? implode(',', array_unique(explode(',', file_get_contents($ISF_filePath . 'include_static_file.txt')))) : '',
886  'title' => $ISF_file,
887  'uid' => $mExtKey
888  ];
889  $subrow = $this->prependStaticExtra($subrow);
890  $this->processTemplate($subrow, $idList . ',ext_' . $mExtKey, $pid, 'ext_' . $mExtKey, $templateID, $ISF_filePath);
891  }
892  }
893  }
894  }
895  }
896  // If "Default (include before if root flag is set)" is set OR
897  // "Always include before this template record" AND root-flag are set
898  if ($row['static_file_mode'] == 1 || $row['static_file_mode'] == 0 && substr($templateID, 0, 4) === 'sys_' && $row['root']) {
899  $this->addExtensionStatics($idList, $templateID, $pid, $row);
900  }
901  // Include Static Template Records after all other TypoScript has been included.
902  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSourcesAtEnd'])) {
903  $_params = [
904  'idList' => &$idList,
905  'templateId' => &$templateID,
906  'pid' => &$pid,
907  'row' => &$row
908  ];
909  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSourcesAtEnd'] as $_funcRef) {
910  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
911  }
912  }
913  }
914 
923  protected function getTypoScriptSourceFileContent($filePath, $baseName)
924  {
925  $extensions = ['.typoscript', '.ts', '.txt'];
926  foreach ($extensions as $extension) {
927  $fileName = $filePath . $baseName . $extension;
928  if (@file_exists($fileName)) {
929  return file_get_contents($fileName);
930  }
931  }
932  return '';
933  }
934 
945  public function addExtensionStatics($idList, $templateID, $pid, $row)
946  {
947  $this->extensionStaticsProcessed = true;
948 
949  // @todo Change to use new API
950  foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extKey => $files) {
951  if ((is_array($files) || $files instanceof \ArrayAccess)
952  && (
953  !empty($files['ext_typoscript_constants.txt'])
954  || !empty($files['ext_typoscript_constants.typoscript'])
955  || !empty($files['ext_typoscript_setup.txt'])
956  || !empty($files['ext_typoscript_setup.typoscript'])
957  )
958  ) {
959  $mExtKey = str_replace('_', '', $extKey);
960  $constants = '';
961  $config = '';
962 
963  if (!empty($files['ext_typoscript_constants.typoscript'])) {
964  $constants = @file_get_contents($files['ext_typoscript_constants.typoscript']);
965  } elseif (!empty($files['ext_typoscript_constants.txt'])) {
966  $constants = @file_get_contents($files['ext_typoscript_constants.txt']);
967  }
968 
969  if (!empty($files['ext_typoscript_setup.typoscript'])) {
970  $config = @file_get_contents($files['ext_typoscript_setup.typoscript']);
971  } elseif (!empty($files['ext_typoscript_setup.txt'])) {
972  $config = @file_get_contents($files['ext_typoscript_setup.txt']);
973  }
974 
975  $this->processTemplate(
976  $this->prependStaticExtra([
977  'constants' => $constants,
978  'config' => $config,
979  'title' => $extKey,
980  'uid' => $mExtKey
981  ]),
982  $idList . ',ext_' . $mExtKey,
983  $pid,
984  'ext_' . $mExtKey,
985  $templateID,
987  );
988  }
989  }
990  }
991 
1002  public function prependStaticExtra($subrow)
1003  {
1004  // the identifier can be "43" if coming from "static template" extension or a path like "cssstyledcontent/static/"
1005  $identifier = $subrow['uid'];
1006  $subrow['config'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.'][$identifier];
1007  $subrow['constants'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.'][$identifier];
1008  // if this is a template of type "default content rendering", also see if other extensions have added their TypoScript that should be included after the content definitions
1009  if (in_array($identifier, $GLOBALS['TYPO3_CONF_VARS']['FE']['contentRenderingTemplates'], true)) {
1010  $subrow['config'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['defaultContentRendering'];
1011  $subrow['constants'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['defaultContentRendering'];
1012  }
1013  return $subrow;
1014  }
1015 
1022  public function versionOL(&$row)
1023  {
1024  // Distinguish frontend and backend call:
1025  // To do the fronted call a full frontend is required, just checking for
1026  // TYPO3_MODE === 'FE' is not enough. This could otherwise lead to fatals in
1027  // eId scripts that run in frontend scope, but do not have a full blown frontend.
1028  if (is_object($this->getTypoScriptFrontendController()) && property_exists($this->getTypoScriptFrontendController(), 'sys_page') && method_exists($this->getTypoScriptFrontendController()->sys_page, 'versionOL')) {
1029  // Frontend
1030  $this->getTypoScriptFrontendController()->sys_page->versionOL('sys_template', $row);
1031  } else {
1032  // Backend
1033  BackendUtility::workspaceOL('sys_template', $row);
1034  }
1035  }
1036 
1037  /*******************************************************************
1038  *
1039  * Parsing TypoScript code text from Template Records into PHP array
1040  *
1041  *******************************************************************/
1048  public function generateConfig()
1049  {
1050  // Add default TS for all code types
1051  $this->addDefaultTypoScript();
1052 
1053  // Parse the TypoScript code text for include-instructions!
1054  $this->processIncludes();
1055  // These vars are also set lateron...
1056  $this->setup['sitetitle'] = $this->sitetitle;
1057  // ****************************
1058  // Parse TypoScript Constants
1059  // ****************************
1060  // Initialize parser and match-condition classes:
1062  $constants = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1063  $constants->breakPointLN = (int)$this->ext_constants_BRP;
1064  $constants->setup = $this->mergeConstantsFromPageTSconfig([]);
1066  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
1067  $matchObj->setSimulateMatchConditions($this->matchAlternative);
1068  $matchObj->setSimulateMatchResult((bool)$this->matchAll);
1069  // Traverse constants text fields and parse them
1070  foreach ($this->constants as $str) {
1071  $constants->parse($str, $matchObj);
1072  }
1073  // Read out parse errors if any
1074  $this->parserErrors['constants'] = $constants->errors;
1075  // Then flatten the structure from a multi-dim array to a single dim array with all constants listed as key/value pairs (ready for substitution)
1076  $this->flatSetup = [];
1077  $this->flattenSetup($constants->setup, '');
1078  // ***********************************************
1079  // Parse TypoScript Setup (here called "config")
1080  // ***********************************************
1081  // Initialize parser and match-condition classes:
1083  $config = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1084  $config->breakPointLN = (int)$this->ext_config_BRP;
1085  $config->regLinenumbers = $this->ext_regLinenumbers;
1086  $config->regComments = $this->ext_regComments;
1087  $config->setup = $this->setup;
1088  // Transfer information about conditions found in "Constants" and which of them returned TRUE.
1089  $config->sections = $constants->sections;
1090  $config->sectionsMatch = $constants->sectionsMatch;
1091  // Traverse setup text fields and concatenate them into one, single string separated by a [GLOBAL] condition
1092  $all = '';
1093  foreach ($this->config as $str) {
1094  $all .= '
1095 [GLOBAL]
1096 ' . $str;
1097  }
1098  // Substitute constants in the Setup code:
1099  if ($this->tt_track) {
1100  $this->getTimeTracker()->push('Substitute Constants (' . count($this->flatSetup) . ')');
1101  }
1102  $all = $this->substituteConstants($all);
1103  if ($this->tt_track) {
1104  $this->getTimeTracker()->pull();
1105  }
1106 
1107  // Searching for possible unsubstituted constants left (only for information)
1108  if ($this->verbose) {
1109  if (preg_match_all('/\\{\\$.[^}]*\\}/', $all, $constantList) > 0) {
1110  if ($this->tt_track) {
1111  $this->getTimeTracker()->setTSlogMessage(implode(', ', $constantList[0]) . ': Constants may remain un-substituted!!', 2);
1112  }
1113  }
1114  }
1115 
1116  // Logging the textual size of the TypoScript Setup field text with all constants substituted:
1117  if ($this->tt_track) {
1118  $this->getTimeTracker()->setTSlogMessage('TypoScript template size as textfile: ' . strlen($all) . ' bytes');
1119  }
1120  // Finally parse the Setup field TypoScript code (where constants are now substituted)
1121  $config->parse($all, $matchObj);
1122  // Read out parse errors if any
1123  $this->parserErrors['config'] = $config->errors;
1124  // Transfer the TypoScript array from the parser object to the internal $this->setup array:
1125  $this->setup = $config->setup;
1126  // Do the same for the constants
1127  $this->setup_constants = $constants->setup;
1128  // ****************************************************************
1129  // Final processing of the $this->setup TypoScript Template array
1130  // Basically: This is unsetting/setting of certain reserved keys.
1131  // ****************************************************************
1132  // These vars are already set after 'processTemplate', but because $config->setup overrides them (in the line above!), we set them again. They are not changed compared to the value they had in the top of the page!
1133  unset($this->setup['sitetitle']);
1134  unset($this->setup['sitetitle.']);
1135  $this->setup['sitetitle'] = $this->sitetitle;
1136  // Unsetting some vars...
1137  unset($this->setup['types.']);
1138  unset($this->setup['types']);
1139  if (is_array($this->setup)) {
1140  foreach ($this->setup as $key => $value) {
1141  if ($value === 'PAGE') {
1142  // Set the typeNum of the current page object:
1143  if (isset($this->setup[$key . '.']['typeNum'])) {
1144  $typeNum = $this->setup[$key . '.']['typeNum'];
1145  $this->setup['types.'][$typeNum] = $key;
1146  } elseif (!isset($this->setup['types.'][0]) || !$this->setup['types.'][0]) {
1147  $this->setup['types.'][0] = $key;
1148  }
1149  }
1150  }
1151  }
1152  unset($this->setup['temp.']);
1153  unset($constants);
1154  // Storing the conditions found/matched information:
1155  $this->sections = $config->sections;
1156  $this->sectionsMatch = $config->sectionsMatch;
1157  }
1158 
1166  public function processIncludes()
1167  {
1168  if ($this->processIncludesHasBeenRun) {
1169  return;
1170  }
1171 
1172  $paths = $this->templateIncludePaths;
1173  $files = [];
1174  foreach ($this->constants as &$value) {
1175  $includeData = Parser\TypoScriptParser::checkIncludeLines($value, 1, true, array_shift($paths));
1176  $files = array_merge($files, $includeData['files']);
1177  $value = $includeData['typoscript'];
1178  }
1179  unset($value);
1180  $paths = $this->templateIncludePaths;
1181  foreach ($this->config as &$value) {
1182  $includeData = Parser\TypoScriptParser::checkIncludeLines($value, 1, true, array_shift($paths));
1183  $files = array_merge($files, $includeData['files']);
1184  $value = $includeData['typoscript'];
1185  }
1186  unset($value);
1187 
1188  if (!empty($files)) {
1189  $files = array_unique($files);
1190  foreach ($files as $file) {
1191  $this->rowSum[] = [$file, filemtime($file)];
1192  }
1193  }
1194 
1195  $this->processIncludesHasBeenRun = true;
1196  }
1197 
1205  public function mergeConstantsFromPageTSconfig($constArray)
1206  {
1207  $TSdataArray = [];
1208  // Setting default configuration:
1209  $TSdataArray[] = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'];
1210  for ($a = 0; $a <= $this->outermostRootlineIndexWithTemplate; $a++) {
1211  if (trim($this->absoluteRootLine[$a]['tsconfig_includes'])) {
1212  $includeTsConfigFileList = GeneralUtility::trimExplode(
1213  ',',
1214  $this->absoluteRootLine[$a]['tsconfig_includes'],
1215  true
1216  );
1217 
1218  $TSdataArray = $this->mergeConstantsFromIncludedTsConfigFiles($includeTsConfigFileList, $TSdataArray);
1219  }
1220  $TSdataArray[] = $this->absoluteRootLine[$a]['TSconfig'];
1221  }
1222  // Parsing the user TS (or getting from cache)
1223  $TSdataArray = Parser\TypoScriptParser::checkIncludeLines_array($TSdataArray);
1224  $userTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
1226  $parseObj = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1227  $parseObj->parse($userTS);
1228  if (is_array($parseObj->setup['TSFE.']['constants.'])) {
1229  ArrayUtility::mergeRecursiveWithOverrule($constArray, $parseObj->setup['TSFE.']['constants.']);
1230  }
1231 
1232  return $constArray;
1233  }
1234 
1242  protected function mergeConstantsFromIncludedTsConfigFiles($filesToInclude, $TSdataArray)
1243  {
1244  foreach ($filesToInclude as $key => $file) {
1245  if (strpos($file, 'EXT:') !== 0) {
1246  continue;
1247  }
1248 
1249  list($extensionKey, $filePath) = explode('/', substr($file, 4), 2);
1250 
1251  if ((string)$extensionKey === '' || !ExtensionManagementUtility::isLoaded($extensionKey)) {
1252  continue;
1253  }
1254  if ((string)$filePath == '') {
1255  continue;
1256  }
1257 
1258  $tsConfigFile = ExtensionManagementUtility::extPath($extensionKey) . $filePath;
1259  if (file_exists($tsConfigFile)) {
1260  $TSdataArray[] = file_get_contents($tsConfigFile);
1261  }
1262  }
1263 
1264  return $TSdataArray;
1265  }
1266 
1274  public function flattenSetup($setupArray, $prefix)
1275  {
1276  if (is_array($setupArray)) {
1277  foreach ($setupArray as $key => $val) {
1278  if ($prefix || strpos($key, 'TSConstantEditor') !== 0) {
1279  // We don't want 'TSConstantEditor' in the flattened setup on the first level (190201)
1280  if (is_array($val)) {
1281  $this->flattenSetup($val, $prefix . $key);
1282  } else {
1283  $this->flatSetup[$prefix . $key] = $val;
1284  }
1285  }
1286  }
1287  }
1288  }
1289 
1297  public function substituteConstants($all)
1298  {
1299  if ($this->tt_track) {
1300  $this->getTimeTracker()->setTSlogMessage('Constants to substitute: ' . count($this->flatSetup));
1301  }
1302  $noChange = false;
1303  // Recursive substitution of constants (up to 10 nested levels)
1304  for ($i = 0; $i < 10 && !$noChange; $i++) {
1305  $old_all = $all;
1306  $all = preg_replace_callback('/\\{\\$(.[^}]*)\\}/', [$this, 'substituteConstantsCallBack'], $all);
1307  if ($old_all == $all) {
1308  $noChange = true;
1309  }
1310  }
1311  return $all;
1312  }
1313 
1321  public function substituteConstantsCallBack($matches)
1322  {
1323  // Replace {$CONST} if found in $this->flatSetup, else leave unchanged
1324  return isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? $this->flatSetup[$matches[1]] : $matches[0];
1325  }
1326 
1327  /*******************************************************************
1328  *
1329  * Various API functions, used from elsewhere in the frontend classes
1330  *
1331  *******************************************************************/
1343  public function splitConfArray($conf, $splitCount)
1344  {
1346  if (!is_array($conf)) {
1347  return [];
1348  }
1349  return GeneralUtility::makeInstance(TypoScriptService::class)->explodeConfigurationForOptionSplit($conf, (int)$splitCount);
1350  }
1351 
1358  public function getFileName($fileFromSetup)
1359  {
1360  $file = trim($fileFromSetup);
1361  if (!$file) {
1362  return null;
1363  }
1364  if (strpos($file, '../') !== false) {
1365  if ($this->tt_track) {
1366  $this->getTimeTracker()->setTSlogMessage('File path "' . $file . '" contained illegal string "../"!', 3);
1367  }
1368  return null;
1369  }
1370  // Cache
1371  $hash = md5($file);
1372  if (isset($this->fileCache[$hash])) {
1373  return $this->fileCache[$hash];
1374  }
1375 
1376  // if this is an URL, it can be returned directly
1377  $urlScheme = parse_url($file, PHP_URL_SCHEME);
1378  if ($urlScheme === 'https' || $urlScheme === 'http' || is_file(PATH_site . $file)) {
1379  return $file;
1380  }
1381 
1382  // this call also resolves EXT:myext/ files
1383  $file = GeneralUtility::getFileAbsFileName($file);
1384  if (!$file) {
1385  if ($this->tt_track) {
1386  $this->getTimeTracker()->setTSlogMessage('File "' . $fileFromSetup . '" was not found!', 3);
1387  }
1388  return null;
1389  }
1390 
1391  $file = PathUtility::stripPathSitePrefix($file);
1392 
1393  // Check if the found file is in the allowed paths
1394  foreach ($this->allowedPaths as $val) {
1395  if (GeneralUtility::isFirstPartOfStr($file, $val)) {
1396  $this->fileCache[$hash] = $file;
1397  return $file;
1398  }
1399  }
1400 
1401  if ($this->tt_track) {
1402  $this->getTimeTracker()->setTSlogMessage('"' . $file . '" was not located in the allowed paths: (' . implode(',', $this->allowedPaths) . ')', 3);
1403  }
1404  return null;
1405  }
1406 
1417  public function printTitle($pageTitle, $noTitle = false, $showTitleFirst = false, $pageTitleSeparator = '')
1418  {
1419  $siteTitle = trim($this->setup['sitetitle']);
1420  $pageTitle = $noTitle ? '' : $pageTitle;
1421  if ($showTitleFirst) {
1422  $temp = $siteTitle;
1423  $siteTitle = $pageTitle;
1424  $pageTitle = $temp;
1425  }
1426  // only show a separator if there are both site title and page title
1427  if ($pageTitle === '' || $siteTitle === '') {
1428  $pageTitleSeparator = '';
1429  } elseif (empty($pageTitleSeparator)) {
1430  // use the default separator if non given
1431  $pageTitleSeparator = ': ';
1432  }
1433  return $siteTitle . $pageTitleSeparator . $pageTitle;
1434  }
1435 
1444  public function fileContent($fileName)
1445  {
1447  $fileName = $this->getFileName($fileName);
1448  if ($fileName) {
1449  return GeneralUtility::getUrl($fileName);
1450  }
1451  return null;
1452  }
1453 
1462  public function removeQueryString($url)
1463  {
1465  if (substr($url, -1) === '?') {
1466  return substr($url, 0, -1);
1467  }
1468  return $url;
1469  }
1470 
1481  public static function sortedKeyList($setupArr, $acceptOnlyProperties = false)
1482  {
1484  return ArrayUtility::filterAndSortByNumericKeys($setupArr, $acceptOnlyProperties);
1485  }
1486 
1493  public function getRootlineLevel($list)
1494  {
1495  $idx = 0;
1496  foreach ($this->rootLine as $page) {
1497  if (GeneralUtility::inList($list, $page['uid'])) {
1498  return $idx;
1499  }
1500  $idx++;
1501  }
1502  return false;
1503  }
1504 
1505  /*******************************************************************
1506  *
1507  * Functions for creating links
1508  *
1509  *******************************************************************/
1527  public function linkData($page, $oTarget, $no_cache, $script, $overrideArray = null, $addParams = '', $typeOverride = '', $targetDomain = '')
1528  {
1529  $LD = [];
1530  // Overriding some fields in the page record and still preserves the values by adding them as parameters. Little strange function.
1531  if (is_array($overrideArray)) {
1532  foreach ($overrideArray as $theKey => $theNewVal) {
1533  $addParams .= '&real_' . $theKey . '=' . rawurlencode($page[$theKey]);
1534  $page[$theKey] = $theNewVal;
1535  }
1536  }
1537  // Adding Mount Points, "&MP=", parameter for the current page if any is set:
1538  if (!strstr($addParams, '&MP=')) {
1539  // Looking for hardcoded defaults:
1540  if (trim($this->getTypoScriptFrontendController()->MP_defaults[$page['uid']])) {
1541  $addParams .= '&MP=' . rawurlencode(trim($this->getTypoScriptFrontendController()->MP_defaults[$page['uid']]));
1542  } elseif ($this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints']) {
1543  // Else look in automatically created map:
1544  $m = $this->getFromMPmap($page['uid']);
1545  if ($m) {
1546  $addParams .= '&MP=' . rawurlencode($m);
1547  }
1548  }
1549  }
1550  // Setting ID/alias:
1551  if (!$script) {
1552  $script = $this->getTypoScriptFrontendController()->config['mainScript'];
1553  }
1554  if ($page['alias']) {
1555  $LD['url'] = $script . '?id=' . rawurlencode($page['alias']);
1556  } else {
1557  $LD['url'] = $script . '?id=' . $page['uid'];
1558  }
1559  // Setting target
1560  $LD['target'] = trim($page['target']) ?: $oTarget;
1561  // typeNum
1562  $typeNum = $this->setup[$LD['target'] . '.']['typeNum'];
1563  if (!MathUtility::canBeInterpretedAsInteger($typeOverride) && (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue']) {
1564  $typeOverride = (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue'];
1565  }
1566  if ((string)$typeOverride !== '') {
1567  $typeNum = $typeOverride;
1568  }
1569  // Override...
1570  if ($typeNum) {
1571  $LD['type'] = '&type=' . (int)$typeNum;
1572  } else {
1573  $LD['type'] = '';
1574  }
1575  // Preserving the type number.
1576  $LD['orig_type'] = $LD['type'];
1577  // noCache
1578  $LD['no_cache'] = trim($page['no_cache']) || $no_cache ? '&no_cache=1' : '';
1579  // linkVars
1580  if ($addParams) {
1581  $LD['linkVars'] = GeneralUtility::implodeArrayForUrl('', GeneralUtility::explodeUrl2Array($this->getTypoScriptFrontendController()->linkVars . $addParams), '', false, true);
1582  } else {
1583  $LD['linkVars'] = $this->getTypoScriptFrontendController()->linkVars;
1584  }
1585  // Add absRefPrefix if exists.
1586  $LD['url'] = $this->getTypoScriptFrontendController()->absRefPrefix . $LD['url'];
1587  // If the special key 'sectionIndex_uid' (added 'manually' in tslib/menu.php to the page-record) is set, then the link jumps directly to a section on the page.
1588  $LD['sectionIndex'] = $page['sectionIndex_uid'] ? '#c' . $page['sectionIndex_uid'] : '';
1589  // Compile the normal total url
1590  $LD['totalURL'] = rtrim($LD['url'] . $LD['type'] . $LD['no_cache'] . $LD['linkVars'] . $this->getTypoScriptFrontendController()->getMethodUrlIdToken, '?') . $LD['sectionIndex'];
1591  // Call post processing function for link rendering:
1592  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'])) {
1593  $_params = [
1594  'LD' => &$LD,
1595  'args' => ['page' => $page, 'oTarget' => $oTarget, 'no_cache' => $no_cache, 'script' => $script, 'overrideArray' => $overrideArray, 'addParams' => $addParams, 'typeOverride' => $typeOverride, 'targetDomain' => $targetDomain],
1596  'typeNum' => $typeNum
1597  ];
1598  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'] as $_funcRef) {
1599  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1600  }
1601  }
1602  // Return the LD-array
1603  return $LD;
1604  }
1605 
1615  public function getFromMPmap($pageId = 0)
1616  {
1617  // Create map if not found already:
1618  if (!is_array($this->MPmap)) {
1619  $this->MPmap = [];
1620  $rootPoints = GeneralUtility::trimExplode(',', strtolower($this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints']), true);
1621  // Traverse rootpoints:
1622  foreach ($rootPoints as $p) {
1623  $initMParray = [];
1624  if ($p === 'root') {
1625  $p = $this->rootLine[0]['uid'];
1626  if ($this->rootLine[0]['_MOUNT_OL'] && $this->rootLine[0]['_MP_PARAM']) {
1627  $initMParray[] = $this->rootLine[0]['_MP_PARAM'];
1628  }
1629  }
1630  $this->initMPmap_create($p, $initMParray);
1631  }
1632  }
1633  // Finding MP var for Page ID:
1634  if ($pageId) {
1635  if (is_array($this->MPmap[$pageId]) && !empty($this->MPmap[$pageId])) {
1636  return implode(',', $this->MPmap[$pageId]);
1637  }
1638  }
1639  return '';
1640  }
1641 
1650  public function initMPmap_create($id, $MP_array = [], $level = 0)
1651  {
1652  $id = (int)$id;
1653  if ($id <= 0) {
1654  return;
1655  }
1656  // First level, check id
1657  if (!$level) {
1658  // Find mount point if any:
1659  $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($id);
1660  // Overlay mode:
1661  if (is_array($mount_info) && $mount_info['overlay']) {
1662  $MP_array[] = $mount_info['MPvar'];
1663  $id = $mount_info['mount_pid'];
1664  }
1665  // Set mapping information for this level:
1666  $this->MPmap[$id] = $MP_array;
1667  // Normal mode:
1668  if (is_array($mount_info) && !$mount_info['overlay']) {
1669  $MP_array[] = $mount_info['MPvar'];
1670  $id = $mount_info['mount_pid'];
1671  }
1672  }
1673  if ($id && $level < 20) {
1674  $nextLevelAcc = [];
1675  // Select and traverse current level pages:
1676  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1677  $queryBuilder->getRestrictions()
1678  ->removeAll()
1679  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1680  $queryResult = $queryBuilder
1681  ->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol')
1682  ->from('pages')
1683  ->where(
1684  $queryBuilder->expr()->eq(
1685  'pid',
1686  $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
1687  ),
1688  $queryBuilder->expr()->neq(
1689  'doktype',
1690  $queryBuilder->createNamedParameter(PageRepository::DOKTYPE_RECYCLER, \PDO::PARAM_INT)
1691  ),
1692  $queryBuilder->expr()->neq(
1693  'doktype',
1694  $queryBuilder->createNamedParameter(PageRepository::DOKTYPE_BE_USER_SECTION, \PDO::PARAM_INT)
1695  )
1696  )->execute();
1697  while ($row = $queryResult->fetch()) {
1698  // Find mount point if any:
1699  $next_id = $row['uid'];
1700  $next_MP_array = $MP_array;
1701  $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($next_id, $row);
1702  // Overlay mode:
1703  if (is_array($mount_info) && $mount_info['overlay']) {
1704  $next_MP_array[] = $mount_info['MPvar'];
1705  $next_id = $mount_info['mount_pid'];
1706  }
1707  if (!isset($this->MPmap[$next_id])) {
1708  // Set mapping information for this level:
1709  $this->MPmap[$next_id] = $next_MP_array;
1710  // Normal mode:
1711  if (is_array($mount_info) && !$mount_info['overlay']) {
1712  $next_MP_array[] = $mount_info['MPvar'];
1713  $next_id = $mount_info['mount_pid'];
1714  }
1715  // Register recursive call
1716  // (have to do it this way since ALL of the current level should be registered BEFORE the sublevel at any time)
1717  $nextLevelAcc[] = [$next_id, $next_MP_array];
1718  }
1719  }
1720  // Call recursively, if any:
1721  foreach ($nextLevelAcc as $pSet) {
1722  $this->initMPmap_create($pSet[0], $pSet[1], $level + 1);
1723  }
1724  }
1725  }
1726 
1734  protected function addDefaultTypoScript()
1735  {
1736  // Add default TS for all code types, if not done already
1737  if (!$this->isDefaultTypoScriptAdded) {
1738  // adding default setup and constants
1739  // defaultTypoScript_setup is *very* unlikely to be empty
1740  // the count of elements in ->constants, ->config and ->templateIncludePaths have to be in sync
1741  array_unshift($this->constants, (string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants']);
1742  array_unshift($this->config, (string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup']);
1743  array_unshift($this->templateIncludePaths, '');
1744  // prepare a proper entry to hierachyInfo (used by TemplateAnalyzer in BE)
1745  $rootTemplateId = $this->hierarchyInfo[count($this->hierarchyInfo)-1]['templateID'];
1746  $defaultTemplateInfo = [
1747  'root' => '',
1748  'next' => '',
1749  'clConst' => '',
1750  'clConf' => '',
1751  'templateID' => '_defaultTypoScript_',
1752  'templateParent' => $rootTemplateId,
1753  'title' => 'SYS:TYPO3_CONF_VARS:FE:defaultTypoScript',
1754  'uid' => '_defaultTypoScript_',
1755  'pid' => '',
1756  'configLines' => substr_count((string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'], LF) + 1
1757  ];
1758  // push info to information arrays used in BE by TemplateTools (Analyzer)
1759  array_unshift($this->clearList_const, $defaultTemplateInfo['uid']);
1760  array_unshift($this->clearList_setup, $defaultTemplateInfo['uid']);
1761  array_unshift($this->hierarchyInfo, $defaultTemplateInfo);
1762  $this->isDefaultTypoScriptAdded = true;
1763  }
1764  }
1765 
1769  protected function getTypoScriptFrontendController()
1770  {
1771  return $GLOBALS['TSFE'];
1772  }
1773 
1777  protected function getTimeTracker()
1778  {
1779  return GeneralUtility::makeInstance(TimeTracker::class);
1780  }
1781 
1789  protected function getCacheEntry($identifier)
1790  {
1791  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash')->get($identifier);
1792  }
1793 
1801  protected function setCacheEntry($identifier, $data, $tag)
1802  {
1803  GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash')->set($identifier, $data, ['ident_' . $tag], 0);
1804  }
1805 }
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static isFirstPartOfStr($str, $partStr)
initMPmap_create($id, $MP_array=[], $level=0)
static callUserFunction($funcName, &$params, &$ref, $_='', $errorMode=0)
static sortedKeyList($setupArr, $acceptOnlyProperties=false)
static getFileAbsFileName($filename, $_=null, $_2=null)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
runThroughTemplates($theRootLine, $start_template_uid=0)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
includeStaticTypoScriptSources($idList, $templateID, $pid, $row)
processTemplate($row, $idList, $pid, $templateID='', $templateParent='', $includePath='')
static makeInstance($className,... $constructorArguments)
printTitle($pageTitle, $noTitle=false, $showTitleFirst=false, $pageTitleSeparator='')
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
setProcessExtensionStatics($processExtensionStatics)
static explodeUrl2Array($string, $multidim=false)
static filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
addExtensionStatics($idList, $templateID, $pid, $row)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
mergeConstantsFromIncludedTsConfigFiles($filesToInclude, $TSdataArray)
getTypoScriptSourceFileContent($filePath, $baseName)
linkData($page, $oTarget, $no_cache, $script, $overrideArray=null, $addParams='', $typeOverride='', $targetDomain='')