diff --git a/framework/core/src/Admin/AdminServiceProvider.php b/framework/core/src/Admin/AdminServiceProvider.php
index 92f187a57..7181baec0 100644
--- a/framework/core/src/Admin/AdminServiceProvider.php
+++ b/framework/core/src/Admin/AdminServiceProvider.php
@@ -63,6 +63,7 @@ class AdminServiceProvider extends AbstractServiceProvider
HttpMiddleware\ReferrerPolicyHeader::class,
HttpMiddleware\ContentTypeOptionsHeader::class,
Middleware\DisableBrowserCache::class,
+ Middleware\GatherDebugInformation::class,
];
});
diff --git a/framework/core/src/Admin/Middleware/GatherDebugInformation.php b/framework/core/src/Admin/Middleware/GatherDebugInformation.php
new file mode 100644
index 000000000..c6329d7ee
--- /dev/null
+++ b/framework/core/src/Admin/Middleware/GatherDebugInformation.php
@@ -0,0 +1,43 @@
+settings->get('core.debug.web_user');
+ $currentUser = get_current_user();
+ if ($user !== $currentUser) {
+ $this->settings->set(
+ "core.web_user",
+ $currentUser
+ );
+ }
+
+ // Read the opcache situation, this is only visible in web.
+ $opcache = $this->settings->get('core.debug.opcache_enabled');
+ $opcacheStatus = function_exists('opcache_get_configuration')
+ && opcache_get_configuration() !== false;
+ if ($opcache !== $opcacheStatus) {
+ $this->settings->set(
+ 'core.debug.opcache_enabled',
+ $opcacheStatus
+ );
+ }
+
+ return $handler->handle($request);
+ }
+}
diff --git a/framework/core/src/Foundation/ApplicationInfoProvider.php b/framework/core/src/Foundation/ApplicationInfoProvider.php
index 7bdbec508..8f2b38fac 100644
--- a/framework/core/src/Foundation/ApplicationInfoProvider.php
+++ b/framework/core/src/Foundation/ApplicationInfoProvider.php
@@ -40,18 +40,21 @@ class ApplicationInfoProvider
return count($this->schedule->events()) > 0;
}
- public function getSchedulerStatus(): string
+ public function getSchedulerStatus(bool $translated = true): string
{
$status = $this->settings->get('schedule.last_run');
- if (! $status) {
- return $this->translator->trans('core.admin.dashboard.status.scheduler.never-run');
+ $key = match(true) {
+ ! $status => 'never-run',
+ Carbon::parse($status) > Carbon::now()->subMinutes(5) => 'active',
+ default => 'inactive'
+ };
+
+ if ($translated) {
+ return $this->translator->trans("core.admin.dashboard.status.scheduler.$key");
}
- // If the schedule has not run in the last 5 minutes, mark it as inactive.
- return Carbon::parse($status) > Carbon::now()->subMinutes(5)
- ? $this->translator->trans('core.admin.dashboard.status.scheduler.active')
- : $this->translator->trans('core.admin.dashboard.status.scheduler.inactive');
+ return $key;
}
public function identifyQueueDriver(): string
diff --git a/framework/core/src/Foundation/Console/InfoCommand.php b/framework/core/src/Foundation/Console/InfoCommand.php
index 06b9c6e79..35c6d1cb5 100644
--- a/framework/core/src/Foundation/Console/InfoCommand.php
+++ b/framework/core/src/Foundation/Console/InfoCommand.php
@@ -14,7 +14,10 @@ use Flarum\Extension\ExtensionManager;
use Flarum\Foundation\Application;
use Flarum\Foundation\ApplicationInfoProvider;
use Flarum\Foundation\Config;
+use Flarum\Foundation\Info\Renderer\CliRenderer;
+use Flarum\Foundation\Info\Report;
use Flarum\Settings\SettingsRepositoryInterface;
+use Illuminate\Contracts\Container\Container;
use Illuminate\Database\ConnectionInterface;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Helper\Table;
@@ -23,11 +26,7 @@ use Symfony\Component\Console\Helper\TableStyle;
class InfoCommand extends AbstractCommand
{
public function __construct(
- protected ExtensionManager $extensions,
- protected Config $config,
- protected SettingsRepositoryInterface $settings,
- protected ConnectionInterface $db,
- protected ApplicationInfoProvider $appInfo
+ protected Container $container
) {
parent::__construct();
}
@@ -41,83 +40,13 @@ class InfoCommand extends AbstractCommand
protected function fire(): int
{
- $coreVersion = $this->findPackageVersion(__DIR__.'/../../../', Application::VERSION);
- $this->output->writeln("Flarum core: $coreVersion");
+ $report = new Report(
+ new CliRenderer($this->output),
+ $this->container
+ );
- $this->output->writeln('PHP version: '.$this->appInfo->identifyPHPVersion());
- $this->output->writeln(''.$this->appInfo->identifyDatabaseDriver().' version: '.$this->appInfo->identifyDatabaseVersion());
-
- $phpExtensions = implode(', ', get_loaded_extensions());
- $this->output->writeln("Loaded extensions: $phpExtensions");
-
- $this->getExtensionTable()->render();
-
- $this->output->writeln('Base URL: '.$this->config->url());
- $this->output->writeln('Installation path: '.getcwd());
- $this->output->writeln('Queue driver: '.$this->appInfo->identifyQueueDriver());
- $this->output->writeln('Session driver: '.$this->appInfo->identifySessionDriver());
-
- if ($this->appInfo->scheduledTasksRegistered()) {
- $this->output->writeln('Scheduler status: '.$this->appInfo->getSchedulerStatus());
- }
-
- $this->output->writeln('Mail driver: '.$this->settings->get('mail_driver', 'unknown'));
- $this->output->writeln('Debug mode: '.($this->config->inDebugMode() ? 'ON' : 'off'));
-
- if ($this->config->inDebugMode()) {
- $this->output->writeln('');
- $this->error(
- "Don't forget to turn off debug mode! It should never be turned on in a production system."
- );
- }
+ $report->render();
return Command::SUCCESS;
}
-
- private function getExtensionTable(): Table
- {
- $table = (new Table($this->output))
- ->setHeaders([
- ['Flarum Extensions'],
- ['ID', 'Version', 'Commit']
- ])->setStyle(
- (new TableStyle)->setCellHeaderFormat('%s')
- );
-
- foreach ($this->extensions->getEnabledExtensions() as $extension) {
- $table->addRow([
- $extension->getId(),
- $extension->getVersion(),
- $this->findPackageVersion($extension->getPath())
- ]);
- }
-
- return $table;
- }
-
- /**
- * Try to detect a package's exact version.
- *
- * If the package seems to be a Git version, we extract the currently
- * checked out commit using the command line.
- */
- private function findPackageVersion(string $path, ?string $fallback = null): ?string
- {
- if (file_exists("$path/.git")) {
- $cwd = getcwd();
- chdir($path);
-
- $output = [];
- $status = null;
- exec('git rev-parse HEAD 2>&1', $output, $status);
-
- chdir($cwd);
-
- if ($status == 0) {
- return isset($fallback) ? "$fallback ($output[0])" : $output[0];
- }
- }
-
- return $fallback;
- }
}
diff --git a/framework/core/src/Foundation/Info/Concerns/PackageVersionFromPath.php b/framework/core/src/Foundation/Info/Concerns/PackageVersionFromPath.php
new file mode 100644
index 000000000..04418f73e
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Concerns/PackageVersionFromPath.php
@@ -0,0 +1,32 @@
+&1', $output, $status);
+
+ chdir($cwd);
+
+ if ($status == 0) {
+ return isset($fallback) ? "$fallback ($output[0])" : $output[0];
+ }
+ }
+
+ return $fallback;
+ }
+}
diff --git a/framework/core/src/Foundation/Info/Renderer/CliRenderer.php b/framework/core/src/Foundation/Info/Renderer/CliRenderer.php
new file mode 100644
index 000000000..c622a4411
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Renderer/CliRenderer.php
@@ -0,0 +1,46 @@
+output->writeln("$title>");
+ }
+
+ public function keyValue(string $key, mixed $value): void
+ {
+ $this->output->writeln("$key: $value");
+ }
+
+ public function table(array $headers, array $rows): void
+ {
+ $table = (new Table($this->output))
+ ->setHeaders($headers)->setStyle(
+ (new TableStyle)->setCellHeaderFormat('%s')
+ );
+
+ foreach ($rows as $row) {
+ $table->addRow($row);
+ }
+
+ $table->render();
+ }
+
+ public function open(): void
+ {
+ }
+
+ public function close(): void
+ {
+ }
+}
diff --git a/framework/core/src/Foundation/Info/RendererInterface.php b/framework/core/src/Foundation/Info/RendererInterface.php
new file mode 100644
index 000000000..b0aee439b
--- /dev/null
+++ b/framework/core/src/Foundation/Info/RendererInterface.php
@@ -0,0 +1,17 @@
+sections;
+
+ $this->renderer->open();
+
+ foreach($sections as &$section) {
+ $section = $this->container->make($section);
+
+ $section($this->renderer);
+ }
+
+ $this->renderer->close();
+ }
+}
diff --git a/framework/core/src/Foundation/Info/Section/CoreVersion.php b/framework/core/src/Foundation/Info/Section/CoreVersion.php
new file mode 100644
index 000000000..c8e2dad40
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Section/CoreVersion.php
@@ -0,0 +1,21 @@
+keyValue(
+ 'Flarum Core',
+ $this->findPackageVersion(__DIR__.'/../../../../', Application::VERSION)
+ );
+ }
+}
diff --git a/framework/core/src/Foundation/Info/Section/Debug.php b/framework/core/src/Foundation/Info/Section/Debug.php
new file mode 100644
index 000000000..51cadd617
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Section/Debug.php
@@ -0,0 +1,26 @@
+keyValue(
+ 'Debug mode',
+ $this->config->inDebugMode() ? 'on' : 'off'
+ );
+
+ if ($this->config->inDebugMode()) {
+ $renderer->heading("Debug mode should not be enabled in production; this will cause javascript and stylesheets to be recompiled on each visit.");
+ }
+ }
+}
diff --git a/framework/core/src/Foundation/Info/Section/EnabledExtensions.php b/framework/core/src/Foundation/Info/Section/EnabledExtensions.php
new file mode 100644
index 000000000..2f04e6a7c
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Section/EnabledExtensions.php
@@ -0,0 +1,33 @@
+extensions->getEnabledExtensions())
+ ->map(fn (Extension $extension) => [
+ $extension->getId(),
+ $this->findPackageVersion($extension->getPath(), $extension->getVersion())
+ ])
+ ->toArray();
+
+ $renderer->table([
+ ['Flarum Extensions'],
+ ['ID', 'Version']
+ ], $rows);
+ }
+}
diff --git a/framework/core/src/Foundation/Info/Section/Features.php b/framework/core/src/Foundation/Info/Section/Features.php
new file mode 100644
index 000000000..e4f1d3dc5
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Section/Features.php
@@ -0,0 +1,59 @@
+keyValue(
+ 'Scheduler required',
+ $this->appInfo->scheduledTasksRegistered() ? 'yes' : 'no'
+ );
+
+ $renderer->keyValue(
+ 'Scheduler status',
+ $this->appInfo->getSchedulerStatus(translated: false)
+ );
+
+ $renderer->keyValue(
+ 'Queue driver',
+ $this->appInfo->identifyQueueDriver()
+ );
+
+ $renderer->keyValue(
+ 'Session driver',
+ $this->appInfo->identifySessionDriver()
+ );
+
+ $renderer->keyValue(
+ 'Mail driver',
+ $this->mail()
+ );
+ }
+
+ protected function mail()
+ {
+ $driver = $this->container->make('mail.driver');
+ $configured = $this->container->make('flarum.mail.configured_driver');
+
+ if ($driver instanceof NullDriver) {
+ $configured .= " (not active)";
+ }
+
+ return $configured;
+ }
+}
diff --git a/framework/core/src/Foundation/Info/Section/PHP.php b/framework/core/src/Foundation/Info/Section/PHP.php
new file mode 100644
index 000000000..974fc7e40
--- /dev/null
+++ b/framework/core/src/Foundation/Info/Section/PHP.php
@@ -0,0 +1,27 @@
+keyValue(
+ 'PHP version',
+ $this->appInfo->identifyPHPVersion()
+ );
+
+ $renderer->keyValue(
+ 'PHP extensions',
+ implode(', ', get_loaded_extensions())
+ );
+ }
+}
diff --git a/framework/core/src/Foundation/Info/SectionInterface.php b/framework/core/src/Foundation/Info/SectionInterface.php
new file mode 100644
index 000000000..7bb14db3a
--- /dev/null
+++ b/framework/core/src/Foundation/Info/SectionInterface.php
@@ -0,0 +1,8 @@
+