[TASK] Cleanup functionality in PackageManager.php
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Core / Bootstrap.php
1 <?php
2 namespace TYPO3\CMS\Core\Core;
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
17 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
18 use TYPO3\CMS\Core\Utility\GeneralUtility;
19 use TYPO3\CMS\Core\Utility\MathUtility;
20
21 /**
22 * This class encapsulates bootstrap related methods.
23 * It is required directly as the very first thing in entry scripts and
24 * used to define all base things like constants and pathes and so on.
25 *
26 * Most methods in this class have dependencies to each other. They can
27 * not be called in arbitrary order. The methods are ordered top down, so
28 * a method at the beginning has lower dependencies than a method further
29 * down. Do not fiddle with the load order in own scripts except you know
30 * exactly what you are doing!
31 */
32 class Bootstrap
33 {
34 /**
35 * @var \TYPO3\CMS\Core\Core\Bootstrap
36 */
37 protected static $instance = null;
38
39 /**
40 * Unique Request ID
41 *
42 * @var string
43 */
44 protected $requestId;
45
46 /**
47 * The application context
48 *
49 * @var \TYPO3\CMS\Core\Core\ApplicationContext
50 */
51 protected $applicationContext;
52
53 /**
54 * @var array List of early instances
55 */
56 protected $earlyInstances = array();
57
58 /**
59 * @var string Path to install tool
60 */
61 protected $installToolPath;
62
63 /**
64 * A list of all registered request handlers, see the Application class / entry points for the registration
65 * @var \TYPO3\CMS\Core\Http\RequestHandlerInterface[]|\TYPO3\CMS\Core\Console\RequestHandlerInterface[]
66 */
67 protected $availableRequestHandlers = array();
68
69 /**
70 * The Response object when using Request/Response logic
71 * @var \Psr\Http\Message\ResponseInterface
72 * @see shutdown()
73 */
74 protected $response;
75
76 /**
77 * @var bool
78 */
79 protected static $usesComposerClassLoading = false;
80
81 /**
82 * Disable direct creation of this object.
83 * Set unique requestId and the application context
84 *
85 * @var string Application context
86 */
87 protected function __construct($applicationContext)
88 {
89 $this->requestId = substr(md5(uniqid('', true)), 0, 13);
90 $this->applicationContext = new ApplicationContext($applicationContext);
91 }
92
93 /**
94 * @return bool
95 */
96 public static function usesComposerClassLoading()
97 {
98 return self::$usesComposerClassLoading;
99 }
100
101 /**
102 * Disable direct cloning of this object.
103 */
104 protected function __clone()
105 {
106 }
107
108 /**
109 * Return 'this' as singleton
110 *
111 * @return Bootstrap
112 * @internal This is not a public API method, do not use in own extensions
113 */
114 public static function getInstance()
115 {
116 if (is_null(static::$instance)) {
117 $applicationContext = getenv('TYPO3_CONTEXT') ?: (getenv('REDIRECT_TYPO3_CONTEXT') ?: 'Production');
118 self::$instance = new static($applicationContext);
119 self::$instance->defineTypo3RequestTypes();
120 }
121 return static::$instance;
122 }
123
124 /**
125 * Gets the request's unique ID
126 *
127 * @return string Unique request ID
128 * @internal This is not a public API method, do not use in own extensions
129 */
130 public function getRequestId()
131 {
132 return $this->requestId;
133 }
134
135 /**
136 * Returns the application context this bootstrap was started in.
137 *
138 * @return \TYPO3\CMS\Core\Core\ApplicationContext The application context encapsulated in an object
139 * @internal This is not a public API method, do not use in own extensions.
140 * Use \TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext() instead
141 */
142 public function getApplicationContext()
143 {
144 return $this->applicationContext;
145 }
146
147 /**
148 * Prevent any unwanted output that may corrupt AJAX/compression.
149 * This does not interfere with "die()" or "echo"+"exit()" messages!
150 *
151 * @return Bootstrap
152 * @internal This is not a public API method, do not use in own extensions
153 */
154 public function startOutputBuffering()
155 {
156 ob_start();
157 return $this;
158 }
159
160 /**
161 * Main entry point called at every request usually from Global scope. Checks if everything is correct,
162 * and loads the Configuration.
163 *
164 * Make sure that the baseSetup() is called before and the class loader is present
165 *
166 * @return Bootstrap
167 */
168 public function configure()
169 {
170 $this->startOutputBuffering()
171 ->loadConfigurationAndInitialize()
172 ->loadTypo3LoadedExtAndExtLocalconf(true)
173 ->setFinalCachingFrameworkCacheConfiguration()
174 ->defineLoggingAndExceptionConstants()
175 ->unsetReservedGlobalVariables()
176 ->initializeTypo3DbGlobal();
177
178 return $this;
179 }
180
181 /**
182 * Run the base setup that checks server environment, determines pathes,
183 * populates base files and sets common configuration.
184 *
185 * Script execution will be aborted if something fails here.
186 *
187 * @param string $relativePathPart Relative path of entry script back to document root
188 * @return Bootstrap
189 * @throws \RuntimeException when TYPO3_REQUESTTYPE was not set before, setRequestType() needs to be called before
190 * @internal This is not a public API method, do not use in own extensions
191 */
192 public function baseSetup($relativePathPart = '')
193 {
194 if (!defined('TYPO3_REQUESTTYPE')) {
195 throw new \RuntimeException('No Request Type was set, TYPO3 does not know in which context it is run.', 1450561838);
196 }
197 SystemEnvironmentBuilder::run($relativePathPart);
198 if (!self::$usesComposerClassLoading && ClassLoadingInformation::isClassLoadingInformationAvailable()) {
199 ClassLoadingInformation::registerClassLoadingInformation();
200 }
201 GeneralUtility::presetApplicationContext($this->applicationContext);
202 return $this;
203 }
204
205 /**
206 * Sets the class loader to the bootstrap
207 *
208 * @param \Composer\Autoload\ClassLoader $classLoader an instance of the class loader
209 * @return Bootstrap
210 * @internal This is not a public API method, do not use in own extensions
211 */
212 public function initializeClassLoader($classLoader)
213 {
214 $this->setEarlyInstance(\Composer\Autoload\ClassLoader::class, $classLoader);
215 if (defined('TYPO3_COMPOSER_MODE') && TYPO3_COMPOSER_MODE) {
216 self::$usesComposerClassLoading = true;
217 }
218 return $this;
219 }
220
221 /**
222 * checks if LocalConfiguration.php or PackageStates.php is missing,
223 * used to see if a redirect to the install tool is needed
224 *
225 * @return bool TRUE when the essential configuration is available, otherwise FALSE
226 * @internal This is not a public API method, do not use in own extensions
227 */
228 public function checkIfEssentialConfigurationExists()
229 {
230 $configurationManager = new \TYPO3\CMS\Core\Configuration\ConfigurationManager;
231 $this->setEarlyInstance(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class, $configurationManager);
232 return file_exists($configurationManager->getLocalConfigurationFileLocation()) && file_exists(PATH_typo3conf . 'PackageStates.php');
233 }
234
235 /**
236 * Redirect to install tool if LocalConfiguration.php is missing.
237 *
238 * @internal This is not a public API method, do not use in own extensions
239 */
240 public function redirectToInstallTool($relativePathPart = '')
241 {
242 $backPathToSiteRoot = str_repeat('../', count(explode('/', $relativePathPart)) - 1);
243 header('Location: ' . $backPathToSiteRoot . 'typo3/sysext/install/Start/Install.php');
244 die;
245 }
246
247 /**
248 * Adds available request handlers usually done via an application from the outside.
249 *
250 * @param string $requestHandler class which implements the request handler interface
251 * @return Bootstrap
252 * @internal This is not a public API method, do not use in own extensions
253 */
254 public function registerRequestHandlerImplementation($requestHandler)
255 {
256 $this->availableRequestHandlers[] = $requestHandler;
257 return $this;
258 }
259
260 /**
261 * Fetches the request handler that suits the best based on the priority and the interface
262 * Be sure to always have the constants that are defined in $this->defineTypo3RequestTypes() are set,
263 * so most RequestHandlers can check if they can handle the request.
264 *
265 * @param \Psr\Http\Message\ServerRequestInterface|\Symfony\Component\Console\Input\InputInterface $request
266 * @return \TYPO3\CMS\Core\Http\RequestHandlerInterface|\TYPO3\CMS\Core\Console\RequestHandlerInterface
267 * @throws \TYPO3\CMS\Core\Exception
268 * @internal This is not a public API method, do not use in own extensions
269 */
270 protected function resolveRequestHandler($request)
271 {
272 $suitableRequestHandlers = array();
273 foreach ($this->availableRequestHandlers as $requestHandlerClassName) {
274 /** @var \TYPO3\CMS\Core\Http\RequestHandlerInterface|\TYPO3\CMS\Core\Console\RequestHandlerInterface $requestHandler */
275 $requestHandler = GeneralUtility::makeInstance($requestHandlerClassName, $this);
276 if ($requestHandler->canHandleRequest($request)) {
277 $priority = $requestHandler->getPriority();
278 if (isset($suitableRequestHandlers[$priority])) {
279 throw new \TYPO3\CMS\Core\Exception('More than one request handler with the same priority can handle the request, but only one handler may be active at a time!', 1176471352);
280 }
281 $suitableRequestHandlers[$priority] = $requestHandler;
282 }
283 }
284 if (empty($suitableRequestHandlers)) {
285 throw new \TYPO3\CMS\Core\Exception('No suitable request handler found.', 1225418233);
286 }
287 ksort($suitableRequestHandlers);
288 return array_pop($suitableRequestHandlers);
289 }
290
291 /**
292 * Builds a Request instance from the current process, and then resolves the request
293 * through the request handlers depending on Frontend, Backend, CLI etc.
294 *
295 * @param \Psr\Http\Message\RequestInterface|\Symfony\Component\Console\Input\InputInterface $request
296 * @return Bootstrap
297 * @throws \TYPO3\CMS\Core\Exception
298 * @internal This is not a public API method, do not use in own extensions
299 */
300 public function handleRequest($request)
301 {
302
303 // Resolve request handler that were registered based on the Application
304 $requestHandler = $this->resolveRequestHandler($request);
305
306 // Execute the command which returns a Response object or NULL
307 $this->response = $requestHandler->handleRequest($request);
308 return $this;
309 }
310
311 /**
312 * Outputs content if there is a proper Response object.
313 *
314 * @return Bootstrap
315 */
316 protected function sendResponse()
317 {
318 if ($this->response instanceof \Psr\Http\Message\ResponseInterface) {
319 if (!headers_sent()) {
320 foreach ($this->response->getHeaders() as $name => $values) {
321 header($name . ': ' . implode(', ', $values));
322 }
323 // If the response code was not changed by legacy code (still is 200)
324 // then allow the PSR-7 response object to explicitly set it.
325 // Otherwise let legacy code take precedence.
326 // This code path can be deprecated once we expose the response object to third party code
327 if (http_response_code() === 200) {
328 header('HTTP/' . $this->response->getProtocolVersion() . ' ' . $this->response->getStatusCode() . ' ' . $this->response->getReasonPhrase());
329 }
330 }
331 echo $this->response->getBody()->__toString();
332 }
333 return $this;
334 }
335
336 /**
337 * Registers the instance of the specified object for an early boot stage.
338 * On finalizing the Object Manager initialization, all those instances will
339 * be transferred to the Object Manager's registry.
340 *
341 * @param string $objectName Object name, as later used by the Object Manager
342 * @param object $instance The instance to register
343 * @return void
344 * @internal This is not a public API method, do not use in own extensions
345 */
346 public function setEarlyInstance($objectName, $instance)
347 {
348 $this->earlyInstances[$objectName] = $instance;
349 }
350
351 /**
352 * Returns an instance which was registered earlier through setEarlyInstance()
353 *
354 * @param string $objectName Object name of the registered instance
355 * @return object
356 * @throws \TYPO3\CMS\Core\Exception
357 * @internal This is not a public API method, do not use in own extensions
358 */
359 public function getEarlyInstance($objectName)
360 {
361 if (!isset($this->earlyInstances[$objectName])) {
362 throw new \TYPO3\CMS\Core\Exception('Unknown early instance "' . $objectName . '"', 1365167380);
363 }
364 return $this->earlyInstances[$objectName];
365 }
366
367 /**
368 * Returns all registered early instances indexed by object name
369 *
370 * @return array
371 * @internal This is not a public API method, do not use in own extensions
372 */
373 public function getEarlyInstances()
374 {
375 return $this->earlyInstances;
376 }
377
378 /**
379 * Includes LocalConfiguration.php and sets several
380 * global settings depending on configuration.
381 *
382 * @param bool $allowCaching Whether to allow caching - affects cache_core (autoloader)
383 * @param string $packageManagerClassName Define an alternative package manager implementation (usually for the installer)
384 * @return Bootstrap
385 * @internal This is not a public API method, do not use in own extensions
386 */
387 public function loadConfigurationAndInitialize($allowCaching = true, $packageManagerClassName = \TYPO3\CMS\Core\Package\PackageManager::class)
388 {
389 $this->populateLocalConfiguration()
390 ->initializeErrorHandling();
391 if (!$allowCaching) {
392 $this->disableCoreCache();
393 }
394 $this->initializeCachingFramework()
395 ->initializePackageManagement($packageManagerClassName)
396 ->initializeRuntimeActivatedPackagesFromConfiguration()
397 ->defineDatabaseConstants()
398 ->defineUserAgentConstant()
399 ->registerExtDirectComponents()
400 ->setCacheHashOptions()
401 ->setDefaultTimezone()
402 ->initializeL10nLocales()
403 ->convertPageNotFoundHandlingToBoolean()
404 ->setMemoryLimit();
405 if ($allowCaching) {
406 $this->ensureClassLoadingInformationExists();
407 }
408 return $this;
409 }
410
411 /**
412 * Initializes the package system and loads the package configuration and settings
413 * provided by the packages.
414 *
415 * @param string $packageManagerClassName Define an alternative package manager implementation (usually for the installer)
416 * @return Bootstrap
417 * @internal This is not a public API method, do not use in own extensions
418 */
419 public function initializePackageManagement($packageManagerClassName)
420 {
421 /** @var \TYPO3\CMS\Core\Package\PackageManager $packageManager */
422 $packageManager = new $packageManagerClassName();
423 $this->setEarlyInstance(\TYPO3\CMS\Core\Package\PackageManager::class, $packageManager);
424 ExtensionManagementUtility::setPackageManager($packageManager);
425 $packageManager->injectCoreCache($this->getEarlyInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_core'));
426 $dependencyResolver = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Package\DependencyResolver::class);
427 $dependencyResolver->injectDependencyOrderingService(GeneralUtility::makeInstance(\TYPO3\CMS\Core\Service\DependencyOrderingService::class));
428 $packageManager->injectDependencyResolver($dependencyResolver);
429 $packageManager->initialize();
430 GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Package\PackageManager::class, $packageManager);
431 return $this;
432 }
433
434 /**
435 * Writes class loading information if not yet present
436 *
437 * @return Bootstrap
438 * @internal This is not a public API method, do not use in own extensions
439 */
440 public function ensureClassLoadingInformationExists()
441 {
442 if (!self::$usesComposerClassLoading && !ClassLoadingInformation::isClassLoadingInformationAvailable()) {
443 ClassLoadingInformation::dumpClassLoadingInformation();
444 ClassLoadingInformation::registerClassLoadingInformation();
445 }
446 return $this;
447 }
448
449 /**
450 * Activates a package during runtime. This is used in AdditionalConfiguration.php
451 * to enable extensions under conditions.
452 *
453 * @return Bootstrap
454 */
455 protected function initializeRuntimeActivatedPackagesFromConfiguration()
456 {
457 if (!empty($GLOBALS['TYPO3_CONF_VARS']['EXT']['runtimeActivatedPackages']) && is_array($GLOBALS['TYPO3_CONF_VARS']['EXT']['runtimeActivatedPackages'])) {
458 /** @var \TYPO3\CMS\Core\Package\PackageManager $packageManager */
459 $packageManager = $this->getEarlyInstance(\TYPO3\CMS\Core\Package\PackageManager::class);
460 foreach ($GLOBALS['TYPO3_CONF_VARS']['EXT']['runtimeActivatedPackages'] as $runtimeAddedPackageKey) {
461 $packageManager->activatePackageDuringRuntime($runtimeAddedPackageKey);
462 }
463 }
464 return $this;
465 }
466
467 /**
468 * Load ext_localconf of extensions
469 *
470 * @param bool $allowCaching
471 * @return Bootstrap
472 * @internal This is not a public API method, do not use in own extensions
473 */
474 public function loadTypo3LoadedExtAndExtLocalconf($allowCaching = true)
475 {
476 ExtensionManagementUtility::loadExtLocalconf($allowCaching);
477 return $this;
478 }
479
480 /**
481 * We need an early instance of the configuration manager.
482 * Since makeInstance relies on the object configuration, we create it here with new instead.
483 *
484 * @return Bootstrap
485 * @internal This is not a public API method, do not use in own extensions
486 */
487 public function populateLocalConfiguration()
488 {
489 try {
490 $configurationManager = $this->getEarlyInstance(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class);
491 } catch (\TYPO3\CMS\Core\Exception $exception) {
492 $configurationManager = new \TYPO3\CMS\Core\Configuration\ConfigurationManager();
493 $this->setEarlyInstance(\TYPO3\CMS\Core\Configuration\ConfigurationManager::class, $configurationManager);
494 }
495 $configurationManager->exportConfiguration();
496 return $this;
497 }
498
499 /**
500 * Set cache_core to null backend, effectively disabling eg. the cache for ext_localconf and PackageManager etc.
501 *
502 * @return \TYPO3\CMS\Core\Core\Bootstrap
503 * @internal This is not a public API method, do not use in own extensions
504 */
505 public function disableCoreCache()
506 {
507 $GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_core']['backend']
508 = \TYPO3\CMS\Core\Cache\Backend\NullBackend::class;
509 unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['cache_core']['options']);
510 return $this;
511 }
512
513 /**
514 * Define database constants
515 *
516 * @return \TYPO3\CMS\Core\Core\Bootstrap
517 */
518 protected function defineDatabaseConstants()
519 {
520 define('TYPO3_db', $GLOBALS['TYPO3_CONF_VARS']['DB']['database']);
521 define('TYPO3_db_username', $GLOBALS['TYPO3_CONF_VARS']['DB']['username']);
522 define('TYPO3_db_password', $GLOBALS['TYPO3_CONF_VARS']['DB']['password']);
523 define('TYPO3_db_host', $GLOBALS['TYPO3_CONF_VARS']['DB']['host']);
524 return $this;
525 }
526
527 /**
528 * Define user agent constant
529 *
530 * @return \TYPO3\CMS\Core\Core\Bootstrap
531 */
532 protected function defineUserAgentConstant()
533 {
534 define('TYPO3_user_agent', 'User-Agent: ' . $GLOBALS['TYPO3_CONF_VARS']['HTTP']['userAgent']);
535 return $this;
536 }
537
538 /**
539 * Register default ExtDirect components
540 *
541 * @return Bootstrap
542 */
543 protected function registerExtDirectComponents()
544 {
545 if (TYPO3_MODE === 'BE') {
546 ExtensionManagementUtility::registerExtDirectComponent(
547 'TYPO3.Components.PageTree.DataProvider',
548 \TYPO3\CMS\Backend\Tree\Pagetree\ExtdirectTreeDataProvider::class
549 );
550 ExtensionManagementUtility::registerExtDirectComponent(
551 'TYPO3.Components.PageTree.Commands',
552 \TYPO3\CMS\Backend\Tree\Pagetree\ExtdirectTreeCommands::class
553 );
554 ExtensionManagementUtility::registerExtDirectComponent(
555 'TYPO3.Components.PageTree.ContextMenuDataProvider',
556 \TYPO3\CMS\Backend\ContextMenu\Pagetree\Extdirect\ContextMenuConfiguration::class
557 );
558 ExtensionManagementUtility::registerExtDirectComponent(
559 'TYPO3.ExtDirectStateProvider.ExtDirect',
560 \TYPO3\CMS\Backend\InterfaceState\ExtDirect\DataProvider::class
561 );
562 }
563 return $this;
564 }
565
566 /**
567 * Initialize caching framework, and re-initializes it (e.g. in the install tool) by recreating the instances
568 * again despite the Singleton instance
569 *
570 * @return Bootstrap
571 * @internal This is not a public API method, do not use in own extensions
572 */
573 public function initializeCachingFramework()
574 {
575 $cacheManager = new \TYPO3\CMS\Core\Cache\CacheManager();
576 $cacheManager->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
577 GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Cache\CacheManager::class, $cacheManager);
578
579 $cacheFactory = new \TYPO3\CMS\Core\Cache\CacheFactory('production', $cacheManager);
580 GeneralUtility::setSingletonInstance(\TYPO3\CMS\Core\Cache\CacheFactory::class, $cacheFactory);
581
582 $this->setEarlyInstance(\TYPO3\CMS\Core\Cache\CacheManager::class, $cacheManager);
583 return $this;
584 }
585
586 /**
587 * Set cacheHash options
588 *
589 * @return Bootstrap
590 */
591 protected function setCacheHashOptions()
592 {
593 $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash'] = array(
594 'cachedParametersWhiteList' => GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['cHashOnlyForParameters'], true),
595 'excludedParameters' => GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['cHashExcludedParameters'], true),
596 'requireCacheHashPresenceParameters' => GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['cHashRequiredParameters'], true)
597 );
598 if (trim($GLOBALS['TYPO3_CONF_VARS']['FE']['cHashExcludedParametersIfEmpty']) === '*') {
599 $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludeAllEmptyParameters'] = true;
600 } else {
601 $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['excludedParametersIfEmpty'] = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['cHashExcludedParametersIfEmpty'], true);
602 }
603 return $this;
604 }
605
606 /**
607 * Set default timezone
608 *
609 * @return Bootstrap
610 */
611 protected function setDefaultTimezone()
612 {
613 $timeZone = $GLOBALS['TYPO3_CONF_VARS']['SYS']['phpTimeZone'];
614 if (empty($timeZone)) {
615 // Time zone from the server environment (TZ env or OS query)
616 $defaultTimeZone = @date_default_timezone_get();
617 if ($defaultTimeZone !== '') {
618 $timeZone = $defaultTimeZone;
619 } else {
620 $timeZone = 'UTC';
621 }
622 }
623 // Set default to avoid E_WARNINGs with PHP > 5.3
624 date_default_timezone_set($timeZone);
625 return $this;
626 }
627
628 /**
629 * Initialize the locales handled by TYPO3
630 *
631 * @return Bootstrap
632 */
633 protected function initializeL10nLocales()
634 {
635 \TYPO3\CMS\Core\Localization\Locales::initialize();
636 return $this;
637 }
638
639 /**
640 * Convert type of "pageNotFound_handling" setting in case it was written as a
641 * string (e.g. if edited in Install Tool)
642 *
643 * @TODO : Remove, if the Install Tool handles such data types correctly
644 * @return Bootstrap
645 */
646 protected function convertPageNotFoundHandlingToBoolean()
647 {
648 if (!strcasecmp($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'], 'TRUE')) {
649 $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'] = true;
650 }
651 return $this;
652 }
653
654 /**
655 * Configure and set up exception and error handling
656 *
657 * @return Bootstrap
658 * @throws \RuntimeException
659 */
660 protected function initializeErrorHandling()
661 {
662 $productionExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['productionExceptionHandler'];
663 $debugExceptionHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['debugExceptionHandler'];
664
665 $errorHandlerClassName = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandler'];
666 $errorHandlerErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['errorHandlerErrors'];
667 $exceptionalErrors = $GLOBALS['TYPO3_CONF_VARS']['SYS']['exceptionalErrors'];
668
669 $displayErrorsSetting = (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['displayErrors'];
670 switch ($displayErrorsSetting) {
671 case -1:
672 $ipMatchesDevelopmentSystem = GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']);
673 $exceptionHandlerClassName = $ipMatchesDevelopmentSystem ? $debugExceptionHandlerClassName : $productionExceptionHandlerClassName;
674 $displayErrors = $ipMatchesDevelopmentSystem ? 1 : 0;
675 $exceptionalErrors = $ipMatchesDevelopmentSystem ? $exceptionalErrors : 0;
676 break;
677 case 0:
678 $exceptionHandlerClassName = $productionExceptionHandlerClassName;
679 $displayErrors = 0;
680 break;
681 case 1:
682 $exceptionHandlerClassName = $debugExceptionHandlerClassName;
683 $displayErrors = 1;
684 break;
685 default:
686 // Throw exception if an invalid option is set.
687 throw new \RuntimeException('The option $TYPO3_CONF_VARS[SYS][displayErrors] is not set to "-1", "0" or "1".');
688 }
689 @ini_set('display_errors', $displayErrors);
690
691 if (!empty($errorHandlerClassName)) {
692 // Register an error handler for the given errorHandlerError
693 $errorHandler = GeneralUtility::makeInstance($errorHandlerClassName, $errorHandlerErrors);
694 $errorHandler->setExceptionalErrors($exceptionalErrors);
695 if (is_callable(array($errorHandler, 'setDebugMode'))) {
696 $errorHandler->setDebugMode($displayErrors === 1);
697 }
698 }
699 if (!empty($exceptionHandlerClassName)) {
700 // Registering the exception handler is done in the constructor
701 GeneralUtility::makeInstance($exceptionHandlerClassName);
702 }
703 return $this;
704 }
705
706 /**
707 * Set PHP memory limit depending on value of
708 * $GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit']
709 *
710 * @return Bootstrap
711 */
712 protected function setMemoryLimit()
713 {
714 if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] > 16) {
715 @ini_set('memory_limit', ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['setMemoryLimit'] . 'm'));
716 }
717 return $this;
718 }
719
720 /**
721 * Define TYPO3_REQUESTTYPE* constants that can be used for developers to see if any context has been hit
722 * also see setRequestType(). Is done at the very beginning so these parameters are always available.
723 *
724 * @return Bootstrap
725 */
726 protected function defineTypo3RequestTypes()
727 {
728 define('TYPO3_REQUESTTYPE_FE', 1);
729 define('TYPO3_REQUESTTYPE_BE', 2);
730 define('TYPO3_REQUESTTYPE_CLI', 4);
731 define('TYPO3_REQUESTTYPE_AJAX', 8);
732 define('TYPO3_REQUESTTYPE_INSTALL', 16);
733 }
734
735 /**
736 * Defines the TYPO3_REQUESTTYPE constant so the environment knows which context the request is running.
737 *
738 * @throws \RuntimeException if the method was already called during a request
739 * @return Bootstrap
740 */
741 public function setRequestType($requestType)
742 {
743 if (defined('TYPO3_REQUESTTYPE')) {
744 throw new \RuntimeException('TYPO3_REQUESTTYPE has already been set, cannot be called multiple times', 1450561878);
745 }
746 define('TYPO3_REQUESTTYPE', $requestType);
747 return $this;
748 }
749
750 /**
751 * Extensions may register new caches, so we set the
752 * global cache array to the manager again at this point
753 *
754 * @return Bootstrap
755 * @internal This is not a public API method, do not use in own extensions
756 */
757 public function setFinalCachingFrameworkCacheConfiguration()
758 {
759 $this->getEarlyInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->setCacheConfigurations($GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']);
760 return $this;
761 }
762
763 /**
764 * Define logging and exception constants
765 *
766 * @return Bootstrap
767 * @internal This is not a public API method, do not use in own extensions
768 */
769 public function defineLoggingAndExceptionConstants()
770 {
771 define('TYPO3_DLOG', $GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_DLOG']);
772 define('TYPO3_ERROR_DLOG', $GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_errorDLOG']);
773 define('TYPO3_EXCEPTION_DLOG', $GLOBALS['TYPO3_CONF_VARS']['SYS']['enable_exceptionDLOG']);
774 return $this;
775 }
776
777 /**
778 * Unsetting reserved global variables:
779 * Those are set in "ext:core/ext_tables.php" file:
780 *
781 * @return Bootstrap
782 * @internal This is not a public API method, do not use in own extensions
783 */
784 public function unsetReservedGlobalVariables()
785 {
786 unset($GLOBALS['PAGES_TYPES']);
787 unset($GLOBALS['TCA']);
788 unset($GLOBALS['TBE_MODULES']);
789 unset($GLOBALS['TBE_STYLES']);
790 unset($GLOBALS['BE_USER']);
791 // Those set otherwise:
792 unset($GLOBALS['TBE_MODULES_EXT']);
793 unset($GLOBALS['TCA_DESCR']);
794 unset($GLOBALS['LOCAL_LANG']);
795 return $this;
796 }
797
798 /**
799 * Initialize database connection in $GLOBALS and connect if requested
800 *
801 * @return \TYPO3\CMS\Core\Core\Bootstrap
802 * @internal This is not a public API method, do not use in own extensions
803 */
804 public function initializeTypo3DbGlobal()
805 {
806 /** @var $databaseConnection \TYPO3\CMS\Core\Database\DatabaseConnection */
807 $databaseConnection = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\DatabaseConnection::class);
808 $databaseConnection->setDatabaseName(TYPO3_db);
809 $databaseConnection->setDatabaseUsername(TYPO3_db_username);
810 $databaseConnection->setDatabasePassword(TYPO3_db_password);
811
812 $databaseHost = TYPO3_db_host;
813 if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['port'])) {
814 $databaseConnection->setDatabasePort($GLOBALS['TYPO3_CONF_VARS']['DB']['port']);
815 } elseif (strpos($databaseHost, ':') > 0) {
816 // @TODO: Find a way to handle this case in the install tool and drop this
817 list($databaseHost, $databasePort) = explode(':', $databaseHost);
818 $databaseConnection->setDatabasePort($databasePort);
819 }
820 if (isset($GLOBALS['TYPO3_CONF_VARS']['DB']['socket'])) {
821 $databaseConnection->setDatabaseSocket($GLOBALS['TYPO3_CONF_VARS']['DB']['socket']);
822 }
823 $databaseConnection->setDatabaseHost($databaseHost);
824
825 $databaseConnection->debugOutput = $GLOBALS['TYPO3_CONF_VARS']['SYS']['sqlDebug'];
826
827 if (
828 isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect'])
829 && !$GLOBALS['TYPO3_CONF_VARS']['SYS']['no_pconnect']
830 ) {
831 $databaseConnection->setPersistentDatabaseConnection(true);
832 }
833
834 $isDatabaseHostLocalHost = $databaseHost === 'localhost' || $databaseHost === '127.0.0.1' || $databaseHost === '::1';
835 if (
836 isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress'])
837 && $GLOBALS['TYPO3_CONF_VARS']['SYS']['dbClientCompress']
838 && !$isDatabaseHostLocalHost
839 ) {
840 $databaseConnection->setConnectionCompression(true);
841 }
842
843 if (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit'])) {
844 $commandsAfterConnect = GeneralUtility::trimExplode(
845 LF,
846 str_replace('\' . LF . \'', LF, $GLOBALS['TYPO3_CONF_VARS']['SYS']['setDBinit']),
847 true
848 );
849 $databaseConnection->setInitializeCommandsAfterConnect($commandsAfterConnect);
850 }
851
852 $GLOBALS['TYPO3_DB'] = $databaseConnection;
853 // $GLOBALS['TYPO3_DB'] needs to be defined first in order to work for DBAL
854 $GLOBALS['TYPO3_DB']->initialize();
855
856 return $this;
857 }
858
859 /**
860 * Check adminOnly configuration variable and redirects
861 * to an URL in file typo3conf/LOCK_BACKEND or exit the script
862 *
863 * @throws \RuntimeException
864 * @param bool $forceProceeding if this option is set, the bootstrap will proceed even if the user is logged in (usually only needed for special AJAX cases, see AjaxRequestHandler)
865 * @return Bootstrap
866 * @internal This is not a public API method, do not use in own extensions
867 */
868 public function checkLockedBackendAndRedirectOrDie($forceProceeding = false)
869 {
870 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'] < 0) {
871 throw new \RuntimeException('TYPO3 Backend locked: Backend and Install Tool are locked for maintenance. [BE][adminOnly] is set to "' . (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'] . '".', 1294586847);
872 }
873 if (@is_file(PATH_typo3conf . 'LOCK_BACKEND') && $forceProceeding === false) {
874 $fileContent = GeneralUtility::getUrl(PATH_typo3conf . 'LOCK_BACKEND');
875 if ($fileContent) {
876 header('Location: ' . $fileContent);
877 } else {
878 throw new \RuntimeException('TYPO3 Backend locked: Browser backend is locked for maintenance. Remove lock by removing the file "typo3conf/LOCK_BACKEND" or use CLI-scripts.', 1294586848);
879 }
880 die;
881 }
882 return $this;
883 }
884
885 /**
886 * Compare client IP with IPmaskList and exit the script run
887 * if the client is not allowed to access the backend
888 *
889 * @return Bootstrap
890 * @internal This is not a public API method, do not use in own extensions
891 * @throws \RuntimeException
892 */
893 public function checkBackendIpOrDie()
894 {
895 if (trim($GLOBALS['TYPO3_CONF_VARS']['BE']['IPmaskList'])) {
896 if (!GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['BE']['IPmaskList'])) {
897 throw new \RuntimeException('TYPO3 Backend access denied: The IP address of your client does not match the list of allowed IP addresses.', 1389265900);
898 }
899 }
900 return $this;
901 }
902
903 /**
904 * Check lockSSL configuration variable and redirect
905 * to https version of the backend if needed
906 *
907 * @return Bootstrap
908 * @internal This is not a public API method, do not use in own extensions
909 * @throws \RuntimeException
910 */
911 public function checkSslBackendAndRedirectIfNeeded()
912 {
913 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL']) {
914 if (!GeneralUtility::getIndpEnv('TYPO3_SSL')) {
915 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL'] === 2) {
916 if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSLPort']) {
917 $sslPortSuffix = ':' . (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSLPort'];
918 } else {
919 $sslPortSuffix = '';
920 }
921 list(, $url) = explode('://', GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir, 2);
922 list($server, $address) = explode('/', $url, 2);
923 header('Location: https://' . $server . $sslPortSuffix . '/' . $address);
924 die;
925 } else {
926 throw new \RuntimeException('TYPO3 Backend not accessed via SSL: TYPO3 Backend is configured to only be accessible through SSL. Change the URL in your browser and try again.', 1389265726);
927 }
928 }
929 }
930 return $this;
931 }
932
933 /**
934 * Load TCA for frontend
935 *
936 * This method is *only* executed in frontend scope. The idea is to execute the
937 * whole TCA and ext_tables (which manipulate TCA) on first frontend access,
938 * and then cache the full TCA on disk to be used for the next run again.
939 *
940 * This way, ext_tables.php ist not executed every time, but $GLOBALS['TCA']
941 * is still always there.
942 *
943 * @return Bootstrap
944 * @internal This is not a public API method, do not use in own extensions
945 */
946 public function loadCachedTca()
947 {
948 $cacheIdentifier = 'tca_fe_' . sha1((TYPO3_version . PATH_site . 'tca_fe'));
949 /** @var $codeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
950 $codeCache = $this->getEarlyInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_core');
951 if ($codeCache->has($cacheIdentifier)) {
952 // substr is necessary, because the php frontend wraps php code around the cache value
953 $GLOBALS['TCA'] = unserialize(substr($codeCache->get($cacheIdentifier), 6, -2));
954 } else {
955 $this->loadExtensionTables();
956 $codeCache->set($cacheIdentifier, serialize($GLOBALS['TCA']));
957 }
958 return $this;
959 }
960
961 /**
962 * Load ext_tables and friends.
963 *
964 * This will mainly set up $TCA and several other global arrays
965 * through API's like extMgm.
966 * Executes ext_tables.php files of loaded extensions or the
967 * according cache file if exists.
968 *
969 * @param bool $allowCaching True, if reading compiled ext_tables file from cache is allowed
970 * @return Bootstrap
971 * @internal This is not a public API method, do not use in own extensions
972 */
973 public function loadExtensionTables($allowCaching = true)
974 {
975 ExtensionManagementUtility::loadBaseTca($allowCaching);
976 ExtensionManagementUtility::loadExtTables($allowCaching);
977 $this->runExtTablesPostProcessingHooks();
978 return $this;
979 }
980
981 /**
982 * Check for registered ext tables hooks and run them
983 *
984 * @throws \UnexpectedValueException
985 * @return void
986 */
987 protected function runExtTablesPostProcessingHooks()
988 {
989 if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'])) {
990 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['GLOBAL']['extTablesInclusion-PostProcessing'] as $classReference) {
991 /** @var $hookObject \TYPO3\CMS\Core\Database\TableConfigurationPostProcessingHookInterface */
992 $hookObject = GeneralUtility::getUserObj($classReference);
993 if (!$hookObject instanceof \TYPO3\CMS\Core\Database\TableConfigurationPostProcessingHookInterface) {
994 throw new \UnexpectedValueException(
995 '$hookObject "' . $classReference . '" must implement interface TYPO3\\CMS\\Core\\Database\\TableConfigurationPostProcessingHookInterface',
996 1320585902
997 );
998 }
999 $hookObject->processData();
1000 }
1001 }
1002 }
1003
1004 /**
1005 * Initialize the Routing for the TYPO3 Backend
1006 * Loads all routes registered inside all packages and stores them inside the Router
1007 *
1008 * @return Bootstrap
1009 * @internal This is not a public API method, do not use in own extensions
1010 */
1011 public function initializeBackendRouter()
1012 {
1013 $packageManager = $this->getEarlyInstance(\TYPO3\CMS\Core\Package\PackageManager::class);
1014
1015 // See if the Routes.php from all active packages have been built together already
1016 $cacheIdentifier = 'BackendRoutesFromPackages_' . sha1((TYPO3_version . PATH_site . 'BackendRoutesFromPackages'));
1017
1018 /** @var $codeCache \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend */
1019 $codeCache = $this->getEarlyInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_core');
1020 $routesFromPackages = array();
1021 if ($codeCache->has($cacheIdentifier)) {
1022 // substr is necessary, because the php frontend wraps php code around the cache value
1023 $routesFromPackages = unserialize(substr($codeCache->get($cacheIdentifier), 6, -2));
1024 } else {
1025 // Loop over all packages and check for a Configuration/Backend/Routes.php file
1026 $packages = $packageManager->getActivePackages();
1027 foreach ($packages as $package) {
1028 $routesFileNameForPackage = $package->getPackagePath() . 'Configuration/Backend/Routes.php';
1029 if (file_exists($routesFileNameForPackage)) {
1030 $definedRoutesInPackage = require $routesFileNameForPackage;
1031 if (is_array($definedRoutesInPackage)) {
1032 $routesFromPackages += $definedRoutesInPackage;
1033 }
1034 }
1035 $routesFileNameForPackage = $package->getPackagePath() . 'Configuration/Backend/AjaxRoutes.php';
1036 if (file_exists($routesFileNameForPackage)) {
1037 $definedRoutesInPackage = require $routesFileNameForPackage;
1038 if (is_array($definedRoutesInPackage)) {
1039 foreach ($definedRoutesInPackage as $routeIdentifier => $routeOptions) {
1040 // prefix the route with "ajax_" as "namespace"
1041 $routeOptions['path'] = '/ajax' . $routeOptions['path'];
1042 $routesFromPackages['ajax_' . $routeIdentifier] = $routeOptions;
1043 $routesFromPackages['ajax_' . $routeIdentifier]['ajax'] = true;
1044 }
1045 }
1046 }
1047 }
1048 // Store the data from all packages in the cache
1049 $codeCache->set($cacheIdentifier, serialize($routesFromPackages));
1050 }
1051
1052 // Build Route objects from the data
1053 $router = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\Router::class);
1054 foreach ($routesFromPackages as $name => $options) {
1055 $path = $options['path'];
1056 unset($options['path']);
1057 $route = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\Route::class, $path, $options);
1058 $router->addRoute($name, $route);
1059 }
1060 return $this;
1061 }
1062
1063 /**
1064 * Initialize backend user object in globals
1065 *
1066 * @return Bootstrap
1067 * @internal This is not a public API method, do not use in own extensions
1068 */
1069 public function initializeBackendUser()
1070 {
1071 /** @var $backendUser \TYPO3\CMS\Core\Authentication\BackendUserAuthentication */
1072 $backendUser = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::class);
1073 $backendUser->warningEmail = $GLOBALS['TYPO3_CONF_VARS']['BE']['warning_email_addr'];
1074 $backendUser->lockIP = $GLOBALS['TYPO3_CONF_VARS']['BE']['lockIP'];
1075 $backendUser->auth_timeout_field = (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['sessionTimeout'];
1076 if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
1077 $backendUser->dontSetCookie = true;
1078 }
1079 // The global must be available very early, because methods below
1080 // might trigger code which relies on it. See: #45625
1081 $GLOBALS['BE_USER'] = $backendUser;
1082 $backendUser->start();
1083 return $this;
1084 }
1085
1086 /**
1087 * Initializes and ensures authenticated access
1088 *
1089 * @internal This is not a public API method, do not use in own extensions
1090 * @param bool $proceedIfNoUserIsLoggedIn if set to TRUE, no forced redirect to the login page will be done
1091 * @return \TYPO3\CMS\Core\Core\Bootstrap
1092 */
1093 public function initializeBackendAuthentication($proceedIfNoUserIsLoggedIn = false)
1094 {
1095 $GLOBALS['BE_USER']->backendCheckLogin($proceedIfNoUserIsLoggedIn);
1096 return $this;
1097 }
1098
1099 /**
1100 * Initialize language object
1101 *
1102 * @return Bootstrap
1103 * @internal This is not a public API method, do not use in own extensions
1104 */
1105 public function initializeLanguageObject()
1106 {
1107 /** @var $GLOBALS['LANG'] \TYPO3\CMS\Lang\LanguageService */
1108 $GLOBALS['LANG'] = GeneralUtility::makeInstance(\TYPO3\CMS\Lang\LanguageService::class);
1109 $GLOBALS['LANG']->init($GLOBALS['BE_USER']->uc['lang']);
1110 return $this;
1111 }
1112
1113 /**
1114 * Throw away all output that may have happened during bootstrapping by weird extensions
1115 *
1116 * @return Bootstrap
1117 * @internal This is not a public API method, do not use in own extensions
1118 */
1119 public function endOutputBufferingAndCleanPreviousOutput()
1120 {
1121 ob_clean();
1122 return $this;
1123 }
1124
1125 /**
1126 * Initialize output compression if configured
1127 *
1128 * @return Bootstrap
1129 * @internal This is not a public API method, do not use in own extensions
1130 */
1131 public function initializeOutputCompression()
1132 {
1133 if (extension_loaded('zlib') && $GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel']) {
1134 if (MathUtility::canBeInterpretedAsInteger($GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel'])) {
1135 @ini_set('zlib.output_compression_level', $GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel']);
1136 }
1137 ob_start('ob_gzhandler');
1138 }
1139 return $this;
1140 }
1141
1142 /**
1143 * Send HTTP headers if configured
1144 *
1145 * @return Bootstrap
1146 * @internal This is not a public API method, do not use in own extensions
1147 */
1148 public function sendHttpHeaders()
1149 {
1150 if (!empty($GLOBALS['TYPO3_CONF_VARS']['BE']['HTTP']['Response']['Headers']) && is_array($GLOBALS['TYPO3_CONF_VARS']['BE']['HTTP']['Response']['Headers'])) {
1151 foreach ($GLOBALS['TYPO3_CONF_VARS']['BE']['HTTP']['Response']['Headers'] as $header) {
1152 header($header);
1153 }
1154 }
1155 return $this;
1156 }
1157
1158 /**
1159 * Things that should be performed to shut down the framework.
1160 * This method is called in all important scripts for a clean
1161 * shut down of the system.
1162 *
1163 * @return Bootstrap
1164 * @internal This is not a public API method, do not use in own extensions
1165 */
1166 public function shutdown()
1167 {
1168 $this->sendResponse();
1169 return $this;
1170 }
1171
1172 /**
1173 * Provides an instance of "template" for backend-modules to
1174 * work with.
1175 *
1176 * @return Bootstrap
1177 * @internal This is not a public API method, do not use in own extensions
1178 */
1179 public function initializeBackendTemplate()
1180 {
1181 $GLOBALS['TBE_TEMPLATE'] = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
1182 return $this;
1183 }
1184 }