Loading core/includes/install.inc +4 −2 Original line number Diff line number Diff line Loading @@ -702,8 +702,10 @@ function drupal_check_module($module) { require_once $file; } // Check requirements. $requirements = install_check_class_requirements($extension); if (empty($requirements)) { $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? []; $requirements = array_merge($requirements, install_check_class_requirements($extension)); } if (!empty($requirements) && RequirementSeverity::maxSeverityFromRequirements($requirements) === RequirementSeverity::Error) { // Print any error messages. Loading core/lib/Drupal/Core/Hook/Attribute/LegacyRequirementsHook.php 0 → 100644 +26 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Core\Hook\Attribute; /** * Prevents procedural requirements hook from executing. * * This allows the use of the legacy hook_requirements() and * hook_requirements_alter() alongside the OOP replacements. * * Marking requirements hooks as #LegacyRequirementsHook will prevent them * from running on Drupal 11.3.0 and later. * * Note that Drupal 11.2 supports both legacy and new OOP requirements hooks * and will invoke both as this attribute is not recognized there. * * On older versions of Drupal which are not aware of the new requirement hooks, * only the legacy hook implementation is executed. * * Adding this attribute will also skip deprecation messages on Drupal 11.3 and * later. */ #[\Attribute(\Attribute::TARGET_FUNCTION)] class LegacyRequirementsHook {} core/lib/Drupal/Core/Hook/HookCollectorPass.php +30 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ use Drupal\Core\Hook\Attribute\LegacyHook; use Drupal\Core\Hook\Attribute\LegacyModuleImplementsAlter; use Drupal\Core\Hook\Attribute\ProceduralHookScanStop; use Drupal\Core\Hook\Attribute\LegacyRequirementsHook; use Drupal\Core\Hook\Attribute\RemoveHook; use Drupal\Core\Hook\Attribute\ReorderHook; use Drupal\Core\Hook\OrderOperation\OrderOperation; Loading Loading @@ -526,7 +527,8 @@ protected function collectModuleHookImplementations($dir, $module, $current_modu break; } if (!StaticReflectionParser::hasAttribute($attributes, LegacyHook::class) && (preg_match($current_module_preg, $function, $matches) || preg_match($all_modules_preg, $function, $matches)) && !StaticReflectionParser::hasAttribute($attributes, LegacyModuleImplementsAlter::class)) { $legacy_attributes = [LegacyHook::class, LegacyModuleImplementsAlter::class, LegacyRequirementsHook::class]; if (!static::hasAnyAttribute($attributes, $legacy_attributes) && (preg_match($current_module_preg, $function, $matches) || preg_match($all_modules_preg, $function, $matches))) { // Skip hooks that are not supported by the new hook system, they // do not need to be added to the BC layer. Note that is different // from static::checkForProceduralOnlyHooks(). hook_requirements Loading Loading @@ -567,6 +569,29 @@ protected function collectModuleHookImplementations($dir, $module, $current_modu } } /** * Returns whether the existing attributes match any of the expected ones. * * @param array $existingAttributes * List of attribute classes. * @param array $attributesLookingFor * List of expected attribute classes. * * @return bool * Whether an expected attribute class exists. */ public static function hasAnyAttribute(array $existingAttributes, array $attributesLookingFor): bool { foreach ($existingAttributes as $existingAttribute) { foreach ($attributesLookingFor as $attributeLookingFor) { if (is_a($existingAttribute, $attributeLookingFor, TRUE)) { return TRUE; } } } return FALSE; } /** * Filter iterator callback. Allows include files and .php files in src/Hook. */ Loading Loading @@ -609,6 +634,10 @@ protected function addProceduralImplementation(\SplFileInfo $fileinfo, string $h $this->moduleImplementsAlters[] = $function; include_once $fileinfo->getPathname(); } elseif (in_array($hook, ['requirements', 'requirements_alter'])) { $message = "$function without a #[LegacyRequirementsHook] attribute is deprecated in drupal:11.3.0 and removed in drupal:13.0.0. See https://www.drupal.org/node/3549685"; @trigger_error($message, E_USER_DEPRECATED); } $this->proceduralImplementations[$hook][] = $module; if ($fileinfo->getExtension() !== 'module') { $this->includes[$function] = $fileinfo->getPathname(); Loading core/modules/system/tests/modules/module_install_requirements/module_install_requirements.install 0 → 100644 +18 −0 Original line number Diff line number Diff line <?php /** * @file * Install hooks for the install requirements test module. */ declare(strict_types=1); use Drupal\Core\Hook\Attribute\LegacyRequirementsHook; /** * Implements hook_requirements() */ #[LegacyRequirementsHook] function module_install_requirements_requirements(): array { throw new \Exception('This is a legacy hook and must not be called'); } core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php +9 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ namespace Drupal\module_install_requirements\Install\Requirements; use Drupal\Core\Extension\InstallRequirementsInterface; use Drupal\Core\Extension\Requirement\RequirementSeverity; /** * Provides method for checking requirements during install time. Loading @@ -17,7 +18,14 @@ class ModuleInstallRequirements implements InstallRequirementsInterface { public static function getRequirements(): array { $GLOBALS['module_install_requirements'] = 'module_install_requirements'; return []; return [ 'test.runtime.install' => [ 'title' => t('InstallOk'), 'value' => t('None'), 'description' => t('Install OK.'), 'severity' => RequirementSeverity::OK, ], ]; } } Loading
core/includes/install.inc +4 −2 Original line number Diff line number Diff line Loading @@ -702,8 +702,10 @@ function drupal_check_module($module) { require_once $file; } // Check requirements. $requirements = install_check_class_requirements($extension); if (empty($requirements)) { $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? []; $requirements = array_merge($requirements, install_check_class_requirements($extension)); } if (!empty($requirements) && RequirementSeverity::maxSeverityFromRequirements($requirements) === RequirementSeverity::Error) { // Print any error messages. Loading
core/lib/Drupal/Core/Hook/Attribute/LegacyRequirementsHook.php 0 → 100644 +26 −0 Original line number Diff line number Diff line <?php declare(strict_types=1); namespace Drupal\Core\Hook\Attribute; /** * Prevents procedural requirements hook from executing. * * This allows the use of the legacy hook_requirements() and * hook_requirements_alter() alongside the OOP replacements. * * Marking requirements hooks as #LegacyRequirementsHook will prevent them * from running on Drupal 11.3.0 and later. * * Note that Drupal 11.2 supports both legacy and new OOP requirements hooks * and will invoke both as this attribute is not recognized there. * * On older versions of Drupal which are not aware of the new requirement hooks, * only the legacy hook implementation is executed. * * Adding this attribute will also skip deprecation messages on Drupal 11.3 and * later. */ #[\Attribute(\Attribute::TARGET_FUNCTION)] class LegacyRequirementsHook {}
core/lib/Drupal/Core/Hook/HookCollectorPass.php +30 −1 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ use Drupal\Core\Hook\Attribute\LegacyHook; use Drupal\Core\Hook\Attribute\LegacyModuleImplementsAlter; use Drupal\Core\Hook\Attribute\ProceduralHookScanStop; use Drupal\Core\Hook\Attribute\LegacyRequirementsHook; use Drupal\Core\Hook\Attribute\RemoveHook; use Drupal\Core\Hook\Attribute\ReorderHook; use Drupal\Core\Hook\OrderOperation\OrderOperation; Loading Loading @@ -526,7 +527,8 @@ protected function collectModuleHookImplementations($dir, $module, $current_modu break; } if (!StaticReflectionParser::hasAttribute($attributes, LegacyHook::class) && (preg_match($current_module_preg, $function, $matches) || preg_match($all_modules_preg, $function, $matches)) && !StaticReflectionParser::hasAttribute($attributes, LegacyModuleImplementsAlter::class)) { $legacy_attributes = [LegacyHook::class, LegacyModuleImplementsAlter::class, LegacyRequirementsHook::class]; if (!static::hasAnyAttribute($attributes, $legacy_attributes) && (preg_match($current_module_preg, $function, $matches) || preg_match($all_modules_preg, $function, $matches))) { // Skip hooks that are not supported by the new hook system, they // do not need to be added to the BC layer. Note that is different // from static::checkForProceduralOnlyHooks(). hook_requirements Loading Loading @@ -567,6 +569,29 @@ protected function collectModuleHookImplementations($dir, $module, $current_modu } } /** * Returns whether the existing attributes match any of the expected ones. * * @param array $existingAttributes * List of attribute classes. * @param array $attributesLookingFor * List of expected attribute classes. * * @return bool * Whether an expected attribute class exists. */ public static function hasAnyAttribute(array $existingAttributes, array $attributesLookingFor): bool { foreach ($existingAttributes as $existingAttribute) { foreach ($attributesLookingFor as $attributeLookingFor) { if (is_a($existingAttribute, $attributeLookingFor, TRUE)) { return TRUE; } } } return FALSE; } /** * Filter iterator callback. Allows include files and .php files in src/Hook. */ Loading Loading @@ -609,6 +634,10 @@ protected function addProceduralImplementation(\SplFileInfo $fileinfo, string $h $this->moduleImplementsAlters[] = $function; include_once $fileinfo->getPathname(); } elseif (in_array($hook, ['requirements', 'requirements_alter'])) { $message = "$function without a #[LegacyRequirementsHook] attribute is deprecated in drupal:11.3.0 and removed in drupal:13.0.0. See https://www.drupal.org/node/3549685"; @trigger_error($message, E_USER_DEPRECATED); } $this->proceduralImplementations[$hook][] = $module; if ($fileinfo->getExtension() !== 'module') { $this->includes[$function] = $fileinfo->getPathname(); Loading
core/modules/system/tests/modules/module_install_requirements/module_install_requirements.install 0 → 100644 +18 −0 Original line number Diff line number Diff line <?php /** * @file * Install hooks for the install requirements test module. */ declare(strict_types=1); use Drupal\Core\Hook\Attribute\LegacyRequirementsHook; /** * Implements hook_requirements() */ #[LegacyRequirementsHook] function module_install_requirements_requirements(): array { throw new \Exception('This is a legacy hook and must not be called'); }
core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php +9 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ namespace Drupal\module_install_requirements\Install\Requirements; use Drupal\Core\Extension\InstallRequirementsInterface; use Drupal\Core\Extension\Requirement\RequirementSeverity; /** * Provides method for checking requirements during install time. Loading @@ -17,7 +18,14 @@ class ModuleInstallRequirements implements InstallRequirementsInterface { public static function getRequirements(): array { $GLOBALS['module_install_requirements'] = 'module_install_requirements'; return []; return [ 'test.runtime.install' => [ 'title' => t('InstallOk'), 'value' => t('None'), 'description' => t('Install OK.'), 'severity' => RequirementSeverity::OK, ], ]; } }