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