Skip to content
Snippets Groups Projects
Unverified Commit 5e0a4ce7 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3490841 by nicxvan, dww, smustgrave: Create hook_runtime_requirements()...

Issue #3490841 by nicxvan, dww, smustgrave: Create hook_runtime_requirements() and hook_runtime_requirements_alter()
parent 928a5cbd
No related branches found
No related tags found
No related merge requests found
......@@ -1187,6 +1187,94 @@ function hook_requirements_alter(array &$requirements): void {
unset($requirements['foo']);
}
/**
* Check runtime requirements and do status reporting.
*
* Requirements are displayed on the 'Status report' (/admin/reports/status).
*
* Runtime requirements do not impact installation or updates of modules that
* define them. These requirements are only used to display information on the
* status report but do not impact site behavior. They can be used for more
* general status information like maintenance tasks and security issues.
* The returned requirements will be listed on the status report in the
* administration section, with an indication of the severity level.
* Moreover, any requirement with a severity of REQUIREMENT_ERROR will result in
* a notice on the 'Configuration' administration page (/admin/config).
*
* @return array
* An associative array where the keys are arbitrary but must be unique (it
* is suggested to use the module short name as a prefix) and the values are
* themselves associative arrays with the following elements:
* - title: The name of the requirement.
* - value: The current value (e.g., version, time, level, etc).
* - description: The description of the requirement/status.
* - severity: (optional) The requirement's severity level, one of:
* - REQUIREMENT_INFO: For info only.
* - REQUIREMENT_OK: The requirement is satisfied.
* - REQUIREMENT_WARNING: The requirement failed with a warning.
* - REQUIREMENT_ERROR: The requirement failed with an error.
* Defaults to REQUIREMENT_OK.
*/
function hook_runtime_requirements(): array {
$requirements = [];
// Report Drupal version
$requirements['drupal'] = [
'title' => t('Drupal'),
'value' => \Drupal::VERSION,
'severity' => REQUIREMENT_INFO,
];
// Test PHP version
$requirements['php'] = [
'title' => t('PHP'),
'value' => Link::fromTextAndUrl(phpversion(), Url::fromRoute('system.php'))->toString(),
];
if (version_compare(phpversion(), \Drupal::MINIMUM_PHP) < 0) {
$requirements['php']['description'] = t('Your PHP installation is too old. Drupal requires at least PHP %version.', ['%version' => \Drupal::MINIMUM_PHP]);
$requirements['php']['severity'] = REQUIREMENT_ERROR;
}
// Report cron status
$cron_last = \Drupal::state()->get('system.cron_last');
$requirements['cron']['title'] = t('Cron maintenance tasks');
if (is_numeric($cron_last)) {
$requirements['cron']['description'] = '';
$requirements['cron']['value'] = t('Last run @time ago', ['@time' => \Drupal::service('date.formatter')->formatTimeDiffSince($cron_last)]);
}
else {
$requirements['cron']['description'] = t('Cron has not run. It appears cron jobs have not been setup on your system. Check the help pages for <a href=":url">configuring cron jobs</a>.', [':url' => 'https://www.drupal.org/docs/administering-a-drupal-site/cron-automated-tasks/cron-automated-tasks-overview']);
$requirements['cron']['value'] = t('Never run');
$requirements['cron']['severity'] = REQUIREMENT_ERROR;
}
$requirements['cron']['description'] .= ' ' . t('You can <a href=":cron">run cron manually</a>.', [':cron' => Url::fromRoute('system.run_cron')->toString()]);
return $requirements;
}
/**
* Alters runtime requirements data.
*
* Implementations are able to alter the title, value, description or the
* severity of certain requirements defined by hook_requirements() and
* hook_runtime_requirements() implementations, or even remove such entries.
*
* @param array $requirements
* The requirements data to be altered.
*
* @see hook_runtime_requirements()
*/
function hook_runtime_requirements_alter(array &$requirements): void {
// Change the title from 'PHP' to 'PHP version'.
$requirements['php']['title'] = t('PHP version');
// Decrease the 'update status' requirement severity from warning to info.
$requirements['update status']['severity'] = REQUIREMENT_INFO;
// Remove a requirements entry.
unset($requirements['foo']);
}
/**
* @} End of "addtogroup hooks".
*/
......@@ -57,54 +57,6 @@ function file_schema(): array {
return $schema;
}
/**
* Implements hook_requirements().
*
* Display information about getting upload progress bars working.
*/
function file_requirements($phase): array {
$requirements = [];
if ($phase != 'runtime') {
return $requirements;
}
$server_software = \Drupal::request()->server->get('SERVER_SOFTWARE', '');
// Get the web server identity.
$is_nginx = preg_match("/Nginx/i", $server_software);
$is_apache = preg_match("/Apache/i", $server_software);
$fastcgi = $is_apache && ((str_contains($server_software, 'mod_fastcgi') || str_contains($server_software, 'mod_fcgi')));
// Check the uploadprogress extension is loaded.
if (extension_loaded('uploadprogress')) {
$value = t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
$description = NULL;
}
else {
$value = t('Not enabled');
$description = t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.');
}
// Adjust the requirement depending on what the server supports.
if (!$is_apache && !$is_nginx) {
$value = t('Not enabled');
$description = t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php or Nginx with PHP-FPM.');
}
elseif ($fastcgi) {
$value = t('Not enabled');
$description = t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.');
}
$requirements['file_progress'] = [
'title' => t('Upload progress'),
'value' => $value,
'description' => $description,
];
return $requirements;
}
/**
* Implements hook_update_last_removed().
*/
......
<?php
namespace Drupal\file\Hook;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Requirements for the File module.
*/
class FileRequirements {
use StringTranslationTrait;
/**
* Implements hook_runtime_requirements().
*/
#[Hook('runtime_requirements')]
public function runtime(): array {
$requirements = [];
$server_software = \Drupal::request()->server->get('SERVER_SOFTWARE', '');
// Get the web server identity.
$is_nginx = preg_match("/Nginx/i", $server_software);
$is_apache = preg_match("/Apache/i", $server_software);
$fastcgi = $is_apache && ((str_contains($server_software, 'mod_fastcgi') || str_contains($server_software, 'mod_fcgi')));
// Check the uploadprogress extension is loaded.
if (extension_loaded('uploadprogress')) {
$value = $this->t('Enabled (<a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress</a>)');
$description = NULL;
}
else {
$value = $this->t('Not enabled');
$description = $this->t('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.');
}
// Adjust the requirement depending on what the server supports.
if (!$is_apache && !$is_nginx) {
$value = $this->t('Not enabled');
$description = $this->t('Your server is not capable of displaying file upload progress. File upload progress requires an Apache server running PHP with mod_php or Nginx with PHP-FPM.');
}
elseif ($fastcgi) {
$value = $this->t('Not enabled');
$description = $this->t('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.');
}
$requirements['file_progress'] = [
'title' => $this->t('Upload progress'),
'value' => $value,
'description' => $description,
];
return $requirements;
}
}
......@@ -32,11 +32,10 @@ public function testUploadRequirements(): void {
/** @var \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler */
$moduleHandler = $this->container->get('module_handler');
$moduleHandler->loadInclude('file', 'install');
// Test unspecified server software.
$this->setServerSoftware(NULL);
$requirements = \file_requirements('runtime');
$requirements = $moduleHandler->invoke('file', 'runtime_requirements');
$this->assertNotEmpty($requirements);
$this->assertEquals('Upload progress', (string) $requirements['file_progress']['title']);
......@@ -45,21 +44,21 @@ public function testUploadRequirements(): void {
// Test Apache + mod_php.
$this->setServerSoftware('Apache mod_php');
$requirements = \file_requirements('runtime');
$requirements = $moduleHandler->invoke('file', 'runtime_requirements');
$this->assertNotEmpty($requirements);
$this->assertEquals('Not enabled', (string) $requirements['file_progress']['value']);
$this->assertEquals('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.', (string) $requirements['file_progress']['description']);
// Test Apache + mod_fastcgi.
$this->setServerSoftware('Apache mod_fastcgi');
$requirements = \file_requirements('runtime');
$requirements = $moduleHandler->invoke('file', 'runtime_requirements');
$this->assertNotEmpty($requirements);
$this->assertEquals('Not enabled', (string) $requirements['file_progress']['value']);
$this->assertEquals('Your server is not capable of displaying file upload progress. File upload progress requires PHP be run with mod_php or PHP-FPM and not as FastCGI.', (string) $requirements['file_progress']['description']);
// Test Nginx.
$this->setServerSoftware('Nginx');
$requirements = \file_requirements('runtime');
$requirements = $moduleHandler->invoke('file', 'runtime_requirements');
$this->assertNotEmpty($requirements);
$this->assertEquals('Not enabled', (string) $requirements['file_progress']['value']);
$this->assertEquals('Your server is capable of displaying file upload progress, but does not have the required libraries. It is recommended to install the <a href="http://pecl.php.net/package/uploadprogress">PECL uploadprogress library</a>.', (string) $requirements['file_progress']['description']);
......
......@@ -107,7 +107,10 @@ public function listRequirements() {
// Check run-time requirements and status information.
$requirements = $this->moduleHandler->invokeAll('requirements', ['runtime']);
$runtime_requirements = $this->moduleHandler->invokeAll('runtime_requirements');
$requirements = array_merge($requirements, $runtime_requirements);
$this->moduleHandler->alter('requirements', $requirements);
$this->moduleHandler->alter('runtime_requirements', $requirements);
uasort($requirements, function ($a, $b) {
if (!isset($a['weight'])) {
if (!isset($b['weight'])) {
......
name: 'Test Hook Runtime Requirements'
type: module
description: 'Support module for testing hook_runtime_requirements().'
package: Testing
version: VERSION
<?php
declare(strict_types=1);
namespace Drupal\module_runtime_requirements\Hook;
use Drupal\Core\Hook\Attribute\Hook;
use Drupal\Core\StringTranslation\StringTranslationTrait;
/**
* Hook implementations for module_runtime_requirements.
*/
class ModuleRuntimeRequirementsHooks {
use StringTranslationTrait;
/**
* Implements hook_runtime_requirements().
*/
#[Hook('runtime_requirements')]
public function runtimeRequirements(): array {
return [
'test.runtime.error' => [
'title' => $this->t('RuntimeError'),
'value' => $this->t('None'),
'description' => $this->t('Runtime Error.'),
'severity' => REQUIREMENT_ERROR,
],
'test.runtime.error.alter' => [
'title' => $this->t('RuntimeError'),
'value' => $this->t('None'),
'description' => $this->t('Runtime Error.'),
'severity' => REQUIREMENT_ERROR,
],
];
}
/**
* Implements hook_runtime_requirements_alter().
*/
#[Hook('runtime_requirements_alter')]
public function runtimeRequirementsAlter(array &$requirements): void {
$requirements['test.runtime.error.alter'] = [
'title' => $this->t('RuntimeWarning'),
'value' => $this->t('None'),
'description' => $this->t('Runtime Warning.'),
'severity' => REQUIREMENT_WARNING,
];
}
}
<?php
declare(strict_types=1);
namespace Drupal\Tests\system\Kernel\System;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests the effectiveness of hook_runtime_requirements().
*
* @group system
*/
class RunTimeRequirementsTest extends KernelTestBase {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
protected static $modules = ['system'];
/**
* Tests hook_runtime_requirements() and hook_runtime_requirements_alter().
*/
public function testRuntimeRequirements(): void {
// Enable the test module.
\Drupal::service('module_installer')->install(['module_runtime_requirements']);
$testRequirements = [
'title' => $this->t('RuntimeError'),
'value' => $this->t('None'),
'description' => $this->t('Runtime Error.'),
'severity' => REQUIREMENT_ERROR,
];
$requirements = \Drupal::service('system.manager')->listRequirements()['test.runtime.error'];
$this->assertEquals($testRequirements, $requirements);
$testRequirementsAlter = [
'title' => $this->t('RuntimeWarning'),
'value' => $this->t('None'),
'description' => $this->t('Runtime Warning.'),
'severity' => REQUIREMENT_WARNING,
];
$requirementsAlter = \Drupal::service('system.manager')->listRequirements()['test.runtime.error.alter'];
$this->assertEquals($testRequirementsAlter, $requirementsAlter);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment