diff --git a/core/includes/update.inc b/core/includes/update.inc index 022f95011eafc78b4cab7b97e49da7606287af01..d6fa9d6a870ea4669060361c5e942f04399c02b3 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -52,8 +52,12 @@ function update_check_requirements() { _update_fix_missing_schema(); // Check requirements of all loaded modules. - $requirements = \Drupal::moduleHandler()->invokeAll('requirements', ['update']); + $requirements = array_merge( + \Drupal::moduleHandler()->invokeAll('requirements', ['update']), + \Drupal::moduleHandler()->invokeAll('update_requirements') + ); \Drupal::moduleHandler()->alter('requirements', $requirements); + \Drupal::moduleHandler()->alter('update_requirements', $requirements); $requirements += update_system_schema_requirements(); return $requirements; } diff --git a/core/lib/Drupal/Core/Extension/module.api.php b/core/lib/Drupal/Core/Extension/module.api.php index 88213fafd7262fb1df9fe15104745622b6fabe14..29b8eebe2d53599ece6c9e5e4a3c08e8e59660f6 100644 --- a/core/lib/Drupal/Core/Extension/module.api.php +++ b/core/lib/Drupal/Core/Extension/module.api.php @@ -1275,6 +1275,66 @@ function hook_runtime_requirements_alter(array &$requirements): void { unset($requirements['foo']); } +/** + * Check requirements before running database updates. + * + * This hook is invoked when update.php is run and when database updates are + * triggered via the CLI. + * + * @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 result/severity level, one of: + * - REQUIREMENT_INFO: Has no effect during updates. + * - REQUIREMENT_OK: Has no effect during updates. + * - REQUIREMENT_WARNING: Displays a warning, user can choose to continue. + * - REQUIREMENT_ERROR: Displays an error message, user cannot continue + * until the problem is resolved. + * Defaults to REQUIREMENT_OK. + */ +function hook_update_requirements() { + $requirements = []; + + // Test PHP version + $requirements['php'] = [ + 'title' => t('PHP'), + 'value' => phpversion(), + ]; + 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; + } + + return $requirements; +} + +/** + * Alters update requirements data. + * + * Implementations are able to alter the title, value, description or the + * severity of certain requirements defined by hook_requirements() and + * hook_update_requirements() implementations, or even remove such entries. + * + * @param array $requirements + * The requirements data to be altered. + * + * @see hook_update_requirements() + */ +function hook_update_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". */ diff --git a/core/modules/system/tests/modules/module_update_requirements/module_update_requirements.info.yml b/core/modules/system/tests/modules/module_update_requirements/module_update_requirements.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..52604b689262e18a658510c1211fd73aeae27b2b --- /dev/null +++ b/core/modules/system/tests/modules/module_update_requirements/module_update_requirements.info.yml @@ -0,0 +1,5 @@ +name: 'Test Hook Update Requirements' +type: module +description: 'Support module for testing hook_update_requirements().' +package: Testing +version: VERSION diff --git a/core/modules/system/tests/modules/module_update_requirements/src/Hook/ModuleUpdateRequirementsHooks.php b/core/modules/system/tests/modules/module_update_requirements/src/Hook/ModuleUpdateRequirementsHooks.php new file mode 100644 index 0000000000000000000000000000000000000000..f0666222f1429549845abcf1ef67a5e6dd685c14 --- /dev/null +++ b/core/modules/system/tests/modules/module_update_requirements/src/Hook/ModuleUpdateRequirementsHooks.php @@ -0,0 +1,51 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\module_update_requirements\Hook; + +use Drupal\Core\Hook\Attribute\Hook; +use Drupal\Core\StringTranslation\StringTranslationTrait; + +/** + * Hook implementations for module_update_requirements. + */ +class ModuleUpdateRequirementsHooks { + + use StringTranslationTrait; + + /** + * Implements hook_update_requirements(). + */ + #[Hook('update_requirements')] + public function updateRequirements(): array { + return [ + 'test.update.error' => [ + 'title' => $this->t('UpdateError'), + 'value' => $this->t('None'), + 'description' => $this->t('Update Error.'), + 'severity' => REQUIREMENT_ERROR, + ], + 'test.update.error.alter' => [ + 'title' => $this->t('UpdateError'), + 'value' => $this->t('None'), + 'description' => $this->t('Update Error.'), + 'severity' => REQUIREMENT_ERROR, + ], + ]; + } + + /** + * Implements hook_update_requirements_alter(). + */ + #[Hook('update_requirements_alter')] + public function updateRequirementsAlter(array &$requirements): void { + $requirements['test.update.error.alter'] = [ + 'title' => $this->t('UpdateWarning'), + 'value' => $this->t('None'), + 'description' => $this->t('Update Warning.'), + 'severity' => REQUIREMENT_WARNING, + ]; + } + +} diff --git a/core/tests/Drupal/KernelTests/Core/Updater/UpdateRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Updater/UpdateRequirementsTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3129361f2a4817536a0c5f6dcdff9d29bc9bbf71 --- /dev/null +++ b/core/tests/Drupal/KernelTests/Core/Updater/UpdateRequirementsTest.php @@ -0,0 +1,45 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\KernelTests\Core\Updater; + +use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\KernelTests\KernelTestBase; + +/** + * Tests hook_update_requirements() and hook_update_requirements_alter(). + * + * @group Hooks + */ +class UpdateRequirementsTest extends KernelTestBase { + + use StringTranslationTrait; + + /** + * Tests hook_update_requirements(). + */ + public function testUpdateRequirements(): void { + require_once 'core/includes/update.inc'; + + \Drupal::service('module_installer')->install(['module_update_requirements']); + $testRequirements = [ + 'title' => $this->t('UpdateError'), + 'value' => $this->t('None'), + 'description' => $this->t('Update Error.'), + 'severity' => REQUIREMENT_ERROR, + ]; + $requirements = update_check_requirements()['test.update.error']; + $this->assertEquals($testRequirements, $requirements); + + $testAlterRequirements = [ + 'title' => $this->t('UpdateWarning'), + 'value' => $this->t('None'), + 'description' => $this->t('Update Warning.'), + 'severity' => REQUIREMENT_WARNING, + ]; + $alterRequirements = update_check_requirements()['test.update.error.alter']; + $this->assertEquals($testAlterRequirements, $alterRequirements); + } + +}