vendor/shopware/core/Kernel.php line 123

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core;
  3. use Doctrine\DBAL\Configuration;
  4. use Doctrine\DBAL\Connection;
  5. use Doctrine\DBAL\DriverManager;
  6. use Doctrine\DBAL\FetchMode;
  7. use Shopware\Core\Framework\Api\Controller\FallbackController;
  8. use Shopware\Core\Framework\Migration\MigrationStep;
  9. use Shopware\Core\Framework\Plugin\KernelPluginLoader\KernelPluginLoader;
  10. use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
  11. use Symfony\Component\Config\Loader\LoaderInterface;
  12. use Symfony\Component\DependencyInjection\ContainerBuilder;
  13. use Symfony\Component\HttpKernel\Kernel as HttpKernel;
  14. use Symfony\Component\Routing\Route;
  15. use Symfony\Component\Routing\RouteCollection;
  16. use Symfony\Component\Routing\RouteCollectionBuilder;
  17. class Kernel extends HttpKernel
  18. {
  19.     use MicroKernelTrait;
  20.     public const CONFIG_EXTS '.{php,xml,yaml,yml}';
  21.     /**
  22.      * @var string Fallback version if nothing is provided via kernel constructor
  23.      */
  24.     public const SHOPWARE_FALLBACK_VERSION '6.3.9999999.9999999-dev';
  25.     /**
  26.      * @var string Regex pattern for validating Shopware versions
  27.      */
  28.     private const VALID_VERSION_PATTERN '#^\d\.\d+\.\d+\.(\d+|x)(-\w+)?#';
  29.     /**
  30.      * @var Connection|null
  31.      */
  32.     protected static $connection;
  33.     /**
  34.      * @var KernelPluginLoader|null
  35.      */
  36.     protected $pluginLoader;
  37.     /**
  38.      * @var string
  39.      */
  40.     protected $shopwareVersion;
  41.     /**
  42.      * @var string|null
  43.      */
  44.     protected $shopwareVersionRevision;
  45.     /**
  46.      * @var string|null
  47.      */
  48.     protected $projectDir;
  49.     /**
  50.      * @var bool
  51.      */
  52.     private $rebooting false;
  53.     /**
  54.      * @var string
  55.      */
  56.     private $cacheId;
  57.     /**
  58.      * {@inheritdoc}
  59.      */
  60.     public function __construct(
  61.         string $environment,
  62.         bool $debug,
  63.         KernelPluginLoader $pluginLoader,
  64.         string $cacheId,
  65.         ?string $version self::SHOPWARE_FALLBACK_VERSION,
  66.         ?Connection $connection null,
  67.         ?string $projectDir null
  68.     ) {
  69.         date_default_timezone_set('UTC');
  70.         parent::__construct($environment$debug);
  71.         self::$connection $connection;
  72.         $this->pluginLoader $pluginLoader;
  73.         $this->parseShopwareVersion($version);
  74.         $this->cacheId $cacheId;
  75.         $this->projectDir $projectDir;
  76.     }
  77.     public function registerBundles()
  78.     {
  79.         /** @var array $bundles */
  80.         $bundles = require $this->getProjectDir() . '/config/bundles.php';
  81.         $instanciatedBundleNames = [];
  82.         /** @var class-string<\Symfony\Component\HttpKernel\Bundle\Bundle> $class */
  83.         foreach ($bundles as $class => $envs) {
  84.             if (isset($envs['all']) || isset($envs[$this->environment])) {
  85.                 $bundle = new $class();
  86.                 $instanciatedBundleNames[] = $bundle->getName();
  87.                 yield $bundle;
  88.             }
  89.         }
  90.         yield from $this->pluginLoader->getBundles($this->getKernelParameters(), $instanciatedBundleNames);
  91.     }
  92.     public function getProjectDir()
  93.     {
  94.         if ($this->projectDir === null) {
  95.             $this->projectDir parent::getProjectDir();
  96.         }
  97.         return $this->projectDir;
  98.     }
  99.     public function boot(): void
  100.     {
  101.         if ($this->booted === true) {
  102.             if ($this->debug) {
  103.                 $this->startTime microtime(true);
  104.             }
  105.             return;
  106.         }
  107.         if ($this->debug) {
  108.             $this->startTime microtime(true);
  109.         }
  110.         if ($this->debug && !isset($_ENV['SHELL_VERBOSITY']) && !isset($_SERVER['SHELL_VERBOSITY'])) {
  111.             putenv('SHELL_VERBOSITY=3');
  112.             $_ENV['SHELL_VERBOSITY'] = 3;
  113.             $_SERVER['SHELL_VERBOSITY'] = 3;
  114.         }
  115.         $this->pluginLoader->initializePlugins($this->getProjectDir());
  116.         // init bundles
  117.         $this->initializeBundles();
  118.         // init container
  119.         $this->initializeContainer();
  120.         foreach ($this->getBundles() as $bundle) {
  121.             $bundle->setContainer($this->container);
  122.             $bundle->boot();
  123.         }
  124.         $this->initializeDatabaseConnectionVariables();
  125.         $this->booted true;
  126.     }
  127.     public static function getConnection(): Connection
  128.     {
  129.         if (!self::$connection) {
  130.             $url $_ENV['DATABASE_URL']
  131.                 ?? $_SERVER['DATABASE_URL']
  132.                 ?? getenv('DATABASE_URL');
  133.             $parameters = [
  134.                 'url' => $url,
  135.                 'charset' => 'utf8mb4',
  136.             ];
  137.             self::$connection DriverManager::getConnection($parameters, new Configuration());
  138.         }
  139.         return self::$connection;
  140.     }
  141.     public function getCacheDir(): string
  142.     {
  143.         return sprintf(
  144.             '%s/var/cache/%s_h%s',
  145.             $this->getProjectDir(),
  146.             $this->getEnvironment(),
  147.             $this->getCacheHash()
  148.         );
  149.     }
  150.     public function getPluginLoader(): KernelPluginLoader
  151.     {
  152.         return $this->pluginLoader;
  153.     }
  154.     public function shutdown(): void
  155.     {
  156.         if (!$this->booted) {
  157.             return;
  158.         }
  159.         // keep connection when rebooting
  160.         if (!$this->rebooting) {
  161.             self::$connection null;
  162.         }
  163.         parent::shutdown();
  164.     }
  165.     public function reboot($warmupDir, ?KernelPluginLoader $pluginLoader null, ?string $cacheId null): void
  166.     {
  167.         $this->rebooting true;
  168.         try {
  169.             if ($pluginLoader) {
  170.                 $this->pluginLoader $pluginLoader;
  171.             }
  172.             if ($cacheId) {
  173.                 $this->cacheId $cacheId;
  174.             }
  175.             parent::reboot($warmupDir);
  176.         } finally {
  177.             $this->rebooting false;
  178.         }
  179.     }
  180.     /**
  181.      * @deprecated tag:v6.4.0.0 - API Routes does not contain versions anymore
  182.      */
  183.     public function loadRoutes(LoaderInterface $loader): RouteCollection
  184.     {
  185.         $routes = new RouteCollectionBuilder($loader);
  186.         $this->configureRoutes($routes);
  187.         return $this->addApiFallbackRoutes($routes->build());
  188.     }
  189.     /**
  190.      * @deprecated tag:v6.4.0.0 - API Routes does not contain versions anymore
  191.      */
  192.     public function addApiFallbackRoutes(RouteCollection $routes): RouteCollection
  193.     {
  194.         foreach ($routes->all() as $name => $route) {
  195.             if (strpos($route->getPath(), '{version}') === false) {
  196.                 continue;
  197.             }
  198.             $fallbackRoute = clone $route;
  199.             $fallbackRoute->setPath(str_replace(['v{version}/''{version}/'], ''$fallbackRoute->getPath()));
  200.             $fallbackRoute->setDefault('version'PlatformRequest::API_VERSION);
  201.             $routes->add($name '.major_fallback'$fallbackRoute);
  202.         }
  203.         return $routes;
  204.     }
  205.     protected function configureContainer(ContainerBuilder $containerLoaderInterface $loader): void
  206.     {
  207.         $container->setParameter('container.dumper.inline_class_loader'true);
  208.         $container->setParameter('container.dumper.inline_factories'true);
  209.         $confDir $this->getProjectDir() . '/config';
  210.         $loader->load($confDir '/{packages}/*' self::CONFIG_EXTS'glob');
  211.         $loader->load($confDir '/{packages}/' $this->environment '/**/*' self::CONFIG_EXTS'glob');
  212.         $loader->load($confDir '/{services}' self::CONFIG_EXTS'glob');
  213.         $loader->load($confDir '/{services}_' $this->environment self::CONFIG_EXTS'glob');
  214.     }
  215.     protected function configureRoutes(RouteCollectionBuilder $routes): void
  216.     {
  217.         $confDir $this->getProjectDir() . '/config';
  218.         $routes->import($confDir '/{routes}/*' self::CONFIG_EXTS'/''glob');
  219.         $routes->import($confDir '/{routes}/' $this->environment '/**/*' self::CONFIG_EXTS'/''glob');
  220.         $routes->import($confDir '/{routes}' self::CONFIG_EXTS'/''glob');
  221.         $this->addBundleRoutes($routes);
  222.         $this->addApiRoutes($routes);
  223.         $this->addBundleOverwrites($routes);
  224.         $this->addFallbackRoute($routes);
  225.     }
  226.     /**
  227.      * {@inheritdoc}
  228.      */
  229.     protected function getKernelParameters(): array
  230.     {
  231.         $parameters parent::getKernelParameters();
  232.         $activePluginMeta = [];
  233.         foreach ($this->pluginLoader->getPluginInstances()->getActives() as $plugin) {
  234.             $class = \get_class($plugin);
  235.             $activePluginMeta[$class] = [
  236.                 'name' => $plugin->getName(),
  237.                 'path' => $plugin->getPath(),
  238.                 'class' => $class,
  239.             ];
  240.         }
  241.         $pluginDir $this->pluginLoader->getPluginDir($this->getProjectDir());
  242.         return array_merge(
  243.             $parameters,
  244.             [
  245.                 'kernel.cache.hash' => $this->getCacheHash(),
  246.                 'kernel.shopware_version' => $this->shopwareVersion,
  247.                 'kernel.shopware_version_revision' => $this->shopwareVersionRevision,
  248.                 'kernel.plugin_dir' => $pluginDir,
  249.                 'kernel.app_dir' => rtrim($this->getProjectDir(), '/') . '/custom/apps',
  250.                 'kernel.active_plugins' => $activePluginMeta,
  251.                 'kernel.plugin_infos' => $this->pluginLoader->getPluginInfos(),
  252.                 'kernel.supported_api_versions' => [23],
  253.                 'defaults_bool_true' => true,
  254.                 'defaults_bool_false' => false,
  255.                 'default_whitespace' => ' ',
  256.             ]
  257.         );
  258.     }
  259.     protected function getCacheHash()
  260.     {
  261.         $pluginHash md5(implode(''array_keys($this->pluginLoader->getPluginInstances()->getActives())));
  262.         return md5(json_encode([
  263.             $this->cacheId,
  264.             mb_substr($this->shopwareVersionRevision08),
  265.             mb_substr($pluginHash08),
  266.         ]));
  267.     }
  268.     protected function initializeDatabaseConnectionVariables(): void
  269.     {
  270.         $connection self::getConnection();
  271.         $nonDestructiveMigrations $connection->executeQuery('
  272.             SELECT `creation_timestamp`
  273.             FROM `migration`
  274.             WHERE `update` IS NOT NULL AND `update_destructive` IS NULL
  275.         ')->fetchAll(FetchMode::COLUMN);
  276.         $activeMigrations $this->container->getParameter('migration.active');
  277.         $activeNonDestructiveMigrations array_intersect($activeMigrations$nonDestructiveMigrations);
  278.         $setSessionVariables $_SERVER['SQL_SET_DEFAULT_SESSION_VARIABLES'] ?? true;
  279.         $connectionVariables = [];
  280.         if ($setSessionVariables) {
  281.             $connectionVariables[] = 'SET @@group_concat_max_len = CAST(IF(@@group_concat_max_len > 320000, @@group_concat_max_len, 320000) AS UNSIGNED)';
  282.             $connectionVariables[] = "SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''))";
  283.         }
  284.         foreach ($activeNonDestructiveMigrations as $migration) {
  285.             $connectionVariables[] = sprintf(
  286.                 'SET %s = TRUE',
  287.                 sprintf(MigrationStep::MIGRATION_VARIABLE_FORMAT$migration)
  288.             );
  289.         }
  290.         if (empty($connectionVariables)) {
  291.             return;
  292.         }
  293.         $connection->executeQuery(implode(';'$connectionVariables));
  294.     }
  295.     private function addApiRoutes(RouteCollectionBuilder $routes): void
  296.     {
  297.         $routes->import('.'null'api');
  298.     }
  299.     private function addBundleRoutes(RouteCollectionBuilder $routes): void
  300.     {
  301.         foreach ($this->getBundles() as $bundle) {
  302.             if ($bundle instanceof Framework\Bundle) {
  303.                 $bundle->configureRoutes($routes, (string) $this->environment);
  304.             }
  305.         }
  306.     }
  307.     private function addBundleOverwrites(RouteCollectionBuilder $routes): void
  308.     {
  309.         foreach ($this->getBundles() as $bundle) {
  310.             if ($bundle instanceof Framework\Bundle) {
  311.                 $bundle->configureRouteOverwrites($routes, (string) $this->environment);
  312.             }
  313.         }
  314.     }
  315.     private function addFallbackRoute(RouteCollectionBuilder $routes): void
  316.     {
  317.         // detail routes
  318.         $route = new Route('/');
  319.         $route->setMethods(['GET']);
  320.         $route->setDefault('_controller'FallbackController::class . '::rootFallback');
  321.         $routes->addRoute($route'root.fallback');
  322.     }
  323.     private function parseShopwareVersion(?string $version): void
  324.     {
  325.         // does not come from composer, was set manually
  326.         if ($version === null || mb_strpos($version'@') === false) {
  327.             $this->shopwareVersion self::SHOPWARE_FALLBACK_VERSION;
  328.             $this->shopwareVersionRevision str_repeat('0'32);
  329.             return;
  330.         }
  331.         [$version$hash] = explode('@'$version);
  332.         $version ltrim($version'v');
  333.         $version = (string) str_replace('+''-'$version);
  334.         /*
  335.          * checks if the version is a valid version pattern
  336.          * Shopware\Core\Framework\Test\KernelTest::testItCreatesShopwareVersion()
  337.          */
  338.         if (!preg_match(self::VALID_VERSION_PATTERN$version)) {
  339.             $version self::SHOPWARE_FALLBACK_VERSION;
  340.         }
  341.         $this->shopwareVersion $version;
  342.         $this->shopwareVersionRevision $hash;
  343.     }
  344. }