TYPO3 CMS  TYPO3_7-6
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 
30 
37 {
45  protected $verbose = false;
46 
52  public $tt_track = true;
53 
59  public $forceTemplateParsing = false;
60 
68  public $matchAlternative = [];
69 
75  public $matchAll = false;
76 
80  public $backend_info = false;
81 
87  public $ext_constants_BRP = 0;
88 
92  public $ext_config_BRP = 0;
93 
97  public $ext_regLinenumbers = false;
98 
102  public $ext_regComments = false;
103 
108  public $tempPath = 'typo3temp/';
109 
115  public $whereClause = '';
116 
120  public $debug = false;
121 
128  public $allowedPaths = [];
129 
136 
142  public $loaded = false;
143 
147  public $setup = [];
148 
152  public $flatSetup = [];
153 
161  public $config = [];
162 
168  public $constants = [];
169 
175  protected $templateIncludePaths = [];
176 
182  public $hierarchyInfo = [];
183 
189  public $hierarchyInfoToRoot = [];
190 
196  public $nextLevel = 0;
197 
203  public $rootId;
204 
210  public $rootLine;
211 
218 
225 
231  public $rowSum;
232 
238  public $sitetitle = '';
239 
245  public $sections;
246 
253 
258  public $clearList_const = [];
259 
265  public $clearList_setup = [];
266 
270  public $parserErrors = [];
271 
275  public $setup_constants = [];
276 
282  public $fileCache = [];
283 
289  public $frames = [];
290 
296  public $MPmap = '';
297 
307  protected $extensionStaticsProcessed = false;
308 
314  protected $processExtensionStatics = false;
315 
323  protected $isDefaultTypoScriptAdded = false;
324 
333  protected $processIncludesHasBeenRun = false;
334 
338  public function getProcessExtensionStatics()
339  {
341  }
342 
347  {
348  $this->processExtensionStatics = (bool)$processExtensionStatics;
349  }
350 
355  public function setVerbose($verbose)
356  {
357  $this->verbose = (bool)$verbose;
358  }
359 
367  public function init()
368  {
369  // $this->whereClause is used only to select templates from sys_template.
370  // $GLOBALS['SIM_ACCESS_TIME'] is used so that we're able to simulate a later time as a test...
371  $this->whereClause = 'AND deleted=0 ';
372  if (!$this->getTypoScriptFrontendController()->showHiddenRecords) {
373  $this->whereClause .= 'AND hidden=0 ';
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  $this->whereClause .= 'AND (starttime<=' . $GLOBALS['SIM_ACCESS_TIME'] . ') AND (endtime=0 OR endtime>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
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 
415  public function getCurrentPageData()
416  {
417  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pagesection')->get((int)$this->getTypoScriptFrontendController()->id . '_' . GeneralUtility::md5int($this->getTypoScriptFrontendController()->MP));
418  }
419 
426  public function matching($cc)
427  {
428  if (is_array($cc['all'])) {
430  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
431  $matchObj->setRootline((array)$cc['rootLine']);
432  $sectionsMatch = [];
433  foreach ($cc['all'] as $key => $pre) {
434  if ($matchObj->match($pre)) {
435  $sectionsMatch[$key] = $pre;
436  }
437  }
438  $cc['match'] = $sectionsMatch;
439  }
440  return $cc;
441  }
442 
452  public function start($theRootLine)
453  {
454  if (is_array($theRootLine)) {
455  $setupData = '';
456  $hash = '';
457  // Flag that indicates that the existing data in cache_pagesection
458  // could be used (this is the case if $TSFE->all is set, and the
459  // rowSum still matches). Based on this we decide if cache_pagesection
460  // needs to be updated...
461  $isCached = false;
462  $this->runThroughTemplates($theRootLine);
463  if ($this->getTypoScriptFrontendController()->all) {
464  $cc = $this->getTypoScriptFrontendController()->all;
465  // The two rowSums must NOT be different from each other - which they will be if start/endtime or hidden has changed!
466  if (serialize($this->rowSum) !== serialize($cc['rowSum'])) {
467  unset($cc);
468  } else {
469  // If $TSFE->all contains valid data, we don't need to update cache_pagesection (because this data was fetched from there already)
470  if (serialize($this->rootLine) === serialize($cc['rootLine'])) {
471  $isCached = true;
472  }
473  // 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)...
474  unset($cc['rootLine']);
475  }
476  }
477  // This is about getting the hash string which is used to fetch the cached TypoScript template.
478  // If there was some cached currentPageData ($cc) then that's good (it gives us the hash).
479  if (isset($cc) && is_array($cc)) {
480  // If currentPageData was actually there, we match the result (if this wasn't done already in $TSFE->getFromCache()...)
481  if (!$cc['match']) {
482  // @todo check if this can ever be the case - otherwise remove
483  $cc = $this->matching($cc);
484  ksort($cc);
485  }
486  $hash = md5(serialize($cc));
487  } else {
488  // 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.
489  $rowSumHash = md5('ROWSUM:' . serialize($this->rowSum));
490  $result = PageRepository::getHash($rowSumHash);
491  if (is_array($result)) {
492  $cc = [];
493  $cc['all'] = $result;
494  $cc['rowSum'] = $this->rowSum;
495  $cc = $this->matching($cc);
496  ksort($cc);
497  $hash = md5(serialize($cc));
498  }
499  }
500  if ($hash) {
501  // Get TypoScript setup array
502  $setupData = PageRepository::getHash($hash);
503  }
504  if (is_array($setupData) && !$this->forceTemplateParsing) {
505  // If TypoScript setup structure was cached we unserialize it here:
506  $this->setup = $setupData;
507  if ($this->tt_track) {
508  $this->getTimeTracker()->setTSLogMessage('Using cached TS template data');
509  }
510  } else {
511  if ($this->tt_track) {
512  $this->getTimeTracker()->setTSLogMessage('Not using any cached TS data');
513  }
514 
515  // Make configuration
516  $this->generateConfig();
517  // This stores the template hash thing
518  $cc = [];
519  // All sections in the template at this point is found
520  $cc['all'] = $this->sections;
521  // The line of templates is collected
522  $cc['rowSum'] = $this->rowSum;
523  $cc = $this->matching($cc);
524  ksort($cc);
525  $hash = md5(serialize($cc));
526  // This stores the data.
527  PageRepository::storeHash($hash, $this->setup, 'TS_TEMPLATE');
528  if ($this->tt_track) {
529  $this->getTimeTracker()->setTSlogMessage('TS template size, serialized: ' . strlen(serialize($this->setup)) . ' bytes');
530  }
531  $rowSumHash = md5('ROWSUM:' . serialize($this->rowSum));
532  PageRepository::storeHash($rowSumHash, $cc['all'], 'TMPL_CONDITIONS_ALL');
533  }
534  // Add rootLine
535  $cc['rootLine'] = $this->rootLine;
536  ksort($cc);
537  // Make global and save
538  $this->getTypoScriptFrontendController()->all = $cc;
539  // Matching must be executed for every request, so this must never be part of the pagesection cache!
540  unset($cc['match']);
541  if (!$isCached && !$this->simulationHiddenOrTime && !$this->getTypoScriptFrontendController()->no_cache) {
542  // Only save the data if we're not simulating by hidden/starttime/endtime
543  $mpvarHash = GeneralUtility::md5int($this->getTypoScriptFrontendController()->MP);
545  $pageSectionCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_pagesection');
546  $pageSectionCache->set((int)$this->getTypoScriptFrontendController()->id . '_' . $mpvarHash, $cc, [
547  'pageId_' . (int)$this->getTypoScriptFrontendController()->id,
548  'mpvarHash_' . $mpvarHash
549  ]);
550  }
551  // If everything OK.
552  if ($this->rootId && $this->rootLine && $this->setup) {
553  $this->loaded = true;
554  }
555  }
556  }
557 
558  /*******************************************************************
559  *
560  * Fetching TypoScript code text for the Template Hierarchy
561  *
562  *******************************************************************/
573  public function runThroughTemplates($theRootLine, $start_template_uid = 0)
574  {
575  $this->constants = [];
576  $this->config = [];
577  $this->rowSum = [];
578  $this->hierarchyInfoToRoot = [];
579  $this->absoluteRootLine = $theRootLine;
580  $this->isDefaultTypoScriptAdded = false;
581 
582  reset($this->absoluteRootLine);
583  $c = count($this->absoluteRootLine);
584  for ($a = 0; $a < $c; $a++) {
585  // If some template loaded before has set a template-id for the next level, then load this template first!
586  if ($this->nextLevel) {
587  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'sys_template', 'uid=' . (int)$this->nextLevel . ' ' . $this->whereClause);
588  $this->nextLevel = 0;
589  if ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
590  $this->versionOL($row);
591  if (is_array($row)) {
592  $this->processTemplate($row, 'sys_' . $row['uid'], $this->absoluteRootLine[$a]['uid'], 'sys_' . $row['uid']);
593  $this->outermostRootlineIndexWithTemplate = $a;
594  }
595  }
596  $this->getDatabaseConnection()->sql_free_result($res);
597  }
598  $addC = '';
599  // If first loop AND there is set an alternative template uid, use that
600  if ($a == $c - 1 && $start_template_uid) {
601  $addC = ' AND uid=' . (int)$start_template_uid;
602  }
603  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'sys_template', 'pid=' . (int)$this->absoluteRootLine[$a]['uid'] . $addC . ' ' . $this->whereClause, '', 'root DESC, sorting', 1);
604  if ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
605  $this->versionOL($row);
606  if (is_array($row)) {
607  $this->processTemplate($row, 'sys_' . $row['uid'], $this->absoluteRootLine[$a]['uid'], 'sys_' . $row['uid']);
608  $this->outermostRootlineIndexWithTemplate = $a;
609  }
610  }
611  $this->getDatabaseConnection()->sql_free_result($res);
612  $this->rootLine[] = $this->absoluteRootLine[$a];
613  }
614 
615  // Process extension static files if not done yet, but explicitly requested
616  if (!$this->extensionStaticsProcessed && $this->processExtensionStatics) {
617  $this->addExtensionStatics('sys_0', 'sys_0', 0, []);
618  }
619 
620  // Add the global default TypoScript from the TYPO3_CONF_VARS
621  $this->addDefaultTypoScript();
622 
623  $this->processIncludes();
624  }
625 
639  public function processTemplate($row, $idList, $pid, $templateID = '', $templateParent = '', $includePath = '')
640  {
641  // Adding basic template record information to rowSum array
642  $this->rowSum[] = [$row['uid'], $row['title'], $row['tstamp']];
643  // Processing "Clear"-flags
644  $clConst = 0;
645  $clConf = 0;
646  if ($row['clear']) {
647  $clConst = $row['clear'] & 1;
648  $clConf = $row['clear'] & 2;
649  if ($clConst) {
650  // Keep amount of items to stay in sync with $this->templateIncludePaths so processIncludes() does not break
651  foreach ($this->constants as &$constantConfiguration) {
652  $constantConfiguration = '';
653  }
654  unset($constantConfiguration);
655  $this->clearList_const = [];
656  }
657  if ($clConf) {
658  // Keep amount of items to stay in sync with $this->templateIncludePaths so processIncludes() does not break
659  foreach ($this->config as &$configConfiguration) {
660  $configConfiguration = '';
661  }
662  unset($configConfiguration);
663  $this->hierarchyInfoToRoot = [];
664  $this->clearList_setup = [];
665  }
666  }
667  // Include static records (static_template) or files (from extensions) (#1/2)
668  // NORMAL inclusion, The EXACT same code is found below the basedOn inclusion!!!
669  if (!$row['includeStaticAfterBasedOn']) {
670  $this->includeStaticTypoScriptSources($idList, $templateID, $pid, $row);
671  }
672  // Include "Based On" sys_templates:
673  // 'basedOn' is a list of templates to include
674  if (trim($row['basedOn'])) {
675  // Normal Operation, which is to include the "based-on" sys_templates,
676  // if they are not already included, and maintaining the sorting of the templates
677  $basedOnIds = GeneralUtility::intExplode(',', $row['basedOn'], true);
678  // skip template if it's already included
679  foreach ($basedOnIds as $key => $basedOnId) {
680  if (GeneralUtility::inList($idList, 'sys_' . $basedOnId)) {
681  unset($basedOnIds[$key]);
682  }
683  }
684  if (!empty($basedOnIds)) {
685  $subTemplates = $this->getDatabaseConnection()->exec_SELECTgetRows('*', 'sys_template', 'uid IN (' . implode(',', $basedOnIds) . ') ' . $this->whereClause, '', '', '', 'uid');
686  // Traversing list again to ensure the sorting of the templates
687  foreach ($basedOnIds as $id) {
688  if (is_array($subTemplates[$id])) {
689  $this->versionOL($subTemplates[$id]);
690  $this->processTemplate($subTemplates[$id], $idList . ',sys_' . $id, $pid, 'sys_' . $id, $templateID);
691  }
692  }
693  }
694  }
695  // Include static records (static_template) or files (from extensions) (#2/2)
696  if ($row['includeStaticAfterBasedOn']) {
697  $this->includeStaticTypoScriptSources($idList, $templateID, $pid, $row);
698  }
699  // Creating hierarchy information; Used by backend analysis tools
700  $this->hierarchyInfo[] = ($this->hierarchyInfoToRoot[] = [
701  'root' => trim($row['root']),
702  'next' => $row['nextLevel'],
703  'clConst' => $clConst,
704  'clConf' => $clConf,
705  'templateID' => $templateID,
706  'templateParent' => $templateParent,
707  'title' => $row['title'],
708  'uid' => $row['uid'],
709  'pid' => $row['pid'],
710  'configLines' => substr_count($row['config'], LF) + 1
711  ]);
712  // Adding the content of the fields constants (Constants) and config (Setup)
713  $this->constants[] = $row['constants'];
714  $this->config[] = $row['config'];
715  $this->templateIncludePaths[] = $includePath;
716  // For backend analysis (Template Analyser) provide the order of added constants/config template IDs
717  $this->clearList_const[] = $templateID;
718  $this->clearList_setup[] = $templateID;
719  if (trim($row['sitetitle'])) {
720  $this->sitetitle = $row['sitetitle'];
721  }
722  // If the template record is a Rootlevel record, set the flag and clear the template rootLine (so it starts over from this point)
723  if (trim($row['root'])) {
724  $this->rootId = $pid;
725  $this->rootLine = [];
726  }
727  // If a template is set to be active on the next level set this internal value to point to this UID. (See runThroughTemplates())
728  if ($row['nextLevel']) {
729  $this->nextLevel = $row['nextLevel'];
730  } else {
731  $this->nextLevel = 0;
732  }
733  }
734 
746  public function updateRootlineData($fullRootLine)
747  {
748  if (!is_array($this->rootLine) || empty($this->rootLine)) {
749  return;
750  }
751 
752  $fullRootLineByUid = [];
753  foreach ($fullRootLine as $rootLineData) {
754  $fullRootLineByUid[$rootLineData['uid']] = $rootLineData;
755  }
756 
757  foreach ($this->rootLine as $level => $dataArray) {
758  $currentUid = $dataArray['uid'];
759 
760  if (!array_key_exists($currentUid, $fullRootLineByUid)) {
761  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);
762  }
763 
764  $this->rootLine[$level] = $fullRootLineByUid[$currentUid];
765  }
766  }
767 
778  public function includeStaticTypoScriptSources($idList, $templateID, $pid, $row)
779  {
780  // Static Template Records (static_template): include_static is a list of static templates to include
781  // Call function for link rendering:
782  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources'])) {
783  $_params = [
784  'idList' => &$idList,
785  'templateId' => &$templateID,
786  'pid' => &$pid,
787  'row' => &$row
788  ];
789  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSources'] as $_funcRef) {
790  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
791  }
792  }
793  // If "Include before all static templates if root-flag is set" is set:
794  if ($row['static_file_mode'] == 3 && substr($templateID, 0, 4) == 'sys_' && $row['root']) {
795  $this->addExtensionStatics($idList, $templateID, $pid, $row);
796  }
797  // Static Template Files (Text files from extensions): include_static_file is a list of static files to include (from extensions)
798  if (trim($row['include_static_file'])) {
799  $include_static_fileArr = GeneralUtility::trimExplode(',', $row['include_static_file'], true);
800  // Traversing list
801  foreach ($include_static_fileArr as $ISF_file) {
802  if (substr($ISF_file, 0, 4) == 'EXT:') {
803  list($ISF_extKey, $ISF_localPath) = explode('/', substr($ISF_file, 4), 2);
804  if ((string)$ISF_extKey !== '' && ExtensionManagementUtility::isLoaded($ISF_extKey) && (string)$ISF_localPath !== '') {
805  $ISF_localPath = rtrim($ISF_localPath, '/') . '/';
806  $ISF_filePath = ExtensionManagementUtility::extPath($ISF_extKey) . $ISF_localPath;
807  if (@is_dir($ISF_filePath)) {
808  $mExtKey = str_replace('_', '', $ISF_extKey . '/' . $ISF_localPath);
809  $subrow = [
810  'constants' => $this->getTypoScriptSourceFileContent($ISF_filePath, 'constants'),
811  'config' => $this->getTypoScriptSourceFileContent($ISF_filePath, 'setup'),
812  'include_static' => @file_exists(($ISF_filePath . 'include_static.txt')) ? implode(',', array_unique(GeneralUtility::intExplode(',', GeneralUtility::getUrl($ISF_filePath . 'include_static.txt')))) : '',
813  'include_static_file' => @file_exists(($ISF_filePath . 'include_static_file.txt')) ? implode(',', array_unique(explode(',', GeneralUtility::getUrl($ISF_filePath . 'include_static_file.txt')))) : '',
814  'title' => $ISF_file,
815  'uid' => $mExtKey
816  ];
817  $subrow = $this->prependStaticExtra($subrow);
818  $this->processTemplate($subrow, $idList . ',ext_' . $mExtKey, $pid, 'ext_' . $mExtKey, $templateID, $ISF_filePath);
819  }
820  }
821  }
822  }
823  }
824  // If "Default (include before if root flag is set)" is set OR
825  // "Always include before this template record" AND root-flag are set
826  if ($row['static_file_mode'] == 1 || $row['static_file_mode'] == 0 && substr($templateID, 0, 4) == 'sys_' && $row['root']) {
827  $this->addExtensionStatics($idList, $templateID, $pid, $row);
828  }
829  // Include Static Template Records after all other TypoScript has been included.
830  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSourcesAtEnd'])) {
831  $_params = [
832  'idList' => &$idList,
833  'templateId' => &$templateID,
834  'pid' => &$pid,
835  'row' => &$row
836  ];
837  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['includeStaticTypoScriptSourcesAtEnd'] as $_funcRef) {
838  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
839  }
840  }
841  }
842 
851  protected function getTypoScriptSourceFileContent($filePath, $baseName)
852  {
853  $extensions = ['.ts', '.txt'];
854  foreach ($extensions as $extension) {
855  $fileName = $filePath . $baseName . $extension;
856  if (@file_exists($fileName)) {
857  return GeneralUtility::getUrl($fileName);
858  }
859  }
860  return '';
861  }
862 
874  public function addExtensionStatics($idList, $templateID, $pid, $row)
875  {
876  $this->extensionStaticsProcessed = true;
877 
878  // @todo Change to use new API
879  foreach ($GLOBALS['TYPO3_LOADED_EXT'] as $extKey => $files) {
880  if ((is_array($files) || $files instanceof \ArrayAccess) && ($files['ext_typoscript_constants.txt'] || $files['ext_typoscript_setup.txt'])) {
881  $mExtKey = str_replace('_', '', $extKey);
882  $subrow = [
883  'constants' => $files['ext_typoscript_constants.txt'] ? GeneralUtility::getUrl($files['ext_typoscript_constants.txt']) : '',
884  'config' => $files['ext_typoscript_setup.txt'] ? GeneralUtility::getUrl($files['ext_typoscript_setup.txt']) : '',
885  'title' => $extKey,
886  'uid' => $mExtKey
887  ];
888  $subrow = $this->prependStaticExtra($subrow);
889  $extPath = ExtensionManagementUtility::extPath($extKey);
890  $this->processTemplate($subrow, $idList . ',ext_' . $mExtKey, $pid, 'ext_' . $mExtKey, $templateID, $extPath);
891  }
892  }
893  }
894 
905  public function prependStaticExtra($subrow)
906  {
907  // the identifier can be "43" if coming from "static template" extension or a path like "cssstyledcontent/static/"
908  $identifier = $subrow['uid'];
909  $subrow['config'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.'][$identifier];
910  $subrow['constants'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.'][$identifier];
911  // 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
912  if (in_array($identifier, $GLOBALS['TYPO3_CONF_VARS']['FE']['contentRenderingTemplates'], true)) {
913  $subrow['config'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup.']['defaultContentRendering'];
914  $subrow['constants'] .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants.']['defaultContentRendering'];
915  }
916  return $subrow;
917  }
918 
926  public function versionOL(&$row)
927  {
928  // Distinguish frontend and backend call:
929  // To do the fronted call a full frontend is required, just checking for
930  // TYPO3_MODE === 'FE' is not enough. This could otherwise lead to fatals in
931  // eId scripts that run in frontend scope, but do not have a full blown frontend.
932  if (is_object($this->getTypoScriptFrontendController()) && property_exists($this->getTypoScriptFrontendController(), 'sys_page') && method_exists($this->getTypoScriptFrontendController()->sys_page, 'versionOL')) {
933  // Frontend
934  $this->getTypoScriptFrontendController()->sys_page->versionOL('sys_template', $row);
935  } else {
936  // Backend
937  BackendUtility::workspaceOL('sys_template', $row);
938  }
939  }
940 
941  /*******************************************************************
942  *
943  * Parsing TypoScript code text from Template Records into PHP array
944  *
945  *******************************************************************/
953  public function generateConfig()
954  {
955  // Add default TS for all code types
956  $this->addDefaultTypoScript();
957 
958  // Parse the TypoScript code text for include-instructions!
959  $this->processIncludes();
960  // These vars are also set lateron...
961  $this->setup['sitetitle'] = $this->sitetitle;
962  // ****************************
963  // Parse TypoScript Constants
964  // ****************************
965  // Initialize parser and match-condition classes:
967  $constants = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
968  $constants->breakPointLN = (int)$this->ext_constants_BRP;
969  $constants->setup = $this->mergeConstantsFromPageTSconfig([]);
971  $matchObj = GeneralUtility::makeInstance(ConditionMatcher::class);
972  $matchObj->setSimulateMatchConditions($this->matchAlternative);
973  $matchObj->setSimulateMatchResult((bool)$this->matchAll);
974  // Traverse constants text fields and parse them
975  foreach ($this->constants as $str) {
976  $constants->parse($str, $matchObj);
977  }
978  // Read out parse errors if any
979  $this->parserErrors['constants'] = $constants->errors;
980  // 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)
981  $this->flatSetup = [];
982  $this->flattenSetup($constants->setup, '', '');
983  // ***********************************************
984  // Parse TypoScript Setup (here called "config")
985  // ***********************************************
986  // Initialize parser and match-condition classes:
988  $config = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
989  $config->breakPointLN = (int)$this->ext_config_BRP;
990  $config->regLinenumbers = $this->ext_regLinenumbers;
991  $config->regComments = $this->ext_regComments;
992  $config->setup = $this->setup;
993  // Transfer information about conditions found in "Constants" and which of them returned TRUE.
994  $config->sections = $constants->sections;
995  $config->sectionsMatch = $constants->sectionsMatch;
996  // Traverse setup text fields and concatenate them into one, single string separated by a [GLOBAL] condition
997  $all = '';
998  foreach ($this->config as $str) {
999  $all .= '
1000 [GLOBAL]
1001 ' . $str;
1002  }
1003  // Substitute constants in the Setup code:
1004  if ($this->tt_track) {
1005  $this->getTimeTracker()->push('Substitute Constants (' . count($this->flatSetup) . ')');
1006  }
1007  $all = $this->substituteConstants($all);
1008  if ($this->tt_track) {
1009  $this->getTimeTracker()->pull();
1010  }
1011 
1012  // Searching for possible unsubstituted constants left (only for information)
1013  if ($this->verbose) {
1014  if (preg_match_all('/\\{\\$.[^}]*\\}/', $all, $constantList) > 0) {
1015  if ($this->tt_track) {
1016  $this->getTimeTracker()->setTSlogMessage(implode(', ', $constantList[0]) . ': Constants may remain un-substituted!!', 2);
1017  }
1018  }
1019  }
1020 
1021  // Logging the textual size of the TypoScript Setup field text with all constants substituted:
1022  if ($this->tt_track) {
1023  $this->getTimeTracker()->setTSlogMessage('TypoScript template size as textfile: ' . strlen($all) . ' bytes');
1024  }
1025  // Finally parse the Setup field TypoScript code (where constants are now substituted)
1026  $config->parse($all, $matchObj);
1027  // Read out parse errors if any
1028  $this->parserErrors['config'] = $config->errors;
1029  // Transfer the TypoScript array from the parser object to the internal $this->setup array:
1030  $this->setup = $config->setup;
1031  if ($this->backend_info) {
1032  // Used for backend purposes only
1033  $this->setup_constants = $constants->setup;
1034  }
1035  // ****************************************************************
1036  // Final processing of the $this->setup TypoScript Template array
1037  // Basically: This is unsetting/setting of certain reserved keys.
1038  // ****************************************************************
1039  // 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!
1040  unset($this->setup['sitetitle']);
1041  unset($this->setup['sitetitle.']);
1042  $this->setup['sitetitle'] = $this->sitetitle;
1043  // Unsetting some vars...
1044  unset($this->setup['types.']);
1045  unset($this->setup['types']);
1046  if (is_array($this->setup)) {
1047  foreach ($this->setup as $key => $value) {
1048  if ($value == 'PAGE') {
1049  // Set the typeNum of the current page object:
1050  if (isset($this->setup[$key . '.']['typeNum'])) {
1051  $typeNum = $this->setup[$key . '.']['typeNum'];
1052  $this->setup['types.'][$typeNum] = $key;
1053  } elseif (!isset($this->setup['types.'][0]) || !$this->setup['types.'][0]) {
1054  $this->setup['types.'][0] = $key;
1055  }
1056  }
1057  }
1058  }
1059  unset($this->setup['temp.']);
1060  unset($constants);
1061  // Storing the conditions found/matched information:
1062  $this->sections = $config->sections;
1063  $this->sectionsMatch = $config->sectionsMatch;
1064  }
1065 
1074  public function processIncludes()
1075  {
1076  if ($this->processIncludesHasBeenRun) {
1077  return;
1078  }
1079 
1080  $paths = $this->templateIncludePaths;
1081  $files = [];
1082  foreach ($this->constants as &$value) {
1083  $includeData = Parser\TypoScriptParser::checkIncludeLines($value, 1, true, array_shift($paths));
1084  $files = array_merge($files, $includeData['files']);
1085  $value = $includeData['typoscript'];
1086  }
1087  unset($value);
1088  $paths = $this->templateIncludePaths;
1089  foreach ($this->config as &$value) {
1090  $includeData = Parser\TypoScriptParser::checkIncludeLines($value, 1, true, array_shift($paths));
1091  $files = array_merge($files, $includeData['files']);
1092  $value = $includeData['typoscript'];
1093  }
1094  unset($value);
1095 
1096  if (!empty($files)) {
1097  $files = array_unique($files);
1098  foreach ($files as $file) {
1099  $this->rowSum[] = [$file, filemtime($file)];
1100  }
1101  }
1102 
1103  $this->processIncludesHasBeenRun = true;
1104  }
1105 
1113  public function mergeConstantsFromPageTSconfig($constArray)
1114  {
1115  $TSdataArray = [];
1116  // Setting default configuration:
1117  $TSdataArray[] = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'];
1119  if (trim($this->absoluteRootLine[$a]['tsconfig_includes'])) {
1120  $includeTsConfigFileList = GeneralUtility::trimExplode(',',
1121  $this->absoluteRootLine[$a]['tsconfig_includes'], true);
1122 
1123  $TSdataArray = $this->mergeConstantsFromIncludedTsConfigFiles($includeTsConfigFileList, $TSdataArray);
1124  }
1125  $TSdataArray[] = $this->absoluteRootLine[$a]['TSconfig'];
1126  }
1127  // Parsing the user TS (or getting from cache)
1128  $TSdataArray = Parser\TypoScriptParser::checkIncludeLines_array($TSdataArray);
1129  $userTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
1131  $parseObj = GeneralUtility::makeInstance(Parser\TypoScriptParser::class);
1132  $parseObj->parse($userTS);
1133  if (is_array($parseObj->setup['TSFE.']['constants.'])) {
1134  ArrayUtility::mergeRecursiveWithOverrule($constArray, $parseObj->setup['TSFE.']['constants.']);
1135  }
1136 
1137  return $constArray;
1138  }
1139 
1147  protected function mergeConstantsFromIncludedTsConfigFiles($filesToInclude, $TSdataArray)
1148  {
1149  foreach ($filesToInclude as $key => $file) {
1150  if (!StringUtility::beginsWith($file, 'EXT:')) {
1151  continue;
1152  }
1153 
1154  list($extensionKey, $filePath) = explode('/', substr($file, 4), 2);
1155 
1156  if ((string)$extensionKey === '' || !ExtensionManagementUtility::isLoaded($extensionKey)) {
1157  continue;
1158  }
1159  if ((string)$filePath == '') {
1160  continue;
1161  }
1162 
1163  $tsConfigFile = ExtensionManagementUtility::extPath($extensionKey) . $filePath;
1164  if (file_exists($tsConfigFile)) {
1165  $TSdataArray[] = GeneralUtility::getUrl($tsConfigFile);
1166  }
1167  }
1168 
1169  return $TSdataArray;
1170  }
1171 
1180  public function flattenSetup($setupArray, $prefix)
1181  {
1182  if (is_array($setupArray)) {
1183  foreach ($setupArray as $key => $val) {
1184  if ($prefix || !StringUtility::beginsWith($key, 'TSConstantEditor')) {
1185  // We don't want 'TSConstantEditor' in the flattend setup on the first level (190201)
1186  if (is_array($val)) {
1187  $this->flattenSetup($val, $prefix . $key);
1188  } else {
1189  $this->flatSetup[$prefix . $key] = $val;
1190  }
1191  }
1192  }
1193  }
1194  }
1195 
1203  public function substituteConstants($all)
1204  {
1205  if ($this->tt_track) {
1206  $this->getTimeTracker()->setTSlogMessage('Constants to substitute: ' . count($this->flatSetup));
1207  }
1208  $noChange = false;
1209  // Recursive substitution of constants (up to 10 nested levels)
1210  for ($i = 0; $i < 10 && !$noChange; $i++) {
1211  $old_all = $all;
1212  $all = preg_replace_callback('/\\{\\$(.[^}]*)\\}/', [$this, 'substituteConstantsCallBack'], $all);
1213  if ($old_all == $all) {
1214  $noChange = true;
1215  }
1216  }
1217  return $all;
1218  }
1219 
1227  public function substituteConstantsCallBack($matches)
1228  {
1229  // Replace {$CONST} if found in $this->flatSetup, else leave unchanged
1230  return isset($this->flatSetup[$matches[1]]) && !is_array($this->flatSetup[$matches[1]]) ? $this->flatSetup[$matches[1]] : $matches[0];
1231  }
1232 
1233  /*******************************************************************
1234  *
1235  * Various API functions, used from elsewhere in the frontend classes
1236  *
1237  *******************************************************************/
1248  public function splitConfArray($conf, $splitCount)
1249  {
1250  // Initialize variables:
1251  $splitCount = (int)$splitCount;
1252  $conf2 = [];
1253  if ($splitCount && is_array($conf)) {
1254  // Initialize output to carry at least the keys:
1255  for ($aKey = 0; $aKey < $splitCount; $aKey++) {
1256  $conf2[$aKey] = [];
1257  }
1258  // Recursive processing of array keys:
1259  foreach ($conf as $cKey => $val) {
1260  if (is_array($val)) {
1261  $tempConf = $this->splitConfArray($val, $splitCount);
1262  foreach ($tempConf as $aKey => $val2) {
1263  $conf2[$aKey][$cKey] = $val2;
1264  }
1265  } else {
1266  // Splitting of all values on this level of the TypoScript object tree:
1267  if ($cKey === 'noTrimWrap' || (!strstr($val, '|*|') && !strstr($val, '||'))) {
1268  for ($aKey = 0; $aKey < $splitCount; $aKey++) {
1269  $conf2[$aKey][$cKey] = $val;
1270  }
1271  } else {
1272  $main = explode('|*|', $val);
1273  $lastC = 0;
1274  $middleC = 0;
1275  $firstC = 0;
1276  if ($main[0]) {
1277  $first = explode('||', $main[0]);
1278  $firstC = count($first);
1279  }
1280  $middle = [];
1281  if ($main[1]) {
1282  $middle = explode('||', $main[1]);
1283  $middleC = count($middle);
1284  }
1285  $last = [];
1286  $value = '';
1287  if ($main[2]) {
1288  $last = explode('||', $main[2]);
1289  $lastC = count($last);
1290  $value = $last[0];
1291  }
1292  for ($aKey = 0; $aKey < $splitCount; $aKey++) {
1293  if ($firstC && isset($first[$aKey])) {
1294  $value = $first[$aKey];
1295  } elseif ($middleC) {
1296  $value = $middle[($aKey - $firstC) % $middleC];
1297  }
1298  if ($lastC && $lastC >= $splitCount - $aKey) {
1299  $value = $last[$lastC - ($splitCount - $aKey)];
1300  }
1301  $conf2[$aKey][$cKey] = trim($value);
1302  }
1303  }
1304  }
1305  }
1306  }
1307  return $conf2;
1308  }
1309 
1316  public function getFileName($fileFromSetup)
1317  {
1318  $file = trim($fileFromSetup);
1319  if (!$file) {
1320  return null;
1321  } elseif (strpos($file, '../') !== false) {
1322  if ($this->tt_track) {
1323  $this->getTimeTracker()->setTSlogMessage('File path "' . $file . '" contained illegal string "../"!', 3);
1324  }
1325  return null;
1326  }
1327  // Cache
1328  $hash = md5($file);
1329  if (isset($this->fileCache[$hash])) {
1330  return $this->fileCache[$hash];
1331  }
1332 
1333  // if this is an URL, it can be returned directly
1334  $urlScheme = parse_url($file, PHP_URL_SCHEME);
1335  if ($urlScheme === 'https' || $urlScheme === 'http' || is_file(PATH_site . $file)) {
1336  return $file;
1337  }
1338 
1339  // this call also resolves EXT:myext/ files
1340  $file = GeneralUtility::getFileAbsFileName($file);
1341  if (!$file) {
1342  if ($this->tt_track) {
1343  $this->getTimeTracker()->setTSlogMessage('File "' . $fileFromSetup . '" was not found!', 3);
1344  }
1345  return null;
1346  }
1347 
1348  $file = PathUtility::stripPathSitePrefix($file);
1349 
1350  // Check if the found file is in the allowed paths
1351  foreach ($this->allowedPaths as $val) {
1352  if (GeneralUtility::isFirstPartOfStr($file, $val)) {
1353  $this->fileCache[$hash] = $file;
1354  return $file;
1355  }
1356  }
1357 
1358  if ($this->tt_track) {
1359  $this->getTimeTracker()->setTSlogMessage('"' . $file . '" was not located in the allowed paths: (' . implode(',', $this->allowedPaths) . ')', 3);
1360  }
1361  return null;
1362  }
1363 
1374  public function printTitle($pageTitle, $noTitle = false, $showTitleFirst = false, $pageTitleSeparator = '')
1375  {
1376  $siteTitle = trim($this->setup['sitetitle']);
1377  $pageTitle = $noTitle ? '' : $pageTitle;
1378  if ($showTitleFirst) {
1379  $temp = $siteTitle;
1380  $siteTitle = $pageTitle;
1381  $pageTitle = $temp;
1382  }
1383  // only show a separator if there are both site title and page title
1384  if ($pageTitle === '' || $siteTitle === '') {
1385  $pageTitleSeparator = '';
1386  // use the default separator if non given
1387  } elseif (empty($pageTitleSeparator)) {
1388  $pageTitleSeparator = ': ';
1389  }
1390  return $siteTitle . $pageTitleSeparator . $pageTitle;
1391  }
1392 
1401  public function fileContent($fileName)
1402  {
1403  $fileName = $this->getFileName($fileName);
1404  if ($fileName) {
1405  return GeneralUtility::getUrl($fileName);
1406  }
1407  return null;
1408  }
1409 
1419  public function wrap($content, $wrap)
1420  {
1422  if ($wrap) {
1423  $wrapArr = explode('|', $wrap);
1424  return trim($wrapArr[0]) . $content . trim($wrapArr[1]);
1425  } else {
1426  return $content;
1427  }
1428  }
1429 
1437  public function removeQueryString($url)
1438  {
1439  if (substr($url, -1) == '?') {
1440  return substr($url, 0, -1);
1441  } else {
1442  return $url;
1443  }
1444  }
1445 
1455  public static function sortedKeyList($setupArr, $acceptOnlyProperties = false)
1456  {
1457  $keyArr = [];
1458  $setupArrKeys = array_keys($setupArr);
1459  foreach ($setupArrKeys as $key) {
1460  if ($acceptOnlyProperties || MathUtility::canBeInterpretedAsInteger($key)) {
1461  $keyArr[] = (int)$key;
1462  }
1463  }
1464  $keyArr = array_unique($keyArr);
1465  sort($keyArr);
1466  return $keyArr;
1467  }
1468 
1475  public function getRootlineLevel($list)
1476  {
1477  $idx = 0;
1478  foreach ($this->rootLine as $page) {
1479  if (GeneralUtility::inList($list, $page['uid'])) {
1480  return $idx;
1481  }
1482  $idx++;
1483  }
1484  return false;
1485  }
1486 
1487  /*******************************************************************
1488  *
1489  * Functions for creating links
1490  *
1491  *******************************************************************/
1509  public function linkData($page, $oTarget, $no_cache, $script, $overrideArray = null, $addParams = '', $typeOverride = '', $targetDomain = '')
1510  {
1511  $LD = [];
1512  // Overriding some fields in the page record and still preserves the values by adding them as parameters. Little strange function.
1513  if (is_array($overrideArray)) {
1514  foreach ($overrideArray as $theKey => $theNewVal) {
1515  $addParams .= '&real_' . $theKey . '=' . rawurlencode($page[$theKey]);
1516  $page[$theKey] = $theNewVal;
1517  }
1518  }
1519  // Adding Mount Points, "&MP=", parameter for the current page if any is set:
1520  if (!strstr($addParams, '&MP=')) {
1521  // Looking for hardcoded defaults:
1522  if (trim($this->getTypoScriptFrontendController()->MP_defaults[$page['uid']])) {
1523  $addParams .= '&MP=' . rawurlencode(trim($this->getTypoScriptFrontendController()->MP_defaults[$page['uid']]));
1524  } elseif ($this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints']) {
1525  // Else look in automatically created map:
1526  $m = $this->getFromMPmap($page['uid']);
1527  if ($m) {
1528  $addParams .= '&MP=' . rawurlencode($m);
1529  }
1530  }
1531  }
1532  // Setting ID/alias:
1533  if (!$script) {
1534  $script = $this->getTypoScriptFrontendController()->config['mainScript'];
1535  }
1536  if ($page['alias']) {
1537  $LD['url'] = $script . '?id=' . rawurlencode($page['alias']);
1538  } else {
1539  $LD['url'] = $script . '?id=' . $page['uid'];
1540  }
1541  // Setting target
1542  $LD['target'] = trim($page['target']) ?: $oTarget;
1543  // typeNum
1544  $typeNum = $this->setup[$LD['target'] . '.']['typeNum'];
1545  if (!MathUtility::canBeInterpretedAsInteger($typeOverride) && (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue']) {
1546  $typeOverride = (int)$this->getTypoScriptFrontendController()->config['config']['forceTypeValue'];
1547  }
1548  if ((string)$typeOverride !== '') {
1549  $typeNum = $typeOverride;
1550  }
1551  // Override...
1552  if ($typeNum) {
1553  $LD['type'] = '&type=' . (int)$typeNum;
1554  } else {
1555  $LD['type'] = '';
1556  }
1557  // Preserving the type number.
1558  $LD['orig_type'] = $LD['type'];
1559  // noCache
1560  $LD['no_cache'] = trim($page['no_cache']) || $no_cache ? '&no_cache=1' : '';
1561  // linkVars
1562  if ($addParams) {
1563  $LD['linkVars'] = GeneralUtility::implodeArrayForUrl('', GeneralUtility::explodeUrl2Array($this->getTypoScriptFrontendController()->linkVars . $addParams), '', false, true);
1564  } else {
1565  $LD['linkVars'] = $this->getTypoScriptFrontendController()->linkVars;
1566  }
1567  // Add absRefPrefix if exists.
1568  $LD['url'] = $this->getTypoScriptFrontendController()->absRefPrefix . $LD['url'];
1569  // 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.
1570  $LD['sectionIndex'] = $page['sectionIndex_uid'] ? '#c' . $page['sectionIndex_uid'] : '';
1571  // Compile the normal total url
1572  $LD['totalURL'] = $this->removeQueryString(($LD['url'] . $LD['type'] . $LD['no_cache'] . $LD['linkVars'] . $this->getTypoScriptFrontendController()->getMethodUrlIdToken)) . $LD['sectionIndex'];
1573  // Call post processing function for link rendering:
1574  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'])) {
1575  $_params = [
1576  'LD' => &$LD,
1577  'args' => ['page' => $page, 'oTarget' => $oTarget, 'no_cache' => $no_cache, 'script' => $script, 'overrideArray' => $overrideArray, 'addParams' => $addParams, 'typeOverride' => $typeOverride, 'targetDomain' => $targetDomain],
1578  'typeNum' => $typeNum
1579  ];
1580  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tstemplate.php']['linkData-PostProc'] as $_funcRef) {
1581  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1582  }
1583  }
1584  // Return the LD-array
1585  return $LD;
1586  }
1587 
1597  public function getFromMPmap($pageId = 0)
1598  {
1599  // Create map if not found already:
1600  if (!is_array($this->MPmap)) {
1601  $this->MPmap = [];
1602  $rootPoints = GeneralUtility::trimExplode(',', strtolower($this->getTypoScriptFrontendController()->config['config']['MP_mapRootPoints']), true);
1603  // Traverse rootpoints:
1604  foreach ($rootPoints as $p) {
1605  $initMParray = [];
1606  if ($p == 'root') {
1607  $p = $this->rootLine[0]['uid'];
1608  if ($this->rootLine[0]['_MOUNT_OL'] && $this->rootLine[0]['_MP_PARAM']) {
1609  $initMParray[] = $this->rootLine[0]['_MP_PARAM'];
1610  }
1611  }
1612  $this->initMPmap_create($p, $initMParray);
1613  }
1614  }
1615  // Finding MP var for Page ID:
1616  if ($pageId) {
1617  if (is_array($this->MPmap[$pageId]) && !empty($this->MPmap[$pageId])) {
1618  return implode(',', $this->MPmap[$pageId]);
1619  }
1620  }
1621  return '';
1622  }
1623 
1633  public function initMPmap_create($id, $MP_array = [], $level = 0)
1634  {
1635  $id = (int)$id;
1636  if ($id <= 0) {
1637  return;
1638  }
1639  // First level, check id
1640  if (!$level) {
1641  // Find mount point if any:
1642  $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($id);
1643  // Overlay mode:
1644  if (is_array($mount_info) && $mount_info['overlay']) {
1645  $MP_array[] = $mount_info['MPvar'];
1646  $id = $mount_info['mount_pid'];
1647  }
1648  // Set mapping information for this level:
1649  $this->MPmap[$id] = $MP_array;
1650  // Normal mode:
1651  if (is_array($mount_info) && !$mount_info['overlay']) {
1652  $MP_array[] = $mount_info['MPvar'];
1653  $id = $mount_info['mount_pid'];
1654  }
1655  }
1656  if ($id && $level < 20) {
1657  $nextLevelAcc = [];
1658  // Select and traverse current level pages:
1659  $res = $this->getDatabaseConnection()->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol', 'pages', 'pid=' . (int)$id . ' AND deleted=0 AND doktype<>' . PageRepository::DOKTYPE_RECYCLER . ' AND doktype<>' . PageRepository::DOKTYPE_BE_USER_SECTION);
1660  while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
1661  // Find mount point if any:
1662  $next_id = $row['uid'];
1663  $next_MP_array = $MP_array;
1664  $mount_info = $this->getTypoScriptFrontendController()->sys_page->getMountPointInfo($next_id, $row);
1665  // Overlay mode:
1666  if (is_array($mount_info) && $mount_info['overlay']) {
1667  $next_MP_array[] = $mount_info['MPvar'];
1668  $next_id = $mount_info['mount_pid'];
1669  }
1670  if (!isset($this->MPmap[$next_id])) {
1671  // Set mapping information for this level:
1672  $this->MPmap[$next_id] = $next_MP_array;
1673  // Normal mode:
1674  if (is_array($mount_info) && !$mount_info['overlay']) {
1675  $next_MP_array[] = $mount_info['MPvar'];
1676  $next_id = $mount_info['mount_pid'];
1677  }
1678  // Register recursive call
1679  // (have to do it this way since ALL of the current level should be registered BEFORE the sublevel at any time)
1680  $nextLevelAcc[] = [$next_id, $next_MP_array];
1681  }
1682  }
1683  $this->getDatabaseConnection()->sql_free_result($res);
1684  // Call recursively, if any:
1685  foreach ($nextLevelAcc as $pSet) {
1686  $this->initMPmap_create($pSet[0], $pSet[1], $level + 1);
1687  }
1688  }
1689  }
1690 
1699  protected function addDefaultTypoScript()
1700  {
1701  // Add default TS for all code types, if not done already
1702  if (!$this->isDefaultTypoScriptAdded) {
1703  // adding default setup and constants
1704  // defaultTypoScript_setup is *very* unlikely to be empty
1705  // the count of elements in ->constants, ->config and ->templateIncludePaths have to be in sync
1706  array_unshift($this->constants, (string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_constants']);
1707  array_unshift($this->config, (string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup']);
1708  array_unshift($this->templateIncludePaths, '');
1709  // prepare a proper entry to hierachyInfo (used by TemplateAnalyzer in BE)
1710  $rootTemplateId = $this->hierarchyInfo[count($this->hierarchyInfo)-1]['templateID'];
1711  $defaultTemplateInfo = [
1712  'root' => '',
1713  'next' => '',
1714  'clConst' => '',
1715  'clConf' => '',
1716  'templateID' => '_defaultTypoScript_',
1717  'templateParent' => $rootTemplateId,
1718  'title' => 'SYS:TYPO3_CONF_VARS:FE:defaultTypoScript',
1719  'uid' => '_defaultTypoScript_',
1720  'pid' => '',
1721  'configLines' => substr_count((string)$GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_setup'], LF) + 1
1722  ];
1723  // push info to information arrays used in BE by TemplateTools (Analyzer)
1724  array_unshift($this->clearList_const, $defaultTemplateInfo['uid']);
1725  array_unshift($this->clearList_setup, $defaultTemplateInfo['uid']);
1726  array_unshift($this->hierarchyInfo, $defaultTemplateInfo);
1727  $this->isDefaultTypoScriptAdded = true;
1728  }
1729  }
1730 
1734  protected function getDatabaseConnection()
1735  {
1736  return $GLOBALS['TYPO3_DB'];
1737  }
1738 
1742  protected function getTypoScriptFrontendController()
1743  {
1744  return $GLOBALS['TSFE'];
1745  }
1746 
1750  protected function getTimeTracker()
1751  {
1752  return $GLOBALS['TT'];
1753  }
1754 }
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static isFirstPartOfStr($str, $partStr)
initMPmap_create($id, $MP_array=[], $level=0)
static sortedKeyList($setupArr, $acceptOnlyProperties=false)
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)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
processTemplate($row, $idList, $pid, $templateID='', $templateParent='', $includePath='')
printTitle($pageTitle, $noTitle=false, $showTitleFirst=false, $pageTitleSeparator='')
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
static storeHash($hash, $data, $ident, $lifetime=0)
setProcessExtensionStatics($processExtensionStatics)
static explodeUrl2Array($string, $multidim=false)
addExtensionStatics($idList, $templateID, $pid, $row)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=true, $includeEmptyValues=true, $enableUnsetFeature=true)
static getUrl($url, $includeHeader=0, $requestHeaders=false, &$report=null)
static getFileAbsFileName($filename, $onlyRelative=true, $relToTYPO3_mainDir=false)
static beginsWith($haystack, $needle)
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='')