[TASK] Mark various TypoScript parsing functionality as internal
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / TypoScript / Parser / TypoScriptParser.php
index ab80353..e4d0d0b 100644 (file)
@@ -14,88 +14,120 @@ namespace TYPO3\CMS\Core\TypoScript\Parser;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Psr\Log\LoggerInterface;
+use Symfony\Component\Finder\Finder;
+use TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher as BackendConditionMatcher;
+use TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait;
+use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
+use TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher;
+use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Log\LogManager;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
+use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
 use TYPO3\CMS\Core\Utility\StringUtility;
-use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
-use TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher;
+use TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching\ConditionMatcher as FrontendConditionMatcher;
 
 /**
  * The TypoScript parser
  */
 class TypoScriptParser
 {
-    /**
-     * If set, then key names cannot contain characters other than [:alnum:]_\.-
-     *
-     * @var bool
-     */
-    public $strict = true;
+    use PublicPropertyDeprecationTrait;
+    use PublicMethodDeprecationTrait;
+
+    protected $deprecatedPublicProperties = [
+        'raw' => 'Using $raw of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'rawP' => 'Using $rawP of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'lastComment' => 'Using $lastComment of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'commentSet' => 'Using $commentSet of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'multiLineEnabled' => 'Using $multiLineEnabled of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'multiLineObject' => 'Using $multiLineObject of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'multiLineValue' => 'Using $multiLineValue of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'inBrace' => 'Using $inBrace of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'lastConditionTrue' => 'Using $lastConditionTrue of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'syntaxHighLight' => 'Using $syntaxHighLight of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'highLightData' => 'Using $highLightData of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'highLightData_bracelevel' => 'Using $highLightData_bracelevel of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'highLightStyles' => 'Using $highLightStyles of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'highLightBlockStyles' => 'Using $highLightBlockStyles of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+        'highLightBlockStyles_basecolor' => 'Using $highLightBlockStyles_basecolor of class TypoScriptParser from the outside is discouraged, as this variable is only used for internal storage.',
+    ];
+
+    protected $deprecatedPublicMethods = [
+        'nextDivider' => 'Using nextDivider() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+        'parseSub' => 'Using parseSub() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+        'rollParseSub' => 'Using rollParseSub() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+        'setVal' => 'Using setVal() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+        'error' => 'Using error() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+        'regHighLight' => 'Using regHighLight() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+        'syntaxHighlight_print' => 'Using syntaxHighlight_print() of class TypoScriptParser from the outside is discouraged, as this method is only meant to be used internally.',
+    ];
 
     /**
      * TypoScript hierarchy being build during parsing.
      *
      * @var array
      */
-    public $setup = array();
+    public $setup = [];
 
     /**
      * Raw data, the input string exploded by LF
      *
      * @var array
      */
-    public $raw;
+    protected $raw;
 
     /**
      * Pointer to entry in raw data array
      *
      * @var int
      */
-    public $rawP;
+    protected $rawP;
 
     /**
      * Holding the value of the last comment
      *
      * @var string
      */
-    public $lastComment = '';
+    protected $lastComment = '';
 
     /**
      * Internally set, used as internal flag to create a multi-line comment (one of those like /* ... * /
      *
      * @var bool
      */
-    public $commentSet = false;
+    protected $commentSet = false;
 
     /**
      * Internally set, when multiline value is accumulated
      *
      * @var bool
      */
-    public $multiLineEnabled = false;
+    protected $multiLineEnabled = false;
 
     /**
      * Internally set, when multiline value is accumulated
      *
      * @var string
      */
-    public $multiLineObject = '';
+    protected $multiLineObject = '';
 
     /**
      * Internally set, when multiline value is accumulated
      *
      * @var array
      */
-    public $multiLineValue = array();
+    protected $multiLineValue = [];
 
     /**
      * Internally set, when in brace. Counter.
      *
      * @var int
      */
-    public $inBrace = 0;
+    protected $inBrace = 0;
 
     /**
      * For each condition this flag is set, if the condition is TRUE,
@@ -103,42 +135,42 @@ class TypoScriptParser
      *
      * @var bool
      */
-    public $lastConditionTrue = true;
+    protected $lastConditionTrue = true;
 
     /**
      * Tracking all conditions found
      *
      * @var array
      */
-    public $sections = array();
+    public $sections = [];
 
     /**
      * Tracking all matching conditions found
      *
      * @var array
      */
-    public $sectionsMatch = array();
+    public $sectionsMatch = [];
 
     /**
      * If set, then syntax highlight mode is on; Call the function syntaxHighlight() to use this function
      *
      * @var bool
      */
-    public $syntaxHighLight = false;
+    protected $syntaxHighLight = false;
 
     /**
      * Syntax highlight data is accumulated in this array. Used by syntaxHighlight_print() to construct the output.
      *
      * @var array
      */
-    public $highLightData = array();
+    protected $highLightData = [];
 
     /**
      * Syntax highlight data keeping track of the curly brace level for each line
      *
      * @var array
      */
-    public $highLightData_bracelevel = array();
+    protected $highLightData_bracelevel = [];
 
     /**
      * DO NOT register the comments. This is default for the ordinary sitetemplate!
@@ -159,7 +191,7 @@ class TypoScriptParser
      *
      * @var array
      */
-    public $errors = array();
+    public $errors = [];
 
     /**
      * Used for the error messages line number reporting. Set externally.
@@ -178,49 +210,49 @@ class TypoScriptParser
     /**
      * @var array
      */
-    public $highLightStyles = array(
-        'prespace' => array('<span class="ts-prespace">', '</span>'),
+    protected $highLightStyles = [
+        'prespace' => ['<span class="ts-prespace">', '</span>'],
         // Space before any content on a line
-        'objstr_postspace' => array('<span class="ts-objstr_postspace">', '</span>'),
+        'objstr_postspace' => ['<span class="ts-objstr_postspace">', '</span>'],
         // Space after the object string on a line
-        'operator_postspace' => array('<span class="ts-operator_postspace">', '</span>'),
+        'operator_postspace' => ['<span class="ts-operator_postspace">', '</span>'],
         // Space after the operator on a line
-        'operator' => array('<span class="ts-operator">', '</span>'),
+        'operator' => ['<span class="ts-operator">', '</span>'],
         // The operator char
-        'value' => array('<span class="ts-value">', '</span>'),
+        'value' => ['<span class="ts-value">', '</span>'],
         // The value of a line
-        'objstr' => array('<span class="ts-objstr">', '</span>'),
+        'objstr' => ['<span class="ts-objstr">', '</span>'],
         // The object string of a line
-        'value_copy' => array('<span class="ts-value_copy">', '</span>'),
+        'value_copy' => ['<span class="ts-value_copy">', '</span>'],
         // The value when the copy syntax (<) is used; that means the object reference
-        'value_unset' => array('<span class="ts-value_unset">', '</span>'),
+        'value_unset' => ['<span class="ts-value_unset">', '</span>'],
         // The value when an object is unset. Should not exist.
-        'ignored' => array('<span class="ts-ignored">', '</span>'),
+        'ignored' => ['<span class="ts-ignored">', '</span>'],
         // The "rest" of a line which will be ignored.
-        'default' => array('<span class="ts-default">', '</span>'),
+        'default' => ['<span class="ts-default">', '</span>'],
         // The default style if none other is applied.
-        'comment' => array('<span class="ts-comment">', '</span>'),
+        'comment' => ['<span class="ts-comment">', '</span>'],
         // Comment lines
-        'condition' => array('<span class="ts-condition">', '</span>'),
+        'condition' => ['<span class="ts-condition">', '</span>'],
         // Conditions
-        'error' => array('<span class="ts-error">', '</span>'),
+        'error' => ['<span class="ts-error">', '</span>'],
         // Error messages
-        'linenum' => array('<span class="ts-linenum">', '</span>')
-    );
+        'linenum' => ['<span class="ts-linenum">', '</span>']
+    ];
 
     /**
      * Additional attributes for the <span> tags for a blockmode line
      *
      * @var string
      */
-    public $highLightBlockStyles = '';
+    protected $highLightBlockStyles = '';
 
     /**
      * The hex-HTML color for the blockmode
      *
      * @var string
      */
-    public $highLightBlockStyles_basecolor = '#cccccc';
+    protected $highLightBlockStyles_basecolor = '#cccccc';
 
     /**
      * @var \TYPO3\CMS\Core\TypoScript\ExtendedTemplateService
@@ -232,8 +264,6 @@ class TypoScriptParser
      *
      * @param string $string The TypoScript text
      * @param object|string $matchObj If is object, then this is used to match conditions found in the TypoScript code. If matchObj not specified, then no conditions will work! (Except [GLOBAL])
-     *
-     * @return void
      */
     public function parse($string, $matchObj = '')
     {
@@ -242,7 +272,11 @@ class TypoScriptParser
         $pre = '[GLOBAL]';
         while ($pre) {
             if ($this->breakPointLN && $pre === '[_BREAK]') {
-                $this->error('Breakpoint at ' . ($this->lineNumberOffset + $this->rawP - 2) . ': Line content was "' . $this->raw[($this->rawP - 2)] . '"', 1);
+                $this->error('Breakpoint at ' . ($this->lineNumberOffset + $this->rawP - 2) . ': Line content was "' . $this->raw[$this->rawP - 2] . '"', 1);
+                break;
+            }
+            if ($pre === '[]') {
+                $this->error('Empty condition is always false, this does not make sense. At line ' . ($this->lineNumberOffset + $this->rawP - 1), 2);
                 break;
             }
             $preUppercase = strtoupper($pre);
@@ -252,7 +286,7 @@ class TypoScriptParser
                     !$this->lastConditionTrue && $preUppercase === '[ELSE]')
             ) {
                 $pre = trim($this->parseSub($this->setup));
-                $this->lastConditionTrue = 1;
+                $this->lastConditionTrue = true;
             } else {
                 // We're in a specific section. Therefore we log this section
                 $specificSection = $preUppercase !== '[ELSE]';
@@ -264,10 +298,10 @@ class TypoScriptParser
                         $this->sectionsMatch[md5($pre)] = $pre;
                     }
                     $pre = trim($this->parseSub($this->setup));
-                    $this->lastConditionTrue = 1;
+                    $this->lastConditionTrue = true;
                 } else {
                     $pre = $this->nextDivider();
-                    $this->lastConditionTrue = 0;
+                    $this->lastConditionTrue = false;
                 }
             }
         }
@@ -286,7 +320,7 @@ class TypoScriptParser
      * @return string The condition value
      * @see parse()
      */
-    public function nextDivider()
+    protected function nextDivider()
     {
         while (isset($this->raw[$this->rawP])) {
             $line = trim($this->raw[$this->rawP]);
@@ -302,9 +336,9 @@ class TypoScriptParser
      * Parsing the $this->raw TypoScript lines from pointer, $this->rawP
      *
      * @param array $setup Reference to the setup array in which to accumulate the values.
-     * @return string|NULL Returns the string of the condition found, the exit signal or possible nothing (if it completed parsing with no interruptions)
+     * @return string|null Returns the string of the condition found, the exit signal or possible nothing (if it completed parsing with no interruptions)
      */
-    public function parseSub(array &$setup)
+    protected function parseSub(array &$setup)
     {
         while (isset($this->raw[$this->rawP])) {
             $line = ltrim($this->raw[$this->rawP]);
@@ -320,23 +354,23 @@ class TypoScriptParser
             }
             // Set comment flag?
             if (!$this->multiLineEnabled && strpos($line, '/*') === 0) {
-                $this->commentSet = 1;
+                $this->commentSet = true;
             }
             // If $this->multiLineEnabled we will go and get the line values here because we know, the first if() will be TRUE.
             if (!$this->commentSet && ($line || $this->multiLineEnabled)) {
                 // If multiline is enabled. Escape by ')'
                 if ($this->multiLineEnabled) {
                     // Multiline ends...
-                    if ($line[0] === ')') {
+                    if (!empty($line[0]) && $line[0] === ')') {
                         if ($this->syntaxHighLight) {
                             $this->regHighLight('operator', $lineP, strlen($line) - 1);
                         }
                         // Disable multiline
-                        $this->multiLineEnabled = 0;
+                        $this->multiLineEnabled = false;
                         $theValue = implode($this->multiLineValue, LF);
                         if (strpos($this->multiLineObject, '.') !== false) {
                             // Set the value deeper.
-                            $this->setVal($this->multiLineObject, $setup, array($theValue));
+                            $this->setVal($this->multiLineObject, $setup, [$theValue]);
                         } else {
                             // Set value regularly
                             $setup[$this->multiLineObject] = $theValue;
@@ -368,12 +402,13 @@ class TypoScriptParser
                         $this->error('Line ' . ($this->lineNumberOffset + $this->rawP - 1) . ': On return to [GLOBAL] scope, the script was short of ' . $this->inBrace . ' end brace(s)', 1);
                         $this->inBrace = 0;
                         return $line;
-                    } elseif ($line[0] !== '}' && $line[0] !== '#' && $line[0] !== '/') {
+                    }
+                    if ($line[0] !== '}' && $line[0] !== '#' && $line[0] !== '/') {
                         // If not brace-end or comment
                         // Find object name string until we meet an operator
-                        $varL = strcspn($line, TAB . ' {=<>(');
+                        $varL = strcspn($line, "\t" . ' {=<>(');
                         // check for special ":=" operator
-                        if ($varL > 0 && substr($line, $varL-1, 2) === ':=') {
+                        if ($varL > 0 && substr($line, $varL - 1, 2) === ':=') {
                             --$varL;
                         }
                         // also remove tabs after the object string name
@@ -382,8 +417,8 @@ class TypoScriptParser
                             $this->regHighLight('objstr', $lineP, strlen(substr($line, $varL)));
                         }
                         if ($objStrName !== '') {
-                            $r = array();
-                            if ($this->strict && preg_match('/[^[:alnum:]_\\\\\\.:-]/i', $objStrName, $r)) {
+                            $r = [];
+                            if (preg_match('/[^[:alnum:]_\\\\\\.:-]/i', $objStrName, $r)) {
                                 $this->error('Line ' . ($this->lineNumberOffset + $this->rawP - 1) . ': Object Name String, "' . htmlspecialchars($objStrName) . '" contains invalid character "' . $r[0] . '". Must be alphanumeric or one of: "_:-\\."');
                             } else {
                                 $line = ltrim(substr($line, $varL));
@@ -398,12 +433,13 @@ class TypoScriptParser
                                     $this->error('Line ' . ($this->lineNumberOffset + $this->rawP - 1) . ': Object Name String, "' . htmlspecialchars($objStrName) . '" was not followed by any operator, =<>({');
                                 } else {
                                     // Checking for special TSparser properties (to change TS values at parsetime)
-                                    $match = array();
+                                    $match = [];
                                     if ($line[0] === ':' && preg_match('/^:=\\s*([[:alpha:]]+)\\s*\\((.*)\\).*/', $line, $match)) {
                                         $tsFunc = $match[1];
                                         $tsFuncArg = $match[2];
-                                        list($currentValue) = $this->getVal($objStrName, $setup);
-                                        $tsFuncArg = str_replace(array('\\\\', '\\n', '\\t'), array('\\', LF, TAB), $tsFuncArg);
+                                        $val = $this->getVal($objStrName, $setup);
+                                        $currentValue = $val[0] ?? null;
+                                        $tsFuncArg = str_replace(['\\\\', '\\n', '\\t'], ['\\', LF, "\t"], $tsFuncArg);
                                         $newValue = $this->executeValueModifier($tsFunc, $tsFuncArg, $currentValue);
                                         if (isset($newValue)) {
                                             $line = '= ' . $newValue;
@@ -415,7 +451,7 @@ class TypoScriptParser
                                                 $this->regHighLight('value', $lineP, strlen(ltrim(substr($line, 1))) - strlen(trim(substr($line, 1))));
                                             }
                                             if (strpos($objStrName, '.') !== false) {
-                                                $value = array();
+                                                $value = [];
                                                 $value[0] = trim(substr($line, 1));
                                                 $this->setVal($objStrName, $setup, $value);
                                             } else {
@@ -437,8 +473,8 @@ class TypoScriptParser
                                                     return $exitSig;
                                                 }
                                             } else {
-                                                if (!isset($setup[($objStrName . '.')])) {
-                                                    $setup[$objStrName . '.'] = array();
+                                                if (!isset($setup[$objStrName . '.'])) {
+                                                    $setup[$objStrName . '.'] = [];
                                                 }
                                                 $exitSig = $this->parseSub($setup[$objStrName . '.']);
                                                 if ($exitSig) {
@@ -448,8 +484,8 @@ class TypoScriptParser
                                             break;
                                         case '(':
                                             $this->multiLineObject = $objStrName;
-                                            $this->multiLineEnabled = 1;
-                                            $this->multiLineValue = array();
+                                            $this->multiLineEnabled = true;
+                                            $this->multiLineValue = [];
                                             break;
                                         case '<':
                                             if ($this->syntaxHighLight) {
@@ -461,8 +497,9 @@ class TypoScriptParser
                                             } else {
                                                 $res = $this->getVal($theVal, $this->setup);
                                             }
+                                            // unserialize(serialize(...)) may look stupid but is needed because of some reference issues.
+                                            // See forge issue #76919 and functional test hasFlakyReferences()
                                             $this->setVal($objStrName, $setup, unserialize(serialize($res)), 1);
-                                            // unserialize(serialize(...)) may look stupid but is needed because of some reference issues. See Kaspers reply to "[TYPO3-core] good question" from December 15 2005.
                                             break;
                                         case '>':
                                             if ($this->syntaxHighLight) {
@@ -498,7 +535,7 @@ class TypoScriptParser
                             $this->lastComment .= rtrim($line) . LF;
                         }
                     }
-                    if (StringUtility::beginsWith($line, '### ERROR')) {
+                    if (strpos($line, '### ERROR') === 0) {
                         $this->error(substr($line, 11));
                     }
                 }
@@ -508,8 +545,8 @@ class TypoScriptParser
                 if ($this->syntaxHighLight) {
                     $this->regHighLight('comment', $lineP);
                 }
-                if (strpos($line, '*/') === 0) {
-                    $this->commentSet = 0;
+                if (strpos($line, '*/') !== false) {
+                    $this->commentSet = false;
                 }
             }
         }
@@ -523,7 +560,7 @@ class TypoScriptParser
      * @param string $modifierName TypoScript function called
      * @param string $modifierArgument Function arguments; In case of multiple arguments, the method must split on its own
      * @param string $currentValue Current TypoScript value
-     * @return string Modification result
+     * @return string|null Modified result or null for no modification
      */
     protected function executeValueModifier($modifierName, $modifierArgument = null, $currentValue = null)
     {
@@ -539,7 +576,9 @@ class TypoScriptParser
                 $newValue = str_replace($modifierArgument, '', $currentValue);
                 break;
             case 'replaceString':
-                list($fromStr, $toStr) = explode('|', $modifierArgument, 2);
+                $modifierArgumentArray = explode('|', $modifierArgument, 2);
+                $fromStr = $modifierArgumentArray[0] ?? '';
+                $toStr = $modifierArgumentArray[1] ?? '';
                 $newValue = str_replace($fromStr, $toStr, $currentValue);
                 break;
             case 'addToList':
@@ -583,18 +622,20 @@ class TypoScriptParser
                 }
                 $newValue = implode(',', $elements);
                 break;
+            case 'getEnv':
+                $environmentValue = getenv(trim($modifierArgument));
+                if ($environmentValue !== false) {
+                    $newValue = $environmentValue;
+                }
+                break;
             default:
                 if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsparser.php']['preParseFunc'][$modifierName])) {
                     $hookMethod = $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsparser.php']['preParseFunc'][$modifierName];
-                    $params = array('currentValue' => $currentValue, 'functionArgument' => $modifierArgument);
+                    $params = ['currentValue' => $currentValue, 'functionArgument' => $modifierArgument];
                     $fakeThis = false;
                     $newValue = GeneralUtility::callUserFunction($hookMethod, $params, $fakeThis);
                 } else {
-                    GeneralUtility::sysLog(
-                        'Missing function definition for ' . $modifierName . ' on TypoScript',
-                        'core',
-                        GeneralUtility::SYSLOG_SEVERITY_WARNING
-                    );
+                    self::getLogger()->warning('Missing function definition for ' . $modifierName . ' on TypoScript');
                 }
         }
         return $newValue;
@@ -609,7 +650,7 @@ class TypoScriptParser
      * @return string Returns the exitSignal
      * @see parseSub()
      */
-    public function rollParseSub($string, array &$setup)
+    protected function rollParseSub($string, array &$setup)
     {
         if ((string)$string === '') {
             return '';
@@ -618,7 +659,7 @@ class TypoScriptParser
         list($key, $remainingKey) = $this->parseNextKeySegment($string);
         $key .= '.';
         if (!isset($setup[$key])) {
-            $setup[$key] = array();
+            $setup[$key] = [];
         }
         $exitSig = $remainingKey === ''
             ? $this->parseSub($setup[$key])
@@ -637,13 +678,13 @@ class TypoScriptParser
     public function getVal($string, $setup)
     {
         if ((string)$string === '') {
-            return array();
+            return [];
         }
 
         list($key, $remainingKey) = $this->parseNextKeySegment($string);
         $subKey = $key . '.';
         if ($remainingKey === '') {
-            $retArr = array();
+            $retArr = [];
             if (isset($setup[$key])) {
                 $retArr[0] = $setup[$key];
             }
@@ -651,12 +692,12 @@ class TypoScriptParser
                 $retArr[1] = $setup[$subKey];
             }
             return $retArr;
-        } else {
-            if ($setup[$subKey]) {
-                return $this->getVal($remainingKey, $setup[$subKey]);
-            }
         }
-        return array();
+        if ($setup[$subKey]) {
+            return $this->getVal($remainingKey, $setup[$subKey]);
+        }
+
+        return [];
     }
 
     /**
@@ -666,9 +707,8 @@ class TypoScriptParser
      * @param array $setup The local setup array from the function calling this function.
      * @param array|string $value The value/property pair array to set. If only one of them is set, then the other is not touched (unless $wipeOut is set, which it is when copies are made which must include both value and property)
      * @param bool $wipeOut If set, then both value and property is wiped out when a copy is made of another value.
-     * @return void
      */
-    public function setVal($string, array &$setup, $value, $wipeOut = false)
+    protected function setVal($string, array &$setup, $value, $wipeOut = false)
     {
         if ((string)$string === '') {
             return;
@@ -685,7 +725,7 @@ class TypoScriptParser
                 }
             } else {
                 $lnRegisDone = 0;
-                if ($wipeOut && $this->strict) {
+                if ($wipeOut) {
                     unset($setup[$key]);
                     unset($setup[$subKey]);
                     if ($this->regLinenumbers) {
@@ -708,7 +748,7 @@ class TypoScriptParser
             }
         } else {
             if (!isset($setup[$subKey])) {
-                $setup[$subKey] = array();
+                $setup[$subKey] = [];
             }
             $this->setVal($remainingKey, $setup[$subKey], $value);
         }
@@ -730,7 +770,7 @@ class TypoScriptParser
         // if no dot is in the key, nothing to do
         $dotPosition = strpos($key, '.');
         if ($dotPosition === false) {
-            return array($key, '');
+            return [$key, ''];
         }
 
         if (strpos($key, '\\') !== false) {
@@ -763,7 +803,7 @@ class TypoScriptParser
             // no backslash in the key, we're fine off
             list($keySegment, $remainingKey) = explode('.', $key, 2);
         }
-        return array($keySegment, $remainingKey);
+        return [$keySegment, $remainingKey];
     }
 
     /**
@@ -771,16 +811,15 @@ class TypoScriptParser
      * If "TT" is a global object (as it is in the frontend when backend users are logged in) the message will be registered here as well.
      *
      * @param string $err The error message string
-     * @param int $num The error severity (in the scale of $GLOBALS['TT']->setTSlogMessage: Approx: 2=warning, 1=info, 0=nothing, 3=fatal.)
-     * @return void
+     * @param int $num The error severity (in the scale of TimeTracker::setTSlogMessage: Approx: 2=warning, 1=info, 0=nothing, 3=fatal.)
      */
-    public function error($err, $num = 2)
+    protected function error($err, $num = 2)
     {
         $tt = $this->getTimeTracker();
         if ($tt !== null) {
             $tt->setTSlogMessage($err, $num);
         }
-        $this->errors[] = array($err, $num, $this->rawP - 1, $this->lineNumberOffset);
+        $this->errors[] = [$err, $num, $this->rawP - 1, $this->lineNumberOffset];
     }
 
     /**
@@ -791,19 +830,19 @@ class TypoScriptParser
      * @param int $cycle_counter Counter for detecting endless loops
      * @param bool $returnFiles When set an array containing the resulting typoscript and all included files will get returned
      * @param string $parentFilenameOrPath The parent file (with absolute path) or path for relative includes
-     * @return string Complete TypoScript with includes added.
+     * @return string|array Complete TypoScript with includes added.
      * @static
      */
     public static function checkIncludeLines($string, $cycle_counter = 1, $returnFiles = false, $parentFilenameOrPath = '')
     {
-        $includedFiles = array();
+        $includedFiles = [];
         if ($cycle_counter > 100) {
-            GeneralUtility::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "&lt;INCLUDE_TYPOSCRIPT: ..." tags', 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
+            self::getLogger()->warning('It appears like TypoScript code is looping over itself. Check your templates for "<INCLUDE_TYPOSCRIPT: ..." tags');
             if ($returnFiles) {
-                return array(
+                return [
                     'typoscript' => '',
                     'files' => $includedFiles
-                );
+                ];
             }
             return '
 ###
@@ -812,6 +851,13 @@ class TypoScriptParser
 ';
         }
 
+        if ($string !== null) {
+            $string = StringUtility::removeByteOrderMark($string);
+        }
+
+        // Checking for @import syntax imported files
+        $string = self::addImportsFromExternalFiles($string, $cycle_counter, $returnFiles, $includedFiles, $parentFilenameOrPath);
+
         // If no tags found, no need to do slower preg_split
         if (strpos($string, '<INCLUDE_TYPOSCRIPT:') !== false) {
             $splitRegEx = '/\r?\n\s*<INCLUDE_TYPOSCRIPT:\s*(?i)source\s*=\s*"((?i)file|dir):\s*([^"]*)"(.*)>[\ \t]*/';
@@ -840,10 +886,18 @@ class TypoScriptParser
                     if ($condition[0] !== '[') {
                         $condition = '[' . $condition . ']';
                     }
-                    /** @var ConditionMatcher $conditionMatcher */
-                    $conditionMatcher = GeneralUtility::makeInstance(ConditionMatcher::class);
-                    // If it didn't match then proceed to the next include
+
+                    /** @var AbstractConditionMatcher $conditionMatcher */
+                    $conditionMatcher = null;
+                    if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_FE) {
+                        $conditionMatcher = GeneralUtility::makeInstance(FrontendConditionMatcher::class);
+                    } else {
+                        $conditionMatcher = GeneralUtility::makeInstance(BackendConditionMatcher::class);
+                    }
+
+                    // If it didn't match then proceed to the next include, but prepend next normal (not file) part to output string
                     if (!$conditionMatcher->match($condition)) {
+                        $newString .= $tsContentsTillNextInclude . LF;
                         continue;
                     }
                 }
@@ -875,16 +929,15 @@ class TypoScriptParser
                 $newString .= $tsContentsTillNextInclude . LF;
 
                 // load default TypoScript for content rendering templates like
-                // css_styled_content if those have been included through f.e.
-                // <INCLUDE_TYPOSCRIPT: source="FILE:EXT:css_styled_content/static/setup.txt">
-                $filePointer = strtolower($filename);
-                if (StringUtility::beginsWith($filePointer, 'ext:')) {
-                    $filePointerPathParts = explode('/', substr($filePointer, 4));
+                // fluid_styled_content if those have been included through f.e.
+                // <INCLUDE_TYPOSCRIPT: source="FILE:EXT:fluid_styled_content/Configuration/TypoScript/setup.typoscript">
+                if (strpos(strtolower($filename), 'ext:') === 0) {
+                    $filePointerPathParts = explode('/', substr($filename, 4));
 
                     // remove file part, determine whether to load setup or constants
                     list($includeType, ) = explode('.', array_pop($filePointerPathParts));
 
-                    if (in_array($includeType, array('setup', 'constants'))) {
+                    if (in_array($includeType, ['setup', 'constants'])) {
                         // adapt extension key to required format (no underscores)
                         $filePointerPathParts[0] = str_replace('_', '', $filePointerPathParts[0]);
 
@@ -902,15 +955,151 @@ class TypoScriptParser
         // When all included files should get returned, simply return an compound array containing
         // the TypoScript with all "includes" processed and the files which got included
         if ($returnFiles) {
-            return array(
+            return [
                 'typoscript' => $string,
                 'files' => $includedFiles
-            );
+            ];
         }
         return $string;
     }
 
     /**
+     * Splits the unparsed TypoScript content into @import statements
+     *
+     * @param string $typoScript unparsed TypoScript
+     * @param int $cycleCounter counter to stop recursion
+     * @param bool $returnFiles whether to populate the included Files or not
+     * @param array $includedFiles - by reference - if any included files are added, they are added here
+     * @param string $parentFilenameOrPath the current imported file to resolve relative paths - handled by reference
+     * @return string the unparsed TypoScript with included external files
+     */
+    protected static function addImportsFromExternalFiles($typoScript, $cycleCounter, $returnFiles, &$includedFiles, &$parentFilenameOrPath)
+    {
+        // Check for new syntax "@import 'EXT:bennilove/Configuration/TypoScript/*'"
+        if (strpos($typoScript, '@import \'') !== false || strpos($typoScript, '@import "') !== false) {
+            $splitRegEx = '/\r?\n\s*@import\s[\'"]([^\'"]*)[\'"][\ \t]?/';
+            $parts = preg_split($splitRegEx, LF . $typoScript . LF, -1, PREG_SPLIT_DELIM_CAPTURE);
+            // First text part goes through
+            $newString = $parts[0] . LF;
+            $partCount = count($parts);
+            for ($i = 1; $i + 2 <= $partCount; $i += 2) {
+                $filename = $parts[$i];
+                $tsContentsTillNextInclude = $parts[$i + 1];
+                // Resolve a possible relative paths if a parent file is given
+                if ($parentFilenameOrPath !== '' && $filename[0] === '.') {
+                    $filename = PathUtility::getAbsolutePathOfRelativeReferencedFileOrPath($parentFilenameOrPath, $filename);
+                }
+                $newString .= self::importExternalTypoScriptFile($filename, $cycleCounter, $returnFiles, $includedFiles);
+                // Prepend next normal (not file) part to output string
+                $newString .= $tsContentsTillNextInclude;
+            }
+            // Add a line break before and after the included code in order to make sure that the parser always has a LF.
+            $typoScript = LF . trim($newString) . LF;
+        }
+        return $typoScript;
+    }
+
+    /**
+     * Include file $filename. Contents of the file will be returned, filename is added to &$includedFiles.
+     * Further include/import statements in the contents are processed recursively.
+     *
+     * @param string $filename Full absolute path+filename to the typoscript file to be included
+     * @param int $cycleCounter Counter for detecting endless loops
+     * @param bool $returnFiles When set, filenames of included files will be prepended to the array &$includedFiles
+     * @param array &$includedFiles Array to which the filenames of included files will be prepended (referenced)
+     * @return string the unparsed TypoScript content from external files
+     */
+    protected static function importExternalTypoScriptFile($filename, $cycleCounter, $returnFiles, array &$includedFiles)
+    {
+        if (strpos('..', $filename) !== false) {
+            return self::typoscriptIncludeError('Invalid filepath "' . $filename . '" (containing "..").');
+        }
+
+        $content = '';
+        $absoluteFileName = GeneralUtility::getFileAbsFileName($filename);
+        if ((string)$absoluteFileName === '') {
+            return self::typoscriptIncludeError('Illegal filepath "' . $filename . '".');
+        }
+
+        $finder = new Finder();
+        $finder
+            // no recursive mode on purpose
+            ->depth(0)
+            // no directories should be fetched
+            ->files()
+            ->sortByName();
+
+        // Search all files in the folder
+        if (is_dir($absoluteFileName)) {
+            $finder->in($absoluteFileName);
+            // Used for the TypoScript comments
+            $readableFilePrefix = $filename;
+        } else {
+            try {
+                // Apparently this is not a folder, so the restriction
+                // is the folder so we restrict into this folder
+                $finder->in(PathUtility::dirname($absoluteFileName));
+                if (!is_file($absoluteFileName)
+                    && strpos(PathUtility::basename($absoluteFileName), '*') === false
+                    && substr(PathUtility::basename($absoluteFileName), -11) !== '.typoscript') {
+                    $absoluteFileName .= '*.typoscript';
+                }
+                $finder->name(PathUtility::basename($absoluteFileName));
+                $readableFilePrefix = PathUtility::dirname($filename);
+            } catch (\InvalidArgumentException $e) {
+                return self::typoscriptIncludeError($e->getMessage());
+            }
+        }
+
+        foreach ($finder as $fileObject) {
+            // Clean filename output for comments
+            $readableFileName = rtrim($readableFilePrefix, '/') . '/' . $fileObject->getFilename();
+            $content .= LF . '### @import \'' . $readableFileName . '\' begin ###' . LF;
+            // Check for allowed files
+            if (!GeneralUtility::verifyFilenameAgainstDenyPattern($fileObject->getFilename())) {
+                $content .= self::typoscriptIncludeError('File "' . $readableFileName . '" was not included since it is not allowed due to fileDenyPattern.');
+            } else {
+                $includedFiles[] = $fileObject->getPathname();
+                // check for includes in included text
+                $included_text = self::checkIncludeLines($fileObject->getContents(), $cycleCounter++, $returnFiles, $absoluteFileName);
+                // If the method also has to return all included files, merge currently included
+                // files with files included by recursively calling itself
+                if ($returnFiles && is_array($included_text)) {
+                    $includedFiles = array_merge($includedFiles, $included_text['files']);
+                    $included_text = $included_text['typoscript'];
+                }
+                $content .= $included_text . LF;
+            }
+            $content .= '### @import \'' . $readableFileName . '\' end ###' . LF . LF;
+
+            // load default TypoScript for content rendering templates like
+            // fluid_styled_content if those have been included through e.g.
+            // @import "fluid_styled_content/Configuration/TypoScript/setup.typoscript"
+            if (strpos(strtoupper($filename), 'EXT:') === 0) {
+                $filePointerPathParts = explode('/', substr($filename, 4));
+                // remove file part, determine whether to load setup or constants
+                list($includeType) = explode('.', array_pop($filePointerPathParts));
+
+                if (in_array($includeType, ['setup', 'constants'], true)) {
+                    // adapt extension key to required format (no underscores)
+                    $filePointerPathParts[0] = str_replace('_', '', $filePointerPathParts[0]);
+
+                    // load default TypoScript
+                    $defaultTypoScriptKey = implode('/', $filePointerPathParts) . '/';
+                    if (in_array($defaultTypoScriptKey, $GLOBALS['TYPO3_CONF_VARS']['FE']['contentRenderingTemplates'], true)) {
+                        $content .= $GLOBALS['TYPO3_CONF_VARS']['FE']['defaultTypoScript_' . $includeType . '.']['defaultContentRendering'];
+                    }
+                }
+            }
+        }
+
+        if (empty($content)) {
+            return self::typoscriptIncludeError('No file or folder found for importing TypoScript on "' . $filename . '".');
+        }
+        return $content;
+    }
+
+    /**
      * Include file $filename. Contents of the file will be prepended to &$newstring, filename to &$includedFiles
      * Further include_typoscript tags in the contents are processed recursively
      *
@@ -922,8 +1111,9 @@ class TypoScriptParser
      * @param string $optionalProperties
      * @param string $parentFilenameOrPath The parent file (with absolute path) or path for relative includes
      * @static
+     * @internal
      */
-    public static function includeFile($filename, $cycle_counter = 1, $returnFiles = false, &$newString = '', array &$includedFiles = array(), $optionalProperties = '', $parentFilenameOrPath = '')
+    public static function includeFile($filename, $cycle_counter = 1, $returnFiles = false, &$newString = '', array &$includedFiles = [], $optionalProperties = '', $parentFilenameOrPath = '')
     {
         // Resolve a possible relative paths if a parent file is given
         if ($parentFilenameOrPath !== '' && $filename[0] === '.') {
@@ -939,19 +1129,36 @@ class TypoScriptParser
             // Check for allowed files
             if (!GeneralUtility::verifyFilenameAgainstDenyPattern($absfilename)) {
                 $newString .= self::typoscriptIncludeError('File "' . $filename . '" was not included since it is not allowed due to fileDenyPattern.');
-            } elseif (!@file_exists($absfilename)) {
-                $newString .= self::typoscriptIncludeError('File "' . $filename . '" was not found.');
             } else {
-                $includedFiles[] = $absfilename;
-                // check for includes in included text
-                $included_text = self::checkIncludeLines(GeneralUtility::getUrl($absfilename), $cycle_counter + 1, $returnFiles, $absfilename);
-                // If the method also has to return all included files, merge currently included
-                // files with files included by recursively calling itself
-                if ($returnFiles && is_array($included_text)) {
-                    $includedFiles = array_merge($includedFiles, $included_text['files']);
-                    $included_text = $included_text['typoscript'];
+                $fileExists = false;
+                if (@file_exists($absfilename)) {
+                    $fileExists = true;
+                } else {
+                    // BC layer after renaming core TypoScript files from .txt to .typoscript
+                    if (substr($absfilename, -4, 4) === '.txt') {
+                        $absfilename = substr($absfilename, 0, -4) . '.typoscript';
+                        if (@file_exists($absfilename)) {
+                            trigger_error('The TypoScript file ' . $filename . ' was renamed to .typoscript extension.'
+                                . ' Update your "<INCLUDE_TYPOSCRIPT" statements.', E_USER_DEPRECATED);
+                            $fileExists = true;
+                        }
+                    }
+                }
+
+                if ($fileExists) {
+                    $includedFiles[] = $absfilename;
+                    // check for includes in included text
+                    $included_text = self::checkIncludeLines(file_get_contents($absfilename), $cycle_counter + 1, $returnFiles, $absfilename);
+                    // If the method also has to return all included files, merge currently included
+                    // files with files included by recursively calling itself
+                    if ($returnFiles && is_array($included_text)) {
+                        $includedFiles = array_merge($includedFiles, $included_text['files']);
+                        $included_text = $included_text['typoscript'];
+                    }
+                    $newString .= $included_text . LF;
+                } else {
+                    $newString .= self::typoscriptIncludeError('File "' . $filename . '" was not found.');
                 }
-                $newString .= $included_text . LF;
             }
         }
         $newString .= '### <INCLUDE_TYPOSCRIPT: source="FILE:' . $filename . '"' . $optionalProperties . '> END:' . LF . LF;
@@ -972,7 +1179,7 @@ class TypoScriptParser
      * @param string $parentFilenameOrPath The parent file (with absolute path) or path for relative includes
      * @static
      */
-    protected static function includeDirectory($dirPath, $cycle_counter = 1, $returnFiles = false, &$newString = '', array &$includedFiles = array(), $optionalProperties = '', $parentFilenameOrPath = '')
+    protected static function includeDirectory($dirPath, $cycle_counter = 1, $returnFiles = false, &$newString = '', array &$includedFiles = [], $optionalProperties = '', $parentFilenameOrPath = '')
     {
         // Extract the value of the property extensions="..."
         $matches = preg_split('#(?i)extensions\s*=\s*"([^"]*)"(\s*|>)#', $optionalProperties, 2, PREG_SPLIT_DELIM_CAPTURE);
@@ -993,9 +1200,9 @@ class TypoScriptParser
             $absDirPath = rtrim($absDirPath, '/') . '/';
             $newString .= LF . '### <INCLUDE_TYPOSCRIPT: source="DIR:' . $dirPath . '"' . $optionalProperties . '> BEGIN:' . LF;
             // Get alphabetically sorted file index in array
-            $fileIndex = GeneralUtility::getAllFilesAndFoldersInPath(array(), $absDirPath, $includedFileExtensions);
+            $fileIndex = GeneralUtility::getAllFilesAndFoldersInPath([], $absDirPath, $includedFileExtensions);
             // Prepend file contents to $newString
-            $prefixLength = strlen(PATH_site);
+            $prefixLength = strlen(Environment::getPublicPath() . '/');
             foreach ($fileIndex as $absFileRef) {
                 $relFileRef = substr($absFileRef, $prefixLength);
                 self::includeFile($relFileRef, $cycle_counter, $returnFiles, $newString, $includedFiles, '', $absDirPath);
@@ -1008,7 +1215,7 @@ class TypoScriptParser
 
     /**
      * Process errors in INCLUDE_TYPOSCRIPT tags
-     * Errors are logged in sysLog and printed in the concatenated Typoscript result (as can be seen in Template Analyzer)
+     * Errors are logged and printed in the concatenated TypoScript result (as can be seen in Template Analyzer)
      *
      * @param string $error Text of the error message
      * @return string The error message encapsulated in comments
@@ -1016,7 +1223,7 @@ class TypoScriptParser
      */
     protected static function typoscriptIncludeError($error)
     {
-        GeneralUtility::sysLog($error, 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
+        self::getLogger()->warning($error);
         return "\n###\n### ERROR: " . $error . "\n###\n\n";
     }
 
@@ -1046,11 +1253,12 @@ class TypoScriptParser
      * @throws \RuntimeException
      * @throws \UnexpectedValueException
      * @return string Template content with uncommented include statements
+     * @internal
      */
-    public static function extractIncludes($string, $cycle_counter = 1, array $extractedFileNames = array(), $parentFilenameOrPath = '')
+    public static function extractIncludes($string, $cycle_counter = 1, array $extractedFileNames = [], $parentFilenameOrPath = '')
     {
         if ($cycle_counter > 10) {
-            GeneralUtility::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "&lt;INCLUDE_TYPOSCRIPT: ..." tags', 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
+            self::getLogger()->warning('It appears like TypoScript code is looping over itself. Check your templates for "<INCLUDE_TYPOSCRIPT: ..." tags');
             return '
 ###
 ### ERROR: Recursion!
@@ -1058,8 +1266,8 @@ class TypoScriptParser
 ';
         }
         $expectedEndTag = '';
-        $fileContent = array();
-        $restContent = array();
+        $fileContent = [];
+        $restContent = [];
         $fileName = null;
         $inIncludePart = false;
         $lines = preg_split("/\r\n|\n|\r/", $string);
@@ -1098,7 +1306,6 @@ class TypoScriptParser
                     // If this is not a beginning commented include statement this line goes into the rest content
                     $restContent[] = $line;
                 }
-                //if (is_array($matches)) GeneralUtility::devLog('matches', 'TypoScriptParser', 0, $matches);
             } else {
                 // Inside commented include statements
                 // Search for the matching ending commented include statement
@@ -1167,7 +1374,7 @@ class TypoScriptParser
                     }
 
                     // Reset variables (preparing for the next commented include statement)
-                    $fileContent = array();
+                    $fileContent = [];
                     $fileName = null;
                     $inIncludePart = false;
                     $openingCommentedIncludeStatement = null;
@@ -1219,9 +1426,9 @@ class TypoScriptParser
      */
     public function doSyntaxHighlight($string, $lineNum = '', $highlightBlockMode = false)
     {
-        $this->syntaxHighLight = 1;
-        $this->highLightData = array();
-        $this->errors = array();
+        $this->syntaxHighLight = true;
+        $this->highLightData = [];
+        $this->errors = [];
         // This is done in order to prevent empty <span>..</span> sections around CR content. Should not do anything but help lessen the amount of HTML code.
         $string = str_replace(CR, '', $string);
         $this->parse($string);
@@ -1234,16 +1441,14 @@ class TypoScriptParser
      * @param string $code Key from the internal array $this->highLightStyles
      * @param int $pointer Pointer to the line in $this->raw which this is about
      * @param int $strlen The number of chars LEFT on this line before the end is reached.
-     * @return void
-     * @access private
      * @see parse()
      */
-    public function regHighLight($code, $pointer, $strlen = -1)
+    protected function regHighLight($code, $pointer, $strlen = -1)
     {
         if ($strlen === -1) {
-            $this->highLightData[$pointer] = array(array($code, 0));
+            $this->highLightData[$pointer] = [[$code, 0]];
         } else {
-            $this->highLightData[$pointer][] = array($code, $strlen);
+            $this->highLightData[$pointer][] = [$code, $strlen];
         }
         $this->highLightData_bracelevel[$pointer] = $this->inBrace;
     }
@@ -1254,18 +1459,17 @@ class TypoScriptParser
      * @param mixed $lineNumDat If blank, linenumbers are NOT printed. If array then the first key is the linenumber offset to add to the internal counter.
      * @param bool $highlightBlockMode If set, then the highlighted output will be formatted in blocks based on the brace levels. prespace will be ignored and empty lines represented with a single no-break-space.
      * @return string HTML content
-     * @access private
      * @see doSyntaxHighlight()
      */
-    public function syntaxHighlight_print($lineNumDat, $highlightBlockMode)
+    protected function syntaxHighlight_print($lineNumDat, $highlightBlockMode)
     {
         // Registers all error messages in relation to their linenumber
-        $errA = array();
+        $errA = [];
         foreach ($this->errors as $err) {
             $errA[$err[2]][] = $err[0];
         }
         // Generates the syntax highlighted output:
-        $lines = array();
+        $lines = [];
         foreach ($this->raw as $rawP => $value) {
             $start = 0;
             $strlen = strlen($value);
@@ -1281,11 +1485,11 @@ class TypoScriptParser
                             $lineC .= $st[0] . htmlspecialchars($part) . $st[1];
                         }
                     } elseif ($len < 0) {
-                        debug(array($len, $value, $rawP));
+                        debug([$len, $value, $rawP]);
                     }
                 }
             } else {
-                debug(array($value));
+                debug([$value]);
             }
             if (strlen($value) > $start) {
                 $lineC .= $this->highLightStyles['ignored'][0] . htmlspecialchars(substr($value, $start)) . $this->highLightStyles['ignored'][1];
@@ -1313,10 +1517,9 @@ class TypoScriptParser
      */
     protected function getTimeTracker()
     {
-        return isset($GLOBALS['TT']) ? $GLOBALS['TT'] : null;
+        return GeneralUtility::makeInstance(TimeTracker::class);
     }
 
-
     /**
      * Modifies a HTML Hex color by adding/subtracting $R,$G and $B integers
      *
@@ -1333,7 +1536,7 @@ class TypoScriptParser
         $nR = MathUtility::forceIntegerInRange(hexdec(substr($color, 1, 2)) + $R, 0, 255);
         $nG = MathUtility::forceIntegerInRange(hexdec(substr($color, 3, 2)) + $G, 0, 255);
         $nB = MathUtility::forceIntegerInRange(hexdec(substr($color, 5, 2)) + $B, 0, 255);
-        return '#' . substr(('0' . dechex($nR)), -2) . substr(('0' . dechex($nG)), -2) . substr(('0' . dechex($nB)), -2);
+        return '#' . substr('0' . dechex($nR), -2) . substr('0' . dechex($nG), -2) . substr('0' . dechex($nB), -2);
     }
 
     /**
@@ -1348,4 +1551,17 @@ class TypoScriptParser
     {
         return $this->modifyHTMLColor($color, $all, $all, $all);
     }
+
+    /**
+     * Get a logger instance
+     *
+     * This class uses logging mostly in static functions, hence we need a static getter for the logger.
+     * Injection of a logger instance via GeneralUtility::makeInstance is not possible.
+     *
+     * @return LoggerInterface
+     */
+    protected static function getLogger()
+    {
+        return GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__);
+    }
 }