diff --git a/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md b/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md index a08727013b4bd..4574d06a22bce 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/WebProfilerBundle/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add support for the `QUERY` HTTP method in the profiler + * Add `APP_RUNTIME` display in the configuration dashboard 7.3 --- diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig index cf25892bc9162..163a64a5e3ea2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig @@ -278,6 +278,16 @@ View full PHP configuration

+ {% if collector.appRuntime %} +

Application Runtime

+
+
+ {{ collector.appRuntime }} + Runtime +
+
+ {% endif %} + {% if collector.bundles %}

Enabled Bundles ({{ collector.bundles|length }})

diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index f690369005a53..a0ec362f922c7 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG * Deprecate implementing `__sleep/wakeup()` on kernels; use `__(un)serialize()` instead * Deprecate implementing `__sleep/wakeup()` on data collectors; use `__(un)serialize()` instead * Make `Profile` final and `Profiler::__sleep()` internal + * Add `APP_RUNTIME` display in the Symfony Profiler configuration dashboard 7.3 --- diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php index cc8ff3ada9e09..0ec47a335ebc0 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php @@ -64,6 +64,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep 'zend_opcache_status' => \extension_loaded('Zend OPcache') ? (filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed', 'bundles' => [], 'sapi_name' => \PHP_SAPI, + 'app_runtime_resolved' => $this->resolveAppRuntime(), ]; if (isset($this->kernel)) { @@ -249,6 +250,11 @@ public function getSapiName(): string return $this->data['sapi_name']; } + public function getAppRuntime(): ?string + { + return $this->data['app_runtime_resolved'] ?? null; + } + public function getName(): string { return 'config'; @@ -272,4 +278,34 @@ private function determineSymfonyState(): string return $versionState; } + + private function resolveAppRuntime(): ?string + { + $envRuntime = $_SERVER['APP_RUNTIME'] ?? null; + if (\is_string($envRuntime) && '' !== $envRuntime) { + return $envRuntime; + } + + if (isset($this->kernel)) { + $composerJsonPath = $this->kernel->getProjectDir().'/composer.json'; + if (is_file($composerJsonPath) && is_readable($composerJsonPath)) { + $json = @file_get_contents($composerJsonPath); + if (false !== $json) { + $decoded = json_decode($json, true); + if (\is_array($decoded)) { + $runtimeClass = $decoded['extra']['runtime']['class'] ?? null; + if (\is_string($runtimeClass) && '' !== $runtimeClass) { + return $runtimeClass; + } + } + } + } + } + + if (class_exists('Symfony\\Runtime\\SymfonyRuntime')) { + return 'Symfony\\Runtime\\SymfonyRuntime'; + } + + return null; + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php index 00da7a7801efd..bbec295d531de 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php @@ -77,6 +77,85 @@ public function testCollectWithoutKernel() $this->assertSame($eom, $c->getSymfonyEom()); $this->assertSame($eol, $c->getSymfonyEol()); } + + public function testGetAppRuntime() + { + $c = new ConfigDataCollector(); + + $c->collect(new Request(), new Response()); + $this->assertNull($c->getAppRuntime()); + + $_SERVER['APP_RUNTIME'] = 'Symfony\\Runtime\\SymfonyRuntime'; + $c->collect(new Request(), new Response()); + $this->assertSame('Symfony\\Runtime\\SymfonyRuntime', $c->getAppRuntime()); + + unset($_SERVER['APP_RUNTIME']); + } + + public function testGetAppRuntimeFromComposerJson() + { + $tempDir = sys_get_temp_dir().'/sf_runtime_'.uniqid(); + @mkdir($tempDir); + + $composerJson = [ + 'name' => 'example/app', + 'type' => 'project', + 'extra' => [ + 'runtime' => [ + 'class' => 'App\\CustomRuntime', + ], + ], + ]; + file_put_contents($tempDir.'/composer.json', json_encode($composerJson)); + + $kernel = new class('test', true, $tempDir) extends KernelForTest { + public function __construct(string $environment, bool $debug, private string $pdir) + { + parent::__construct($environment, $debug); + } + public function getProjectDir(): string + { + return $this->pdir; + } + }; + + $c = new ConfigDataCollector(); + $c->setKernel($kernel); + $c->collect(new Request(), new Response()); + $this->assertSame('App\\CustomRuntime', $c->getAppRuntime()); + + @unlink($tempDir.'/composer.json'); + @rmdir($tempDir); + } + + public function testGetAppRuntimeFallback() + { + $tempDir = sys_get_temp_dir().'/sf_runtime_'.uniqid(); + @mkdir($tempDir); + + $kernel = new class('test', true, $tempDir) extends KernelForTest { + public function __construct(string $environment, bool $debug, private string $pdir) + { + parent::__construct($environment, $debug); + } + public function getProjectDir(): string + { + return $this->pdir; + } + }; + + $c = new ConfigDataCollector(); + $c->setKernel($kernel); + $c->collect(new Request(), new Response()); + + if (class_exists('Symfony\\Runtime\\SymfonyRuntime')) { + $this->assertSame('Symfony\\Runtime\\SymfonyRuntime', $c->getAppRuntime()); + } else { + $this->assertNull($c->getAppRuntime()); + } + + @rmdir($tempDir); + } } class KernelForTest extends Kernel