vendor/shopware/core/HttpKernel.php line 156

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. namespace Shopware\Core;
  3. use Composer\Autoload\ClassLoader;
  4. use Composer\InstalledVersions;
  5. use Doctrine\DBAL\Connection;
  6. use Doctrine\DBAL\DriverManager;
  7. use Doctrine\DBAL\Exception;
  8. use Shopware\Core\Framework\Adapter\Cache\CacheIdLoader;
  9. use Shopware\Core\Framework\Adapter\Database\MySQLFactory;
  10. use Shopware\Core\Framework\Event\BeforeSendRedirectResponseEvent;
  11. use Shopware\Core\Framework\Event\BeforeSendResponseEvent;
  12. use Shopware\Core\Framework\Feature;
  13. use Shopware\Core\Framework\Log\Package;
  14. use Shopware\Core\Framework\Plugin\KernelPluginLoader\DbalKernelPluginLoader;
  15. use Shopware\Core\Framework\Plugin\KernelPluginLoader\KernelPluginLoader;
  16. use Shopware\Core\Framework\Routing\CanonicalRedirectService;
  17. use Shopware\Core\Framework\Routing\RequestTransformerInterface;
  18. use Shopware\Core\Profiling\Doctrine\DebugStack;
  19. use Shopware\Storefront\Framework\Cache\CacheStore;
  20. use Symfony\Component\HttpFoundation\RedirectResponse;
  21. use Symfony\Component\HttpFoundation\Request;
  22. use Symfony\Component\HttpFoundation\Response;
  23. use Symfony\Component\HttpKernel\HttpCache\HttpCache;
  24. use Symfony\Component\HttpKernel\HttpKernelInterface;
  25. use Symfony\Component\HttpKernel\KernelInterface;
  26. use Symfony\Component\HttpKernel\TerminableInterface;
  27. /**
  28. * @psalm-import-type Params from DriverManager
  29. */
  30. #[Package('core')]
  31. class HttpKernel
  32. {
  33. protected static ?Connection $connection = null;
  34. /**
  35. * @var class-string<Kernel>
  36. */
  37. protected static string $kernelClass = Kernel::class;
  38. /**
  39. * @var class-string<HttpCache>
  40. */
  41. protected static string $httpCacheClass = HttpCache::class;
  42. protected ?ClassLoader $classLoader;
  43. protected string $environment;
  44. protected bool $debug;
  45. protected ?string $projectDir = null;
  46. protected ?KernelPluginLoader $pluginLoader = null;
  47. protected ?KernelInterface $kernel = null;
  48. public function __construct(string $environment, bool $debug, ?ClassLoader $classLoader = null)
  49. {
  50. $this->classLoader = $classLoader;
  51. $this->environment = $environment;
  52. $this->debug = $debug;
  53. }
  54. /**
  55. * @deprecated tag:v6.5.0 - parameter `$type` will be typed to `int` and parameter `$catch` will be typed to `bool`
  56. */
  57. public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true): HttpKernelResult
  58. {
  59. if (!\is_int($type)) {
  60. Feature::triggerDeprecationOrThrow('v6.5.0.0', 'The second parameter `$type` of `HttpKernel->handle()` will be typed to `int`');
  61. }
  62. if (!\is_bool($catch)) {
  63. Feature::triggerDeprecationOrThrow('v6.5.0.0', 'The third parameter `$catch` of `HttpKernel->handle()` will be typed to `bool`');
  64. }
  65. try {
  66. return $this->doHandle($request, (int) $type, (bool) $catch);
  67. } catch (Exception $e) {
  68. /** @var Params|array{url?: string} $connectionParams */
  69. $connectionParams = self::getConnection()->getParams();
  70. $message = str_replace([$connectionParams['url'] ?? null, $connectionParams['password'] ?? null, $connectionParams['user'] ?? null], '******', $e->getMessage());
  71. throw new \RuntimeException(sprintf('Could not connect to database. Message from SQL Server: %s', $message));
  72. }
  73. }
  74. public function getKernel(): KernelInterface
  75. {
  76. return $this->createKernel();
  77. }
  78. /**
  79. * Allows to switch the plugin loading.
  80. */
  81. public function setPluginLoader(KernelPluginLoader $pluginLoader): void
  82. {
  83. $this->pluginLoader = $pluginLoader;
  84. }
  85. public static function getConnection(): Connection
  86. {
  87. if (self::$connection) {
  88. return self::$connection;
  89. }
  90. self::$connection = MySQLFactory::create();
  91. return self::$connection;
  92. }
  93. public function terminate(Request $request, Response $response): void
  94. {
  95. if (!$this->kernel instanceof TerminableInterface) {
  96. return;
  97. }
  98. $this->kernel->terminate($request, $response);
  99. }
  100. private function doHandle(Request $request, int $type, bool $catch): HttpKernelResult
  101. {
  102. // create core kernel which contains bootstrapping for plugins etc.
  103. $kernel = $this->createKernel();
  104. $kernel->boot();
  105. $container = $kernel->getContainer();
  106. // transform request to resolve seo urls and detect sales channel
  107. $transformed = $container
  108. ->get(RequestTransformerInterface::class)
  109. ->transform($request);
  110. $redirect = $container
  111. ->get(CanonicalRedirectService::class)
  112. ->getRedirect($transformed);
  113. if ($redirect instanceof RedirectResponse) {
  114. $event = new BeforeSendRedirectResponseEvent($transformed, $redirect);
  115. $container->get('event_dispatcher')->dispatch($event);
  116. return new HttpKernelResult($transformed, $event->getResponse());
  117. }
  118. // check for http caching
  119. $enabled = $container->hasParameter('shopware.http.cache.enabled')
  120. && $container->getParameter('shopware.http.cache.enabled');
  121. if ($enabled && $container->has(CacheStore::class)) {
  122. $kernel = new static::$httpCacheClass($kernel, $container->get(CacheStore::class), null, ['debug' => $this->debug]);
  123. }
  124. $response = $kernel->handle($transformed, $type, $catch);
  125. // fire event to trigger runtime events like seo url headers
  126. $event = new BeforeSendResponseEvent($transformed, $response);
  127. $container->get('event_dispatcher')->dispatch($event);
  128. return new HttpKernelResult($transformed, $event->getResponse());
  129. }
  130. private function createKernel(): KernelInterface
  131. {
  132. if ($this->kernel !== null) {
  133. return $this->kernel;
  134. }
  135. if (InstalledVersions::isInstalled('shopware/platform')) {
  136. $shopwareVersion = InstalledVersions::getVersion('shopware/platform')
  137. . '@' . InstalledVersions::getReference('shopware/platform');
  138. } else {
  139. $shopwareVersion = InstalledVersions::getVersion('shopware/core')
  140. . '@' . InstalledVersions::getReference('shopware/core');
  141. }
  142. $connection = self::getConnection();
  143. if ($this->environment !== 'prod') {
  144. $connection->getConfiguration()->setSQLLogger(new DebugStack());
  145. }
  146. $pluginLoader = $this->createPluginLoader($connection);
  147. $cacheId = (new CacheIdLoader($connection))->load();
  148. return $this->kernel = new static::$kernelClass(
  149. $this->environment,
  150. $this->debug,
  151. $pluginLoader,
  152. $cacheId,
  153. $shopwareVersion,
  154. $connection,
  155. $this->getProjectDir()
  156. );
  157. }
  158. private function getProjectDir(): string
  159. {
  160. if ($this->projectDir === null) {
  161. if ($dir = $_ENV['PROJECT_ROOT'] ?? $_SERVER['PROJECT_ROOT'] ?? false) {
  162. return $this->projectDir = $dir;
  163. }
  164. $r = new \ReflectionObject($this);
  165. /** @var string $dir */
  166. $dir = $r->getFileName();
  167. if (!file_exists($dir)) {
  168. throw new \LogicException(sprintf('Cannot auto-detect project dir for kernel of class "%s".', $r->name));
  169. }
  170. $dir = $rootDir = \dirname($dir);
  171. while (!file_exists($dir . '/vendor')) {
  172. if ($dir === \dirname($dir)) {
  173. return $this->projectDir = $rootDir;
  174. }
  175. $dir = \dirname($dir);
  176. }
  177. $this->projectDir = $dir;
  178. }
  179. return $this->projectDir;
  180. }
  181. private function createPluginLoader(Connection $connection): KernelPluginLoader
  182. {
  183. if ($this->pluginLoader) {
  184. return $this->pluginLoader;
  185. }
  186. if (!$this->classLoader) {
  187. throw new \RuntimeException('No plugin loader and no class loader provided');
  188. }
  189. $this->pluginLoader = new DbalKernelPluginLoader($this->classLoader, null, $connection);
  190. return $this->pluginLoader;
  191. }
  192. }