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 @@ +