vendor/contao/core-bundle/src/Framework/ContaoFramework.php line 281

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Framework;
  11. use Contao\ClassLoader;
  12. use Contao\Config;
  13. use Contao\CoreBundle\Exception\RedirectResponseException;
  14. use Contao\CoreBundle\Routing\ScopeMatcher;
  15. use Contao\CoreBundle\Security\Authentication\Token\TokenChecker;
  16. use Contao\CoreBundle\Session\LazySessionAccess;
  17. use Contao\Environment;
  18. use Contao\Input;
  19. use Contao\InsertTags;
  20. use Contao\Model\Registry;
  21. use Contao\RequestToken;
  22. use Contao\System;
  23. use Contao\TemplateLoader;
  24. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  25. use Symfony\Component\DependencyInjection\ContainerAwareTrait;
  26. use Symfony\Component\Filesystem\Filesystem;
  27. use Symfony\Component\HttpFoundation\Request;
  28. use Symfony\Component\HttpFoundation\RequestStack;
  29. use Symfony\Component\HttpFoundation\Session\SessionInterface;
  30. use Symfony\Contracts\Service\ResetInterface;
  31. /**
  32.  * @internal Do not use this class in your code; use the "contao.framework" service instead
  33.  */
  34. class ContaoFramework implements ContaoFrameworkInterfaceContainerAwareInterfaceResetInterface
  35. {
  36.     use ContainerAwareTrait;
  37.     /**
  38.      * @var bool
  39.      */
  40.     private static $initialized false;
  41.     /**
  42.      * @var RequestStack
  43.      */
  44.     private $requestStack;
  45.     /**
  46.      * @var ScopeMatcher
  47.      */
  48.     private $scopeMatcher;
  49.     /**
  50.      * @var TokenChecker
  51.      */
  52.     private $tokenChecker;
  53.     /**
  54.      * @var Filesystem
  55.      */
  56.     private $filesystem;
  57.     /**
  58.      * @var string
  59.      */
  60.     private $projectDir;
  61.     /**
  62.      * @var int
  63.      */
  64.     private $errorLevel;
  65.     /**
  66.      * @var Request
  67.      */
  68.     private $request;
  69.     /**
  70.      * @var bool
  71.      */
  72.     private $isFrontend false;
  73.     /**
  74.      * @var array
  75.      */
  76.     private $adapterCache = [];
  77.     /**
  78.      * @var array
  79.      */
  80.     private $hookListeners = [];
  81.     public function __construct(RequestStack $requestStackScopeMatcher $scopeMatcherTokenChecker $tokenCheckerFilesystem $filesystemstring $projectDirint $errorLevel)
  82.     {
  83.         $this->requestStack $requestStack;
  84.         $this->scopeMatcher $scopeMatcher;
  85.         $this->tokenChecker $tokenChecker;
  86.         $this->filesystem $filesystem;
  87.         $this->projectDir $projectDir;
  88.         $this->errorLevel $errorLevel;
  89.     }
  90.     public function reset(): void
  91.     {
  92.         $this->adapterCache = [];
  93.         $this->isFrontend false;
  94.         if (!$this->isInitialized()) {
  95.             return;
  96.         }
  97.         Environment::reset();
  98.         Input::resetCache();
  99.         Input::resetUnusedGet();
  100.         InsertTags::reset();
  101.         Registry::getInstance()->reset();
  102.     }
  103.     public function isInitialized(): bool
  104.     {
  105.         return self::$initialized;
  106.     }
  107.     /**
  108.      * @throws \LogicException
  109.      */
  110.     public function initialize(bool $isFrontend false): void
  111.     {
  112.         if ($this->isInitialized()) {
  113.             return;
  114.         }
  115.         // Set before calling any methods to prevent recursion
  116.         self::$initialized true;
  117.         if (null === $this->container) {
  118.             throw new \LogicException('The service container has not been set.');
  119.         }
  120.         $this->isFrontend $isFrontend;
  121.         $this->request $this->requestStack->getMasterRequest();
  122.         $this->setConstants();
  123.         $this->initializeFramework();
  124.     }
  125.     public function setHookListeners(array $hookListeners): void
  126.     {
  127.         $this->hookListeners $hookListeners;
  128.     }
  129.     public function createInstance($class$args = [])
  130.     {
  131.         if (\in_array('getInstance'get_class_methods($class), true)) {
  132.             return \call_user_func_array([$class'getInstance'], $args);
  133.         }
  134.         $reflection = new \ReflectionClass($class);
  135.         return $reflection->newInstanceArgs($args);
  136.     }
  137.     public function getAdapter($class): Adapter
  138.     {
  139.         if (!isset($this->adapterCache[$class])) {
  140.             $this->adapterCache[$class] = new Adapter($class);
  141.         }
  142.         return $this->adapterCache[$class];
  143.     }
  144.     /**
  145.      * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0
  146.      */
  147.     private function setConstants(): void
  148.     {
  149.         if (!\defined('TL_MODE')) {
  150.             \define('TL_MODE'$this->getMode());
  151.         }
  152.         \define('TL_START'microtime(true));
  153.         \define('TL_ROOT'$this->projectDir);
  154.         \define('TL_REFERER_ID'$this->getRefererId());
  155.         if (!\defined('TL_SCRIPT')) {
  156.             \define('TL_SCRIPT'$this->getRoute());
  157.         }
  158.         // Define the login status constants (see #4099, #5279)
  159.         if ('FE' === $this->getMode() && ($session $this->getSession()) && $this->request->hasPreviousSession()) {
  160.             $session->start();
  161.             \define('BE_USER_LOGGED_IN'$this->tokenChecker->hasBackendUser() && $this->tokenChecker->isPreviewMode());
  162.             \define('FE_USER_LOGGED_IN'$this->tokenChecker->hasFrontendUser());
  163.         } else {
  164.             \define('BE_USER_LOGGED_IN'false);
  165.             \define('FE_USER_LOGGED_IN'false);
  166.         }
  167.         // Define the relative path to the installation (see #5339)
  168.         \define('TL_PATH'$this->getPath());
  169.     }
  170.     private function getMode(): ?string
  171.     {
  172.         if (true === $this->isFrontend) {
  173.             return 'FE';
  174.         }
  175.         if (null === $this->request) {
  176.             return null;
  177.         }
  178.         if ($this->scopeMatcher->isBackendRequest($this->request)) {
  179.             return 'BE';
  180.         }
  181.         if ($this->scopeMatcher->isFrontendRequest($this->request)) {
  182.             return 'FE';
  183.         }
  184.         return null;
  185.     }
  186.     private function getRefererId(): ?string
  187.     {
  188.         if (null === $this->request) {
  189.             return null;
  190.         }
  191.         return $this->request->attributes->get('_contao_referer_id''');
  192.     }
  193.     private function getRoute(): ?string
  194.     {
  195.         if (null === $this->request) {
  196.             return null;
  197.         }
  198.         return substr($this->request->getBaseUrl().$this->request->getPathInfo(), \strlen($this->request->getBasePath().'/'));
  199.     }
  200.     private function getPath(): ?string
  201.     {
  202.         if (null === $this->request) {
  203.             return null;
  204.         }
  205.         return $this->request->getBasePath();
  206.     }
  207.     private function initializeFramework(): void
  208.     {
  209.         // Set the error_reporting level
  210.         error_reporting($this->errorLevel);
  211.         $this->includeHelpers();
  212.         $this->includeBasicClasses();
  213.         // Set the container
  214.         System::setContainer($this->container);
  215.         /** @var Config $config */
  216.         $config $this->getAdapter(Config::class);
  217.         // Preload the configuration (see #5872)
  218.         $config->preload();
  219.         // Register the class loader
  220.         ClassLoader::scanAndRegister();
  221.         $this->initializeLegacySessionAccess();
  222.         $this->setDefaultLanguage();
  223.         // Fully load the configuration
  224.         $config->getInstance();
  225.         $this->registerHookListeners();
  226.         $this->validateInstallation();
  227.         Input::initialize();
  228.         TemplateLoader::initialize();
  229.         $this->setTimezone();
  230.         $this->triggerInitializeSystemHook();
  231.         $this->handleRequestToken();
  232.     }
  233.     private function includeHelpers(): void
  234.     {
  235.         require __DIR__.'/../Resources/contao/helper/functions.php';
  236.         require __DIR__.'/../Resources/contao/config/constants.php';
  237.     }
  238.     /**
  239.      * Includes the basic classes required for further processing.
  240.      */
  241.     private function includeBasicClasses(): void
  242.     {
  243.         static $basicClasses = [
  244.             'System',
  245.             'Config',
  246.             'ClassLoader',
  247.             'TemplateLoader',
  248.             'ModuleLoader',
  249.         ];
  250.         foreach ($basicClasses as $class) {
  251.             if (!class_exists($classfalse)) {
  252.                 require_once __DIR__.'/../Resources/contao/library/Contao/'.$class.'.php';
  253.             }
  254.         }
  255.     }
  256.     /**
  257.      * Initializes session access for $_SESSION['FE_DATA'] and $_SESSION['BE_DATA'].
  258.      */
  259.     private function initializeLegacySessionAccess(): void
  260.     {
  261.         if (!$session $this->getSession()) {
  262.             return;
  263.         }
  264.         if (!$session->isStarted()) {
  265.             $_SESSION = new LazySessionAccess($session);
  266.         } else {
  267.             $_SESSION['BE_DATA'] = $session->getBag('contao_backend');
  268.             $_SESSION['FE_DATA'] = $session->getBag('contao_frontend');
  269.         }
  270.     }
  271.     private function setDefaultLanguage(): void
  272.     {
  273.         $language 'en';
  274.         if (null !== $this->request) {
  275.             $language str_replace('_''-'$this->request->getLocale());
  276.         }
  277.         // Deprecated since Contao 4.0, to be removed in Contao 5.0
  278.         $GLOBALS['TL_LANGUAGE'] = $language;
  279.     }
  280.     /**
  281.      * Redirects to the install tool if the installation is incomplete.
  282.      */
  283.     private function validateInstallation(): void
  284.     {
  285.         if (null === $this->request) {
  286.             return;
  287.         }
  288.         static $installRoutes = [
  289.             'contao_install',
  290.             'contao_install_redirect',
  291.         ];
  292.         if (\in_array($this->request->attributes->get('_route'), $installRoutestrue)) {
  293.             return;
  294.         }
  295.         /** @var Config $config */
  296.         $config $this->getAdapter(Config::class);
  297.         if (!$config->isComplete()) {
  298.             throw new RedirectResponseException('/contao/install');
  299.         }
  300.     }
  301.     private function setTimezone(): void
  302.     {
  303.         /** @var Config $config */
  304.         $config $this->getAdapter(Config::class);
  305.         $this->iniSet('date.timezone', (string) $config->get('timeZone'));
  306.         date_default_timezone_set((string) $config->get('timeZone'));
  307.     }
  308.     private function triggerInitializeSystemHook(): void
  309.     {
  310.         if (
  311.             !empty($GLOBALS['TL_HOOKS']['initializeSystem'])
  312.             && \is_array($GLOBALS['TL_HOOKS']['initializeSystem'])
  313.             && is_dir($this->projectDir.'/system/tmp')
  314.         ) {
  315.             foreach ($GLOBALS['TL_HOOKS']['initializeSystem'] as $callback) {
  316.                 System::importStatic($callback[0])->{$callback[1]}();
  317.             }
  318.         }
  319.         if ($this->filesystem->exists($this->projectDir.'/system/config/initconfig.php')) {
  320.             @trigger_error('Using the "initconfig.php" file has been deprecated and will no longer work in Contao 5.0.'E_USER_DEPRECATED);
  321.             include $this->projectDir.'/system/config/initconfig.php';
  322.         }
  323.     }
  324.     private function handleRequestToken(): void
  325.     {
  326.         /** @var RequestToken $requestToken */
  327.         $requestToken $this->getAdapter(RequestToken::class);
  328.         // Deprecated since Contao 4.0, to be removed in Contao 5.0
  329.         if (!\defined('REQUEST_TOKEN')) {
  330.             \define('REQUEST_TOKEN''cli' === \PHP_SAPI null $requestToken->get());
  331.         }
  332.     }
  333.     private function iniSet(string $keystring $value): void
  334.     {
  335.         if (\function_exists('ini_set')) {
  336.             ini_set($key$value);
  337.         }
  338.     }
  339.     private function getSession(): ?SessionInterface
  340.     {
  341.         if (null === $this->request || !$this->request->hasSession()) {
  342.             return null;
  343.         }
  344.         return $this->request->getSession();
  345.     }
  346.     private function registerHookListeners(): void
  347.     {
  348.         foreach ($this->hookListeners as $hookName => $priorities) {
  349.             if (isset($GLOBALS['TL_HOOKS'][$hookName]) && \is_array($GLOBALS['TL_HOOKS'][$hookName])) {
  350.                 if (isset($priorities[0])) {
  351.                     $priorities[0] = array_merge($GLOBALS['TL_HOOKS'][$hookName], $priorities[0]);
  352.                 } else {
  353.                     $priorities[0] = $GLOBALS['TL_HOOKS'][$hookName];
  354.                     krsort($priorities);
  355.                 }
  356.             }
  357.             $GLOBALS['TL_HOOKS'][$hookName] = array_merge(...$priorities);
  358.         }
  359.     }
  360. }