TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
TemplateService.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\TypoScript;
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 
84  public $backend_info = false;
85 
91  public $ext_constants_BRP = 0;
92 
96  public $ext_config_BRP = 0;
97 
101  public $ext_regLinenumbers = false;
102 
106  public $ext_regComments = false;
107 
113  public $whereClause = '';
114 
118  public $debug = false;
119 
126  public $allowedPaths = [];
127 
134 
140  public $loaded = false;
141 
145  public $setup = [];
146 
150  public $flatSetup = [];
151 
159  public $config = [];
160 
166  public $constants = [];
167 
173  protected $templateIncludePaths = [];
174 
180  public $hierarchyInfo = [];
181 
187  public $hierarchyInfoToRoot = [];
188 
194  public $nextLevel = 0;
195 
201  public $rootId;
202 
208  public $rootLine;
209 
216 
223 
229  public $rowSum;
230 
236  public $sitetitle = '';
237 
243  public $sections;
244 
251 
256  public $clearList_const = [];
257 
263  public $clearList_setup = [];
264 
268  public $parserErrors = [];
269 
273  public $setup_constants = [];
274 
280  public $fileCache = [];
281 
287  public $frames = [];
288 
294  public $MPmap = '';
295 
305  protected $extensionStaticsProcessed = false;
306 
312  protected $processExtensionStatics = false;
313 
321  protected $isDefaultTypoScriptAdded = false;
322 
331  protected $processIncludesHasBeenRun = false;
332 
338 
342  public function getProcessExtensionStatics()
343  {
345  }
346 
351  {
352  $this->processExtensionStatics = (bool)$processExtensionStatics;
353  }
354 
359  public function setVerbose($verbose)
360  {
361  $this->verbose = (bool)$verbose;
362  }
363 
371  public function init()
372  {
374 
375  if ($this->getTypoScriptFrontendController()->showHiddenRecords || $GLOBALS['SIM_ACCESS_TIME'] !== $GLOBALS['ACCESS_TIME']) {
376  // Set the simulation flag, if simulation is detected!
377  $this->simulationHiddenOrTime = 1;
378  }
379 
380  // Sets the paths from where TypoScript resources are allowed to be used:
381  $this->allowedPaths = [
382  $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'],
383  // fileadmin/ path
384  'uploads/',
385  'typo3temp/',
386  TYPO3_mainDir . 'ext/',
387  TYPO3_mainDir . 'sysext/',
388  'typo3conf/ext/'
389  ];
390  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['addAllowedPaths']) {
391  $pathArr = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['addAllowedPaths'], true);
392  foreach ($pathArr as $p) {
393  // 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.
394  $this->allowedPaths[] = $p;
395  }
396  }
397  }
398 
403  {
404  // $this->whereClause is used only to select templates from sys_template.
405  // $GLOBALS['SIM_ACCESS_TIME'] is used so that we're able to simulate a later time as a test...
406  $this->whereClause = 'AND deleted=0 ';
407  if (!$this->getTypoScriptFrontendController()->showHiddenRecords) {
408  $this->whereClause .= 'AND hidden=0 ';
409  }
410  $this->whereClause .= 'AND (starttime<=' . $GLOBALS['SIM_ACCESS_TIME'] . ') AND (endtime=0 OR endtime>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
411 
412  // set up the query builder restrictions
413  $this->queryBuilderRestrictions = GeneralUtility::makeInstance(DefaultRestrictionContainer::class);
414 
415  if ($this->getTypoScriptFrontendController()->showHiddenRecords) {
416  $this->queryBuilderRestrictions
417  ->removeByType(HiddenRestriction::class);
418  }
419  }
420 
437  public function getCurrentPageData()
438  {
439  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pagesection')->get((int)$this->getTypoScriptFrontendController()->id . '_' . GeneralUtility::md5int($this->getTypoScriptFrontendController()->MP));
440  }
441 
448  public function matching($cc)
449  {
450  if (is_array($cc['all'])) {
452  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
453  $matchObj->setRootline((array)$cc['rootLine']);
454  $sectionsMatch = [];
455  foreach ($cc['all'] as $key => $pre) {
456  if ($matchObj->match($pre)) {
457  $sectionsMatch[$key] = $pre;
458  }
459  }
460  $cc['match'] = $sectionsMatch;
461  }
462  return $cc;
463  }
464 
474  public function start($theRootLine)
475  {
476  if (is_array($theRootLine)) {
477  $setupData = '';
478  $cacheIdentifier = '';
479  // Flag that indicates that the existing data in cache_pagesection
480  // could be used (this is the case if $TSFE->all is set, and the
481  // rowSum still matches). Based on this we decide if cache_pagesection
482  // needs to be updated...
483  $isCached = false;
484  $this->runThroughTemplates($theRootLine);
485  if ($this->getTypoScriptFrontendController()->all) {
486  $cc = $this->getTypoScriptFrontendController()->all;
487  // The two rowSums must NOT be different from each other - which they will be if start/endtime or hidden has changed!
488  if (serialize($this->rowSum) !== serialize($cc['rowSum'])) {
489  unset($cc);
490  } else {
491  // If $TSFE->all contains valid data, we don't need to update cache_pagesection (because this data was fetched from there already)
492  if (serialize($this->rootLine) === serialize($cc['rootLine'])) {
493  $isCached = true;
494  }
495  // 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)...
496  unset($cc['rootLine']);
497  }
498  }
499  // This is about getting the hash string which is used to fetch the cached TypoScript template.
500  // If there was some cached currentPageData ($cc) then that's good (it gives us the hash).
501  if (isset($cc) && is_array($cc)) {
502  // If currentPageData was actually there, we match the result (if this wasn't done already in $TSFE->getFromCache()...)
503  if (!$cc['match']) {
504  // @todo check if this can ever be the case - otherwise remove
505  $cc = $this->matching($cc);
506  ksort($cc);
507  }
508  $cacheIdentifier = md5(serialize($cc));
509  } else {
510  // 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.
511  $rowSumHash = md5('ROWSUM:' . serialize($this->rowSum));
512  $result = $this->getCacheEntry($rowSumHash);
513  if (is_array($result)) {
514  $cc = [];
515  $cc['all'] = $result;
516  $cc['rowSum'] = $this->rowSum;
517  $cc = $this->matching($cc);
518  ksort($cc);
519  $cacheIdentifier = md5(serialize($cc));
520  }
521  }
522  if ($cacheIdentifier) {
523  // Get TypoScript setup array
524  $setupData = $this->getCacheEntry($cacheIdentifier);
525  }
526  if (is_array($setupData) && !$this->forceTemplateParsing) {
527  // If TypoScript setup structure was cached we unserialize it here:
528  $this->setup = $setupData;
529  if ($this->tt_track) {
530  $this->getTimeTracker()->setTSlogMessage('Using cached TS template data');
531  }
532  } else {
533  if ($this->tt_track) {
534  $this->getTimeTracker()->setTSlogMessage('Not using any cached TS data');
535  }
536 
537  // Make configuration
538  $this->generateConfig();
539  // This stores the template hash thing
540  $cc = [];
541  // All sections in the template at this point is found
542  $cc['all'] = $this->sections;
543  // The line of templates is collected
544  $cc['rowSum'] = $this->rowSum;
545  $cc = $this->matching($cc);
546  ksort($cc);
547  $cacheIdentifier = md5(serialize($cc));
548  // This stores the data.
549  $this->setCacheEntry($cacheIdentifier, $this->setup, 'TS_TEMPLATE');
550  if ($this->tt_track) {
551  $this->getTimeTracker()->setTSlogMessage('TS template size, serialized: ' . strlen(serialize($this->setup)) . ' bytes');
552  }
553  $rowSumHash = md5('ROWSUM:' . serialize($this->rowSum));
554  $this->setCacheEntry($rowSumHash, $cc['all'], 'TMPL_CONDITIONS_ALL');
555  }
556  // Add rootLine
557  $cc['rootLine'] = $this->rootLine;
558  ksort($cc);
559  // Make global and save
560  $this->getTypoScriptFrontendController()->all = $cc;
561  // Matching must be executed for every request, so this must never be part of the pagesection cache!
562  unset($cc['match']);
563  if (!$isCached && !$this->simulationHiddenOrTime && !$this->getTypoScriptFrontendController()->no_cache) {
564  // Only save the data if we're not simulating by hidden/starttime/endtime
565  $mpvarHash = GeneralUtility::md5int($this->getTypoScriptFrontendController()->MP);
567  $pageSectionCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pagesection');
568  $pageSectionCache->set((int)$this->getTypoScriptFrontendController()->id . '_' . $mpvarHash, $cc, [
569  'pageId_' . (int)$this->getTypoScriptFrontendController()->id,
570  'mpvarHash_' . $mpvarHash
571  ]);
572  }
573  // If everything OK.
574  if ($this->rootId && $this->rootLine && $this->setup) {
575  $this->loaded = true;
576  }
577  }
578  }
579 
580  /*******************************************************************
581  *
582  * Fetching TypoScript code text for the Template Hierarchy
583  *
584  *******************************************************************/
595  public function runThroughTemplates($theRootLine, $start_template_uid = 0)
596  {
597  $this->constants = [];
598  $this->config = [];
599  $this->rowSum = [];
600  $this->hierarchyInfoToRoot = [];
601  $this->absoluteRootLine = $theRootLine;
602  $this->isDefaultTypoScriptAdded = false;
603 
604  reset($this->absoluteRootLine);
605  $c = count($this->absoluteRootLine);
606  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template');
607  for ($a = 0; $a < $c; $a++) {
608  // If some template loaded before has set a template-id for the next level, then load this template first!
609  if ($this->nextLevel) {
610  $queryBuilder->setRestrictions($this->queryBuilderRestrictions);
611  $queryResult = $queryBuilder
612  ->select('*')
613  ->from('sys_template')
614  ->where(
615  $queryBuilder->expr()->eq(
616  'uid',
617  $queryBuilder->createNamedParameter($this->nextLevel, \PDO::PARAM_INT)
618  )
619  )
620  ->execute();
621  $this->nextLevel = 0;
622  if ($row = $queryResult->fetch()) {
623  $this->versionOL($row);
624  if (is_array($row)) {
625  $this->processTemplate($row, 'sys_' . $row['uid'], $this->absoluteRootLine[$a]['uid'], 'sys_' . $row['uid']);
626  $this->outermostRootlineIndexWithTemplate = $a;
627  }
628  }
629  }
630 
631  $where = [
632  $queryBuilder->expr()->eq(
633  'pid',
634  $queryBuilder->createNamedParameter($this->absoluteRootLine[$a]['uid'], \PDO::PARAM_INT)
635  )
636  ];
637  // If first loop AND there is set an alternative template uid, use that
638  if ($a === $c - 1 && $start_template_uid) {
639  $where[] = $queryBuilder->expr()->eq(
640  'uid',
641  $queryBuilder->createNamedParameter($start_template_uid, \PDO::PARAM_INT)
642  );
643  }
644  $queryBuilder->setRestrictions($this->queryBuilderRestrictions);
645  $queryResult = $queryBuilder
646  ->select('*')
647  ->from('sys_template')
648  ->where(...$where)
649  ->orderBy('root', 'DESC')
650  ->addOrderBy('sorting')
651  ->setMaxResults(1)
652  ->execute();
653  if ($row = $queryResult->fetch()) {
654  $this->versionOL($row);
655  if (is_array($row)) {
656  $this->processTemplate($row, 'sys_' . $row['uid'], $this->absoluteRootLine[$a]['uid'], 'sys_' . $row['uid']);
657  $this->outermostRootlineIndexWithTemplate = $a;
658  }
659  }
660  $this->rootLine[] = $this->absoluteRootLine[$a];
661  }
662 
663  // Process extension static files if not done yet, but explicitly requested
664  if (!$this->extensionStaticsProcessed && $this->processExtensionStatics) {
665  $this->addExtensionStatics('sys_0', 'sys_0', 0, []);
666  }
667 
668  // Add the global default TypoScript from the TYPO3_CONF_VARS
669  $this->addDefaultTypoScript();
670 
671  $this->processIncludes();
672  }
673 
687  public function processTemplate($row, $idList, $pid, $templateID = '', $templateParent = '', $includePath = '')
688  {
689  // Adding basic template record information to rowSum array
690  $this->rowSum[] = [$row['uid'], $row['title'], $row['tstamp']];
691  // Processing "Clear"-flags
692  $clConst = 0;
693  $clConf = 0;
694  if ($row['clear']) {
695  $clConst = $row['clear'] & 1;
696  $clConf = $row['clear'] & 2;
697  if ($clConst) {
698  // Keep amount of items to stay in sync with $this->templateIncludePaths so processIncludes() does not break
699  foreach ($this->constants as &$constantConfiguration) {
700  $constantConfiguration = '';
701  }
702  unset($constantConfiguration);
703  $this->clearList_const = [];
704  }
705  if ($clConf) {
706  // Keep amount of items to stay in sync with $this->templateIncludePaths so processIncludes() does not break
707  foreach ($this->config as &$configConfiguration) {
708  $configConfiguration = '';
709  }
710  unset($configConfiguration);
711  $this->hierarchyInfoToRoot = [];
712  $this->clearList_setup = [];
713  }
714  }
715  // Include static records (static_template) or files (from extensions) (#1/2)
716  // NORMAL inclusion, The EXACT same code is found below the basedOn inclusion!!!
717  if (!$row['includeStaticAfterBasedOn']) {
718  $this->includeStaticTypoScriptSources($idList, $templateID, $pid, $row);
719  }
720  // Include "Based On" sys_templates:
721  // 'basedOn' is a list of templates to include
722  if (trim($row['basedOn'])) {
723  // Normal Operation, which is to include the "based-on" sys_templates,
724  // if they are not already included, and maintaining the sorting of the templates
725  $basedOnIds = GeneralUtility::intExplode(',', $row['basedOn'], true);
726  // skip template if it's already included
727  foreach ($basedOnIds as $key => $basedOnId) {
728  if (GeneralUtility::inList($idList, 'sys_' . $basedOnId)) {
729  unset($basedOnIds[$key]);
730  }
731  }
732  if (!empty($basedOnIds)) {
733  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_template');
734  $queryBuilder->setRestrictions($this->queryBuilderRestrictions);
735  $queryResult = $queryBuilder
736  ->select('*')
737  ->from('sys_template')
738  ->where(
739  $queryBuilder->expr()->in(
740  'uid',
741  $queryBuilder->createNamedParameter($basedOnIds, Connection::PARAM_INT_ARRAY)
742  )
743  )
744  ->execute();
745  // make it an associative array with the UID as key
746  $subTemplates = [];
747  while ($rowItem = $queryResult->fetch()) {
748  $subTemplates[(int)$rowItem['uid']] = $rowItem;
749  }
750  // Traversing list again to ensure the sorting of the templates
751  foreach ($basedOnIds as $id) {
752  if (is_array($subTemplates[$id])) {
753  $this->versionOL($subTemplates[$id]);
754  $this->processTemplate($subTemplates[$id], $idList . ',sys_' . $id, $pid, 'sys_' . $id, $templateID);
755  }
756  }
757  }
758  }
759  // Include static records (static_template) or files (from extensions) (#2/2)
760  if ($row['includeStaticAfterBasedOn']) {
761  $this->includeStaticTypoScriptSources($idList, $templateID, $pid, $row);
762  }
763  // Creating hierarchy information; Used by backend analysis tools
764  $this->hierarchyInfo[] = ($this->hierarchyInfoToRoot[] = [
765  'root' => trim($row['root']),
766  'next' => $row['nextLevel'],
767  'clConst' => $clConst,
768  'clConf' => $clConf,
769  'templateID' => $templateID,
770  'templateParent' => $templateParent,
771  'title' => $row['title'],
772  'uid' => $row['uid'],
773  'pid' => $row['pid'],
774  'configLines' => substr_count($row['config'], LF) + 1
775  ]);
776  // Adding the content of the fields constants (Constants) and config (Setup)
777  $this->constants[] = $row['constants'];
778  $this->config[] = $row['config'];
779  $this->templateIncludePaths[] = $includePath;
780  // For backend analysis (Template Analyser) provide the order of added constants/config template IDs
781  $this->clearList_const[] = $templateID;
782  $this->clearList_setup[] = $templateID;
783  if (trim($row['sitetitle'])) {
784  $this->sitetitle = $row['sitetitle'];
785  }
786  // If the template record is a Rootlevel record, set the flag and clear the template rootLine (so it starts over from this point)
787  if (trim($row['root'])) {
788  $this->rootId = $pid;
789  $this->rootLine = [];
790  }
791  // If a template is set to be active on the next level set this internal value to point to this UID. (See runThroughTemplates())
792  if ($row['nextLevel']) {
793  $this->nextLevel = $row['nextLevel'];
794  } else {
795  $this->nextLevel = 0;
796  }
797  }
798 
810  public function updateRootlineData($fullRootLine)
811  {
812  if (!is_array($this->rootLine) || empty($this->rootLine)) {
813  return;
814  }
815 
816  $fullRootLineByUid = [];
817  foreach ($fullRootLine as $rootLineData) {
818  $fullRootLineByUid[$rootLineData['uid']] = $rootLineData;
819  }
820 
821  foreach ($this->rootLine as $level => $dataArray) {
822  $currentUid = $dataArray['uid'];
823 
824  if (!array_key_exists($currentUid, $fullRootLineByUid)) {
825  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);
826  }
827 
828  $this->rootLine[$level] = $fullRootLineByUid[$currentUid];
829  }
830  }
831 
842  public function includeStaticTypoScriptSources($idList, $templateID, $pid, $row)
843  {
844  // Static Template Records (static_template): include_static is a list of static templates to include
845  // Call function for link rendering:
846  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources'])) {
847  $_params = [
848  'idList' => &$idList,
849  'templateId' => &$templateID,
850  'pid' => &$pid,
851  'row' => &$row
852  ];
853  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources'] as $_funcRef) {
854  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
855  }
856  }
857  // If "Include before all static templates if root-flag is set" is set:
858  if ($row['static_file_mode'] == 3 && strpos($templateID, 'sys_') === 0 && $row['root']) {
859  $this->addExtensionStatics($idList, $templateID, $pid, $row);
860  }
861  // Static Template Files (Text files from extensions): include_static_file is a list of static files to include (from extensions)
862  if (trim($row['include_static_file'])) {
863  $include_static_fileArr = GeneralUtility::trimExplode(',', $row['include_static_file'], true);
864  // Traversing list
865  foreach ($include_static_fileArr as $ISF_file) {
866  if (strpos($ISF_file, 'EXT:') === 0) {
867  list($ISF_extKey, $ISF_localPath) = explode('/', substr($ISF_file, 4), 2);
868  if ((string)$ISF_extKey !== '' && ExtensionManagementUtility::isLoaded($ISF_extKey) && (string)$ISF_localPath !== '') {
869  $ISF_localPath = rtrim($ISF_localPath, '/') . '/';
870  $ISF_filePath = ExtensionManagementUtility::extPath($ISF_extKey) . $ISF_localPath;
871  if (@is_dir($ISF_filePath)) {
872  $mExtKey = str_replace('_', '', $ISF_extKey . '/' . $ISF_localPath);
873  $subrow = [
874  'constants' => $this->getTypoScriptSourceFileContent($ISF_filePath, 'constants'),
875  'config' => $this->getTypoScriptSourceFileContent($ISF_filePath, 'setup'),
876  'include_static' => @file_exists(($ISF_filePath . 'include_static.txt')) ? implode(',', array_unique(GeneralUtility::intExplode(',', file_get_contents($ISF_filePath . 'include_static.txt')))) : '',
877  'include_static_file' => @file_exists(($ISF_filePath . 'include_static_file.txt')) ? implode(',', array_unique(explode(',', file_get_contents($ISF_filePath . 'include_static_file.txt')))) : '',
878  'title' => $ISF_file,
879  'uid' => $mExtKey
880  ];
881  $subrow = $this->prependStaticExtra($subrow);
882  $this->processTemplate($subrow, $idList . ',ext_' . $mExtKey, $pid, 'ext_' . $mExtKey, $templateID, $ISF_filePath);
883  }
884  }
885  }
886  }
887  }
888  // If "Default (include before if root flag is set)" is set OR
889  // "Always include before this template record" AND root-flag are set
890  if ($row['static_file_mode'] == 1 || $row['static_file_mode'] == 0 && substr($templateID, 0, 4) == 'sys_' && $row['root']) {
891  $this->addExtensionStatics($idList, $templateID, $pid, $row);
892  }
893  // Include Static Template Records after all other TypoScript has been included.
894  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSourcesAtEnd'])) {
895  $_params = [
896  'idList' => &$idList,
897  'templateId' => &$templateID,
898  'pid' => &$pid,
899  'row' => &$row
900  ];
901  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSourcesAtEnd'] as $_funcRef) {
902  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
903  }
904  }
905  }
906 
915  protected function getTypoScriptSourceFileContent($filePath, $baseName)
916  {
917  $extensions = ['.ts', '.txt'];
918  foreach ($extensions as $extension) {
919  $fileName = $filePath . $baseName . $extension;
920  if (@file_exists($fileName)) {
921  return file_get_contents($fileName);
922  }
923  }
924  return '';
925  }
926 
938  public function addExtensionStatics($idList, $templateID, $pid, $row)
939  {
940  $this->extensionStaticsProcessed = true;
941 
942  // @todo Change to use new API
943  foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extKey => $files) {
944  if ((is_array($files) || $files instanceof \ArrayAccess) && ($files['ext_typoscript_constants.txt'] || $files['ext_typoscript_setup.txt'])) {
945  $mExtKey = str_replace('_', '', $extKey);
946  $subrow = [
947  'constants' => $files['ext_typoscript_constants.txt'] ? @file_get_contents($files['ext_typoscript_constants.txt']) : '',
948  'config' => $files['ext_typoscript_setup.txt'] ? @file_get_contents($files['ext_typoscript_setup.txt']) : '',
949  'title' => $extKey,
950  'uid' => $mExtKey
951  ];
952  $subrow = $this->prependStaticExtra($subrow);
953  $extPath = ExtensionManagementUtility::extPath($extKey);
954  $this->processTemplate($subrow, $idList . ',ext_' . $mExtKey, $pid, 'ext_' . $mExtKey, $templateID, $extPath);
955  }
956  }
957  }
958 
969  public function prependStaticExtra($subrow)
970  {
971  // the identifier can be "43" if coming from "static template" extension or a path like "cssstyledcontent/static/"
972  $identifier = $subrow['uid'];
973  $subrow['config'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.'][$identifier];
974  $subrow['constants'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.'][$identifier];
975  // 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
976  if (in_array($identifier, $GLOBALS['TYPO3_CONF_VARS']['FE']['contentRenderingTemplates'], true)) {
977  $subrow['config'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['defaultContentRendering'];
978  $subrow['constants'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['defaultContentRendering'];
979  }
980  return $subrow;
981  }
982 
990  public function versionOL(&$row)
991  {
992  // Distinguish frontend and backend call:
993  // To do the fronted call a full frontend is required, just checking for
994  // TYPO3_MODE === 'FE' is not enough. This could otherwise lead to fatals in
995  // eId scripts that run in frontend scope, but do not have a full blown frontend.
996  if (is_object($this->getTypoScriptFrontendController()) && property_exists($this->getTypoScriptFrontendController(), 'sys_page') && method_exists($this->getTypoScriptFrontendController()->sys_page, 'versionOL')) {
997  // Frontend
998  $this->getTypoScriptFrontendController()->sys_page->versionOL('sys_template', $row);
999  } else {
1000  // Backend
1001  BackendUtility::workspaceOL('sys_template', $row);
1002  }
1003  }
1004 
1005  /*******************************************************************
1006  *
1007  * Parsing TypoScript code text from Template Records into PHP array
1008  *
1009  *******************************************************************/
1017  public function generateConfig()
1018  {
1019  // Add default TS for all code types
1020  $this->addDefaultTypoScript();
1021 
1022  // Parse the TypoScript code text for include-instructions!
1023  $this->processIncludes();
1024  // These vars are also set lateron...
1025  $this->setup['sitetitle'] = $this->sitetitle;
1026  // ****************************
1027  // Parse TypoScript Constants
1028  // ****************************
1029  // Initialize parser and match-condition classes:
1031  $constants = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1032  $constants->breakPointLN = (int)$this->ext_constants_BRP;
1033  $constants->setup = $this->mergeConstantsFromPageTSconfig([]);
1035  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
1036  $matchObj->setSimulateMatchConditions($this->matchAlternative);
1037  $matchObj->setSimulateMatchResult((bool)$this->matchAll);
1038  // Traverse constants text fields and parse them
1039  foreach ($this->constants as $str) {
1040  $constants->parse($str, $matchObj);
1041  }
1042  // Read out parse errors if any
1043  $this->parserErrors['constants'] = $constants->errors;
1044  // 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)
1045  $this->flatSetup = [];
1046  $this->flattenSetup($constants->setup, '');
1047  // ***********************************************
1048  // Parse TypoScript Setup (here called "config")
1049  // ***********************************************
1050  // Initialize parser and match-condition classes:
1052  $config = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1053  $config->breakPointLN = (int)$this->ext_config_BRP;
1054  $config->regLinenumbers = $this->ext_regLinenumbers;
1055  $config->regComments = $this->ext_regComments;
1056  $config->setup = $this->setup;
1057  // Transfer information about conditions found in "Constants" and which of them returned TRUE.
1058  $config->sections = $constants->sections;
1059  $config->sectionsMatch = $constants->sectionsMatch;
1060  // Traverse setup text fields and concatenate them into one, single string separated by a [GLOBAL] condition
1061  $all = '';
1062  foreach ($this->config as $str) {
1063  $all .= '
1064 [GLOBAL]
1065 ' . $str;
1066  }
1067  // Substitute constants in the Setup code:
1068  if ($this->tt_track) {
1069  $this->getTimeTracker()->push('Substitute Constants (' . count($this->flatSetup) . ')');
1070  }
1071  $all = $this->substituteConstants($all);
1072  if ($this->tt_track) {
1073  $this->getTimeTracker()->pull();
1074  }
1075 
1076  // Searching for possible unsubstituted constants left (only for information)
1077  if ($this->verbose) {
1078  if (preg_match_all('/\\{\\$.[^}]*\\}/', $all, $constantList) > 0) {
1079  if ($this->tt_track) {
1080  $this->getTimeTracker()->setTSlogMessage(implode(', ', $constantList[0]) . ': Constants may remain un-substituted!!', 2);
1081  }
1082  }
1083  }
1084 
1085  // Logging the textual size of the TypoScript Setup field text with all constants substituted:
1086  if ($this->tt_track) {
1087  $this->getTimeTracker()->setTSlogMessage('TypoScript template size as textfile: ' . strlen($all) . ' bytes');
1088  }
1089  // Finally parse the Setup field TypoScript code (where constants are now substituted)
1090  $config->parse($all, $matchObj);
1091  // Read out parse errors if any
1092  $this->parserErrors['config'] = $config->errors;
1093  // Transfer the TypoScript array from the parser object to the internal $this->setup array:
1094  $this->setup = $config->setup;
1095  if ($this->backend_info) {
1096  // Used for backend purposes only
1097  $this->setup_constants = $constants->setup;
1098  }
1099  // ****************************************************************
1100  // Final processing of the $this->setup TypoScript Template array
1101  // Basically: This is unsetting/setting of certain reserved keys.
1102  // ****************************************************************
1103  // These vars are allready 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!
1104  unset($this->setup['sitetitle']);
1105  unset($this->setup['sitetitle.']);
1106  $this->setup['sitetitle'] = $this->sitetitle;
1107  // Unsetting some vars...
1108  unset($this->setup['types.']);
1109  unset($this->setup['types']);
1110  if (is_array($this->setup)) {
1111  foreach ($this->setup as $key => $value) {
1112  if ($value == 'PAGE') {
1113  // Set the typeNum of the current page object:
1114  if (isset($this->setup[$key . '.']['typeNum'])) {
1115  $typeNum = $this->setup[$key . '.']['typeNum'];
1116  $this->setup['types.'][$typeNum] = $key;
1117  } elseif (!isset($this->setup['types.'][0]) || !$this->setup['types.'][0]) {
1118  $this->setup['types.'][0] = $key;
1119  }
1120  }
1121  }
1122  }
1123  unset($this->setup['temp.']);
1124  unset($constants);
1125  // Storing the conditions found/matched information:
1126  $this->sections = $config->sections;
1127  $this->sectionsMatch = $config->sectionsMatch;
1128  }
1129 
1138  public function processIncludes()
1139  {
1140  if ($this->processIncludesHasBeenRun) {
1141  return;
1142  }
1143 
1144  $paths = $this->templateIncludePaths;
1145  $files = [];
1146  foreach ($this->constants as &$value) {
1147  $includeData = Parser\TypoScriptParser::checkIncludeLines($value, 1, true, array_shift($paths));
1148  $files = array_merge($files, $includeData['files']);
1149  $value = $includeData['typoscript'];
1150  }
1151  unset($value);
1152  $paths = $this->templateIncludePaths;
1153  foreach ($this->config as &$value) {
1154  $includeData = Parser\TypoScriptParser::checkIncludeLines($value, 1, true, array_shift($paths));
1155  $files = array_merge($files, $includeData['files']);
1156  $value = $includeData['typoscript'];
1157  }
1158  unset($value);
1159 
1160  if (!empty($files)) {
1161  $files = array_unique($files);
1162  foreach ($files as $file) {
1163  $this->rowSum[] = [$file, filemtime($file)];
1164  }
1165  }
1166 
1167  $this->processIncludesHasBeenRun = true;
1168  }
1169 
1177  public function mergeConstantsFromPageTSconfig($constArray)
1178  {
1179  $TSdataArray = [];
1180  // Setting default configuration:
1181  $TSdataArray[] = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'];
1182  for ($a = 0; $a <= $this->outermostRootlineIndexWithTemplate; $a++) {
1183  if (trim($this->absoluteRootLine[$a]['tsconfig_includes'])) {
1184  $includeTsConfigFileList = GeneralUtility::trimExplode(',',
1185  $this->absoluteRootLine[$a]['tsconfig_includes'], true);
1186 
1187  $TSdataArray = $this->mergeConstantsFromIncludedTsConfigFiles($includeTsConfigFileList, $TSdataArray);
1188  }
1189  $TSdataArray[] = $this->absoluteRootLine[$a]['TSconfig'];
1190  }
1191  // Parsing the user TS (or getting from cache)
1192  $TSdataArray = Parser\TypoScriptParser::checkIncludeLines_array($TSdataArray);
1193  $userTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
1195  $parseObj = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1196  $parseObj->parse($userTS);
1197  if (is_array($parseObj->setup['TSFE.']['constants.'])) {
1198  ArrayUtility::mergeRecursiveWithOverrule($constArray, $parseObj->setup['TSFE.']['constants.']);
1199  }
1200 
1201  return $constArray;
1202  }
1203 
1211  protected function mergeConstantsFromIncludedTsConfigFiles($filesToInclude, $TSdataArray)
1212  {
1213  foreach ($filesToInclude as $key => $file) {
1214  if (strpos($file, 'EXT:') !== 0) {
1215  continue;
1216  }
1217 
1218  list($extensionKey, $filePath) = explode('/', substr($file, 4), 2);
1219 
1220  if ((string)$extensionKey === '' || !ExtensionManagementUtility::isLoaded($extensionKey)) {
1221  continue;
1222  }
1223  if ((string)$filePath == '') {
1224  continue;
1225  }
1226 
1227  $tsConfigFile = ExtensionManagementUtility::extPath($extensionKey) . $filePath;
1228  if (file_exists($tsConfigFile)) {
1229  $TSdataArray[] = file_get_contents($tsConfigFile);
1230  }
1231  }
1232 
1233  return $TSdataArray;
1234  }
1235 
1244  public function flattenSetup($setupArray, $prefix)
1245  {
1246  if (is_array($setupArray)) {
1247  foreach ($setupArray as $key => $val) {
1248  if ($prefix || strpos($key, 'TSConstantEditor') !== 0) {
1249  // We don't want 'TSConstantEditor' in the flattened setup on the first level (190201)
1250  if (is_array($val)) {
1251  $this->flattenSetup($val, $prefix . $key);
1252  } else {
1253  $this->flatSetup[$prefix . $key] = $val;
1254  }
1255  }
1256  }
1257  }
1258  }
1259 
1267  public function substituteConstants($all)
1268  {
1269  if ($this->tt_track) {
1270  $this->getTimeTracker()->setTSlogMessage('Constants to substitute: ' . count($this->flatSetup));
1271  }
1272  $noChange = false;
1273  // Recursive substitution of constants (up to 10 nested levels)
1274  for ($i = 0; $i < 10 && !$noChange; $i++) {
1275  $old_all = $all;
1276  $all = preg_replace_callback('/\\{\\$(.[^}]*)\\}/', [$this, 'substituteConstantsCallBack'], $all);
1277  if ($old_all == $all) {
1278  $noChange = true;
1279  }
1280  }
1281  return $all;
1282  }
1283 
1291  public function substituteConstantsCallBack($matches)
1292  {
1293  // Replace {$CONST} if found in $this->flatSetup, else leave unchanged
1294  return isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? $this->flatSetup[$matches[1]] : $matches[0];
1295  }
1296 
1297  /*******************************************************************
1298  *
1299  * Various API functions, used from elsewhere in the frontend classes
1300  *
1301  *******************************************************************/
1312  public function splitConfArray($conf, $splitCount)
1313  {
1314  // Initialize variables:
1315  $splitCount = (int)$splitCount;
1316  $conf2 = [];
1317  if ($splitCount && is_array($conf)) {
1318  // Initialize output to carry at least the keys:
1319  for ($aKey = 0; $aKey < $splitCount; $aKey++) {
1320  $conf2[$aKey] = [];
1321  }
1322  // Recursive processing of array keys:
1323  foreach ($conf as $cKey => $val) {
1324  if (is_array($val)) {
1325  $tempConf = $this->splitConfArray($val, $splitCount);
1326  foreach ($tempConf as $aKey => $val2) {
1327  $conf2[$aKey][$cKey] = $val2;
1328  }
1329  } else {
1330  // Splitting of all values on this level of the TypoScript object tree:
1331  if ($cKey === 'noTrimWrap' || (!strstr($val, '|*|') && !strstr($val, '||'))) {
1332  for ($aKey = 0; $aKey < $splitCount; $aKey++) {
1333  $conf2[$aKey][$cKey] = $val;
1334  }
1335  } else {
1336  $main = explode('|*|', $val);
1337  $lastC = 0;
1338  $middleC = 0;
1339  $firstC = 0;
1340  if ($main[0]) {
1341  $first = explode('||', $main[0]);
1342  $firstC = count($first);
1343  }
1344  $middle = [];
1345  if ($main[1]) {
1346  $middle = explode('||', $main[1]);
1347  $middleC = count($middle);
1348  }
1349  $last = [];
1350  $value = '';
1351  if ($main[2]) {
1352  $last = explode('||', $main[2]);
1353  $lastC = count($last);
1354  $value = $last[0];
1355  }
1356  for ($aKey = 0; $aKey < $splitCount; $aKey++) {
1357  if ($firstC && isset($first[$aKey])) {
1358  $value = $first[$aKey];
1359  } elseif ($middleC) {
1360  $value = $middle[($aKey - $firstC) % $middleC];
1361  }
1362  if ($lastC && $lastC >= $splitCount - $aKey) {
1363  $value = $last[$lastC - ($splitCount - $aKey)];
1364  }
1365  $conf2[$aKey][$cKey] = trim($value);
1366  }
1367  }
1368  }
1369  }
1370  }
1371  return $conf2;
1372  }
1373 
1380  public function getFileName($fileFromSetup)
1381  {
1382  $file = trim($fileFromSetup);
1383  if (!$file) {
1384  return null;
1385  } elseif (strpos($file, '../') !== false) {
1386  if ($this->tt_track) {
1387  $this->getTimeTracker()->setTSlogMessage('File path "' . $file . '" contained illegal string "../"!', 3);
1388  }
1389  return null;
1390  }
1391  // Cache
1392  $hash = md5($file);
1393  if (isset($this->fileCache[$hash])) {
1394  return $this->fileCache[$hash];
1395  }
1396 
1397  // if this is an URL, it can be returned directly
1398  $urlScheme = parse_url($file, PHP_URL_SCHEME);
1399  if ($urlScheme === 'https' || $urlScheme === 'http' || is_file(PATH_site . $file)) {
1400  return $file;
1401  }
1402 
1403  // this call also resolves EXT:myext/ files
1404  $file = GeneralUtility::getFileAbsFileName($file);
1405  if (!$file) {
1406  if ($this->tt_track) {
1407  $this->getTimeTracker()->setTSlogMessage('File "' . $fileFromSetup . '" was not found!', 3);
1408  }
1409  return null;
1410  }
1411 
1412  $file = PathUtility::stripPathSitePrefix($file);
1413 
1414  // Check if the found file is in the allowed paths
1415  foreach ($this->allowedPaths as $val) {
1416  if (GeneralUtility::isFirstPartOfStr($file, $val)) {
1417  $this->fileCache[$hash] = $file;
1418  return $file;
1419  }
1420  }
1421 
1422  if ($this->tt_track) {
1423  $this->getTimeTracker()->setTSlogMessage('"' . $file . '" was not located in the allowed paths: (' . implode(',', $this->allowedPaths) . ')', 3);
1424  }
1425  return null;
1426  }
1427 
1438  public function printTitle($pageTitle, $noTitle = false, $showTitleFirst = false, $pageTitleSeparator = '')
1439  {
1440  $siteTitle = trim($this->setup['sitetitle']);
1441  $pageTitle = $noTitle ? '' : $pageTitle;
1442  if ($showTitleFirst) {
1443  $temp = $siteTitle;
1444  $siteTitle = $pageTitle;
1445  $pageTitle = $temp;
1446  }
1447  // only show a separator if there are both site title and page title
1448  if ($pageTitle === '' || $siteTitle === '') {
1449  $pageTitleSeparator = '';
1450  // use the default separator if non given
1451  } elseif (empty($pageTitleSeparator)) {
1452  $pageTitleSeparator = ': ';
1453  }
1454  return $siteTitle . $pageTitleSeparator . $pageTitle;
1455  }
1456 
1465  public function fileContent($fileName)
1466  {
1468  $fileName = $this->getFileName($fileName);
1469  if ($fileName) {
1470  return GeneralUtility::getUrl($fileName);
1471  }
1472  return null;
1473  }
1474 
1483  public function removeQueryString($url)
1484  {
1486  if (substr($url, -1) == '?') {
1487  return substr($url, 0, -1);
1488  } else {
1489  return $url;
1490  }
1491  }
1492 
1503  public static function sortedKeyList($setupArr, $acceptOnlyProperties = false)
1504  {
1506  return ArrayUtility::filterAndSortByNumericKeys($setupArr, $acceptOnlyProperties);
1507  }
1508 
1515  public function getRootlineLevel($list)
1516  {
1517  $idx = 0;
1518  foreach ($this->rootLine as $page) {
1519  if (GeneralUtility::inList($list, $page['uid'])) {
1520  return $idx;
1521  }
1522  $idx++;
1523  }
1524  return false;
1525  }
1526 
1527  /*******************************************************************
1528  *
1529  * Functions for creating links
1530  *
1531  *******************************************************************/
1549  public function linkData($page, $oTarget, $no_cache, $script, $overrideArray = null, $addParams = '', $typeOverride = '', $targetDomain = '')
1550  {
1551  $LD = [];
1552  // Overriding some fields in the page record and still preserves the values by adding them as parameters. Little strange function.
1553  if (is_array($overrideArray)) {
1554  foreach ($overrideArray as $theKey => $theNewVal) {
1555  $addParams .= '&real_' . $theKey . '=' . rawurlencode($page[$theKey]);
1556  $page[$theKey] = $theNewVal;
1557  }
1558  }
1559  // Adding Mount Points, "&MP=", parameter for the current page if any is set:
1560  if (!strstr($addParams, '&MP=')) {
1561  // Looking for hardcoded defaults:
1562  if (trim($this->getTypoScriptFrontendController()->MP_defaults[$page['uid']])) {
1563  $addParams .= '&MP=' . rawurlencode(trim($this->getTypoScriptFrontendController()->MP_defaults[$page['uid']]));
1564  } elseif ($this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints']) {
1565  // Else look in automatically created map:
1566  $m = $this->getFromMPmap($page['uid']);
1567  if ($m) {
1568  $addParams .= '&MP=' . rawurlencode($m);
1569  }
1570  }
1571  }
1572  // Setting ID/alias:
1573  if (!$script) {
1574  $script = $this->getTypoScriptFrontendController()->config['mainScript'];
1575  }
1576  if ($page['alias']) {
1577  $LD['url'] = $script . '?id=' . rawurlencode($page['alias']);
1578  } else {
1579  $LD['url'] = $script . '?id=' . $page['uid'];
1580  }
1581  // Setting target
1582  $LD['target'] = trim($page['target']) ?: $oTarget;
1583  // typeNum
1584  $typeNum = $this->setup[$LD['target'] . '.']['typeNum'];
1585  if (!MathUtility::canBeInterpretedAsInteger($typeOverride) && (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue']) {
1586  $typeOverride = (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue'];
1587  }
1588  if ((string)$typeOverride !== '') {
1589  $typeNum = $typeOverride;
1590  }
1591  // Override...
1592  if ($typeNum) {
1593  $LD['type'] = '&type=' . (int)$typeNum;
1594  } else {
1595  $LD['type'] = '';
1596  }
1597  // Preserving the type number.
1598  $LD['orig_type'] = $LD['type'];
1599  // noCache
1600  $LD['no_cache'] = trim($page['no_cache']) || $no_cache ? '&no_cache=1' : '';
1601  // linkVars
1602  if ($addParams) {
1603  $LD['linkVars'] = GeneralUtility::implodeArrayForUrl('', GeneralUtility::explodeUrl2Array($this->getTypoScriptFrontendController()->linkVars . $addParams), '', false, true);
1604  } else {
1605  $LD['linkVars'] = $this->getTypoScriptFrontendController()->linkVars;
1606  }
1607  // Add absRefPrefix if exists.
1608  $LD['url'] = $this->getTypoScriptFrontendController()->absRefPrefix . $LD['url'];
1609  // 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.
1610  $LD['sectionIndex'] = $page['sectionIndex_uid'] ? '#c' . $page['sectionIndex_uid'] : '';
1611  // Compile the normal total url
1612  $LD['totalURL'] = rtrim($LD['url'] . $LD['type'] . $LD['no_cache'] . $LD['linkVars'] . $this->getTypoScriptFrontendController()->getMethodUrlIdToken, '?') . $LD['sectionIndex'];
1613  // Call post processing function for link rendering:
1614  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'])) {
1615  $_params = [
1616  'LD' => &$LD,
1617  'args' => ['page' => $page, 'oTarget' => $oTarget, 'no_cache' => $no_cache, 'script' => $script, 'overrideArray' => $overrideArray, 'addParams' => $addParams, 'typeOverride' => $typeOverride, 'targetDomain' => $targetDomain],
1618  'typeNum' => $typeNum
1619  ];
1620  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'] as $_funcRef) {
1621  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1622  }
1623  }
1624  // Return the LD-array
1625  return $LD;
1626  }
1627 
1637  public function getFromMPmap($pageId = 0)
1638  {
1639  // Create map if not found already:
1640  if (!is_array($this->MPmap)) {
1641  $this->MPmap = [];
1642  $rootPoints = GeneralUtility::trimExplode(',', strtolower($this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints']), true);
1643  // Traverse rootpoints:
1644  foreach ($rootPoints as $p) {
1645  $initMParray = [];
1646  if ($p == 'root') {
1647  $p = $this->rootLine[0]['uid'];
1648  if ($this->rootLine[0]['_MOUNT_OL'] && $this->rootLine[0]['_MP_PARAM']) {
1649  $initMParray[] = $this->rootLine[0]['_MP_PARAM'];
1650  }
1651  }
1652  $this->initMPmap_create($p, $initMParray);
1653  }
1654  }
1655  // Finding MP var for Page ID:
1656  if ($pageId) {
1657  if (is_array($this->MPmap[$pageId]) && !empty($this->MPmap[$pageId])) {
1658  return implode(',', $this->MPmap[$pageId]);
1659  }
1660  }
1661  return '';
1662  }
1663 
1673  public function initMPmap_create($id, $MP_array = [], $level = 0)
1674  {
1675  $id = (int)$id;
1676  if ($id <= 0) {
1677  return;
1678  }
1679  // First level, check id
1680  if (!$level) {
1681  // Find mount point if any:
1682  $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($id);
1683  // Overlay mode:
1684  if (is_array($mount_info) && $mount_info['overlay']) {
1685  $MP_array[] = $mount_info['MPvar'];
1686  $id = $mount_info['mount_pid'];
1687  }
1688  // Set mapping information for this level:
1689  $this->MPmap[$id] = $MP_array;
1690  // Normal mode:
1691  if (is_array($mount_info) && !$mount_info['overlay']) {
1692  $MP_array[] = $mount_info['MPvar'];
1693  $id = $mount_info['mount_pid'];
1694  }
1695  }
1696  if ($id && $level < 20) {
1697  $nextLevelAcc = [];
1698  // Select and traverse current level pages:
1699  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1700  $queryBuilder->getRestrictions()
1701  ->removeAll()
1702  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1703  $queryResult = $queryBuilder
1704  ->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol')
1705  ->from('pages')
1706  ->where(
1707  $queryBuilder->expr()->eq(
1708  'pid',
1709  $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)
1710  ),
1711  $queryBuilder->expr()->neq(
1712  'doktype',
1713  $queryBuilder->createNamedParameter(PageRepository::DOKTYPE_RECYCLER, \PDO::PARAM_INT)
1714  ),
1715  $queryBuilder->expr()->neq(
1716  'doktype',
1717  $queryBuilder->createNamedParameter(PageRepository::DOKTYPE_BE_USER_SECTION, \PDO::PARAM_INT)
1718  )
1719  )->execute();
1720  while ($row = $queryResult->fetch()) {
1721  // Find mount point if any:
1722  $next_id = $row['uid'];
1723  $next_MP_array = $MP_array;
1724  $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($next_id, $row);
1725  // Overlay mode:
1726  if (is_array($mount_info) && $mount_info['overlay']) {
1727  $next_MP_array[] = $mount_info['MPvar'];
1728  $next_id = $mount_info['mount_pid'];
1729  }
1730  if (!isset($this->MPmap[$next_id])) {
1731  // Set mapping information for this level:
1732  $this->MPmap[$next_id] = $next_MP_array;
1733  // Normal mode:
1734  if (is_array($mount_info) && !$mount_info['overlay']) {
1735  $next_MP_array[] = $mount_info['MPvar'];
1736  $next_id = $mount_info['mount_pid'];
1737  }
1738  // Register recursive call
1739  // (have to do it this way since ALL of the current level should be registered BEFORE the sublevel at any time)
1740  $nextLevelAcc[] = [$next_id, $next_MP_array];
1741  }
1742  }
1743  // Call recursively, if any:
1744  foreach ($nextLevelAcc as $pSet) {
1745  $this->initMPmap_create($pSet[0], $pSet[1], $level + 1);
1746  }
1747  }
1748  }
1749 
1758  protected function addDefaultTypoScript()
1759  {
1760  // Add default TS for all code types, if not done already
1761  if (!$this->isDefaultTypoScriptAdded) {
1762  // adding default setup and constants
1763  // defaultTypoScript_setup is *very* unlikely to be empty
1764  // the count of elements in ->constants, ->config and ->templateIncludePaths have to be in sync
1765  array_unshift($this->constants, (string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants']);
1766  array_unshift($this->config, (string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup']);
1767  array_unshift($this->templateIncludePaths, '');
1768  // prepare a proper entry to hierachyInfo (used by TemplateAnalyzer in BE)
1769  $rootTemplateId = $this->hierarchyInfo[count($this->hierarchyInfo)-1]['templateID'];
1770  $defaultTemplateInfo = [
1771  'root' => '',
1772  'next' => '',
1773  'clConst' => '',
1774  'clConf' => '',
1775  'templateID' => '_defaultTypoScript_',
1776  'templateParent' => $rootTemplateId,
1777  'title' => 'SYS:TYPO3_CONF_VARS:FE:defaultTypoScript',
1778  'uid' => '_defaultTypoScript_',
1779  'pid' => '',
1780  'configLines' => substr_count((string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'], LF) + 1
1781  ];
1782  // push info to information arrays used in BE by TemplateTools (Analyzer)
1783  array_unshift($this->clearList_const, $defaultTemplateInfo['uid']);
1784  array_unshift($this->clearList_setup, $defaultTemplateInfo['uid']);
1785  array_unshift($this->hierarchyInfo, $defaultTemplateInfo);
1786  $this->isDefaultTypoScriptAdded = true;
1787  }
1788  }
1789 
1793  protected function getTypoScriptFrontendController()
1794  {
1795  return $GLOBALS['TSFE'];
1796  }
1797 
1801  protected function getTimeTracker()
1802  {
1803  return GeneralUtility::makeInstance(TimeTracker::class);
1804  }
1805 
1813  protected function getCacheEntry($identifier)
1814  {
1815  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash')->get($identifier);
1816  }
1817 
1826  protected function setCacheEntry($identifier, $data, $tag)
1827  {
1828  GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash')->set($identifier, $data, ['ident_' . $tag], 0);
1829  }
1830 }
printTitle($pageTitle, $noTitle=false, $showTitleFirst=false, $pageTitleSeparator= '')
includeStaticTypoScriptSources($idList, $templateID, $pid, $row)
static isFirstPartOfStr($str, $partStr)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static explodeUrl2Array($string, $multidim=false)
static implodeArrayForUrl($name, array $theArray, $str= '', $skipBlank=false, $rawurlencodeParamName=false)
mergeConstantsFromIncludedTsConfigFiles($filesToInclude, $TSdataArray)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static sortedKeyList($setupArr, $acceptOnlyProperties=false)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
addExtensionStatics($idList, $templateID, $pid, $row)
initMPmap_create($id, $MP_array=[], $level=0)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
static filterAndSortByNumericKeys($setupArr, $acceptAnyKeys=false)
runThroughTemplates($theRootLine, $start_template_uid=0)
static getFileAbsFileName($filename, $_=null, $_2=null)
setProcessExtensionStatics($processExtensionStatics)
linkData($page, $oTarget, $no_cache, $script, $overrideArray=null, $addParams= '', $typeOverride= '', $targetDomain= '')
processTemplate($row, $idList, $pid, $templateID= '', $templateParent= '', $includePath= '')
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static callUserFunction($funcName, &$params, &$ref, $_= '', $errorMode=0)
getTypoScriptSourceFileContent($filePath, $baseName)