From 0b8568914084d455670e505b8fa8ba1f4a70fcdd Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 6 Dec 2024 21:30:00 -0500
Subject: [PATCH 01/34] Add OOP Install requirements

---
 core/includes/install.inc                     | 14 +++++-
 .../InstallRequirementsInterface.php          | 46 +++++++++++++++++++
 .../module_install_requirements.info.yml      |  6 +++
 .../src/Install/Requirements.php              | 20 ++++++++
 .../Installer/InstallRequirementsTest.php     | 28 +++++++++++
 5 files changed, 113 insertions(+), 1 deletion(-)
 create mode 100644 core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
 create mode 100644 core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
 create mode 100644 core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
 create mode 100644 core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 368c8c694901..ad3b677abf24 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -660,12 +660,24 @@ function drupal_requirements_severity(&$requirements) {
 function drupal_check_module($module) {
   /** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
   $module_list = \Drupal::service('extension.list.module');
-  $file = DRUPAL_ROOT . '/' . $module_list->getPath($module) . "/$module.install";
+  $module_path = $module_list->getPath($module);
+  $file = DRUPAL_ROOT . '/' . $module_path . "/$module.install";
   if (is_file($file)) {
     require_once $file;
   }
   // Check requirements
   $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']);
+  \Drupal::service('class_loader')->addPsr4('Drupal\\' . $module . '\\', DRUPAL_ROOT . "/$module_path/src");
+  $class = "Drupal\\{$module}\\Install\\Requirements";
+  if (class_exists($class)) {
+    $requirementsGet = new $class();
+    if (!is_array($requirements)) {
+      $requirements = $requirementsGet->getRequirements();
+    }
+    else {
+      $requirements = array_merge($requirements, $requirementsGet->getRequirements());
+    }
+  }
   if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
     // Print any error messages
     foreach ($requirements as $requirement) {
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
new file mode 100644
index 000000000000..fc4fa967a096
--- /dev/null
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace Drupal\Core\Extension;
+
+interface InstallRequirementsInterface {
+
+  /**
+   * Check installation requirements.
+   *
+   * @todo Do we need this to be in a specific location.
+   *
+   * @todo Is this restricted to one.
+   *
+   * During the 'install' phase, modules can for example assert that
+   * library or server versions are available or sufficient.
+   * Note that the installation of a module can happen during installation of
+   * Drupal itself (by install.php) with an installation profile or later by hand.
+   * As a consequence, install-time requirements must be checked without access
+   * to the full Drupal API, because it is not available during install.php.
+   * If a requirement has a severity of REQUIREMENT_ERROR, install.php will abort
+   * or at least the module will not install.
+   * Other severity levels have no effect on the installation.
+   * Module dependencies do not belong to these installation requirements,
+   * but should be defined in the module's .info.yml file.
+   *
+   * During installation, if you need to load a class from your module,
+   * you'll need to include the class file directly.
+   *
+   * @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: This should only be used for version numbers, do not set it if
+   *     not applicable.
+   *   - description: The description of the requirement/status.
+   *   - severity: (optional) The requirement's result/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 when installing.
+   */
+  public function getRequirements(): array;
+
+}
diff --git a/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
new file mode 100644
index 000000000000..d8b1e9555567
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
@@ -0,0 +1,6 @@
+
+name: 'Test Hook Install Requirements'
+type: module
+description: 'Support module for testing install requirements.'
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
new file mode 100644
index 000000000000..a85134222111
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\module_install_requirements\Install;
+
+use Drupal\Core\Extension\InstallRequirementsInterface;
+
+class Requirements implements InstallRequirementsInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRequirements(): array {
+    $GLOBALS['install_requirements'] = 'install_requirements';
+
+    return [];
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
new file mode 100644
index 000000000000..2ecefde59196
--- /dev/null
+++ b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\KernelTests\Core\Installer;
+
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests for install requirements.
+ *
+ * @group Installer
+ */
+class InstallRequirementsTest extends KernelTestBase {
+
+  /**
+   * Tests that the installer checks merges requirements.
+   */
+  public function testRequirements(): void {
+    require_once 'core/includes/install.inc';
+
+    $this->assertFalse(isset($GLOBALS['install_requirements']));
+    \Drupal::service('module_installer')->install(['module_install_requirements']);
+    drupal_check_module('module_install_requirements');
+    $this->assertTrue(isset($GLOBALS['install_requirements']));
+  }
+
+}
-- 
GitLab


From 6f1305f786b11f7302f1796f03f535a5179410b9 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 6 Dec 2024 22:08:00 -0500
Subject: [PATCH 02/34] Profile requirements

---
 core/includes/install.inc                     | 46 +++++++++++++------
 .../src/Install/Requirements.php              |  2 +-
 .../profile_install_requirements.info.yml     |  6 +++
 .../src/Install/Requirements.php              | 20 ++++++++
 .../Installer/TestingProfileRequirements.php  | 33 +++++++++++++
 .../Installer/InstallRequirementsTest.php     |  4 +-
 6 files changed, 95 insertions(+), 16 deletions(-)
 create mode 100644 core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
 create mode 100644 core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
 create mode 100644 core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php

diff --git a/core/includes/install.inc b/core/includes/install.inc
index ad3b677abf24..0c5aaf82565a 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -616,6 +616,8 @@ function drupal_check_profile($profile) {
       if (function_exists($function)) {
         $requirements = array_merge($requirements, $function('install'));
       }
+
+      $requirements = array_merge($requirements, check_class_requirements($module, $module_path));
     }
   }
 
@@ -625,6 +627,9 @@ function drupal_check_profile($profile) {
     $requirements = array_merge($requirements, $function('install'));
   }
 
+  $profile_path = \Drupal::service('extension.list.profile')->getPath($profile);
+  $requirements = array_merge($requirements, check_class_requirements($profile, $profile_path));
+
   return $requirements;
 }
 
@@ -666,19 +671,10 @@ function drupal_check_module($module) {
     require_once $file;
   }
   // Check requirements
-  $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']);
-  \Drupal::service('class_loader')->addPsr4('Drupal\\' . $module . '\\', DRUPAL_ROOT . "/$module_path/src");
-  $class = "Drupal\\{$module}\\Install\\Requirements";
-  if (class_exists($class)) {
-    $requirementsGet = new $class();
-    if (!is_array($requirements)) {
-      $requirements = $requirementsGet->getRequirements();
-    }
-    else {
-      $requirements = array_merge($requirements, $requirementsGet->getRequirements());
-    }
-  }
-  if (is_array($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
+  $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? [];
+  $requirements = array_merge($requirements, check_class_requirements($module, $module_path));
+
+  if (is_array($requirements) && !empty($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
     // Print any error messages
     foreach ($requirements as $requirement) {
       if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
@@ -802,3 +798,27 @@ function install_profile_info($profile, $langcode = 'en') {
   }
   return $cache[$profile][$langcode];
 }
+
+/**
+ * Checks a module's requirements in RequirementsInterface.
+ *
+ * @param string $module
+ *   Machine name of module to check.
+ * @param string $module_path
+ *   The path to the module.
+ *
+ * @return array
+ *   The requirements.
+ */
+function check_class_requirements(string $module, string $module_path): array {
+  $requirements = [];
+  // @todo Do we need this.
+  \Drupal::service('class_loader')->addPsr4('Drupal\\' . $module . '\\', DRUPAL_ROOT . "/$module_path/src");
+  $class = "Drupal\\{$module}\\Install\\Requirements";
+  if (class_exists($class)) {
+    $requirementsGet = new $class();
+    $requirements = $requirementsGet->getRequirements();
+  }
+
+  return $requirements;
+}
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
index a85134222111..86702eaabddd 100644
--- a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
@@ -12,7 +12,7 @@ class Requirements implements InstallRequirementsInterface {
    * {@inheritdoc}
    */
   public function getRequirements(): array {
-    $GLOBALS['install_requirements'] = 'install_requirements';
+    $GLOBALS['module_install_requirements'] = 'module_install_requirements';
 
     return [];
   }
diff --git a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
new file mode 100644
index 000000000000..4312afbb3bc8
--- /dev/null
+++ b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
@@ -0,0 +1,6 @@
+
+name: 'Test Hook Install Requirements'
+type: profile
+description: 'Support profile for testing install requirements.'
+package: Testing
+version: VERSION
diff --git a/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php b/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
new file mode 100644
index 000000000000..e168dbb2c2f5
--- /dev/null
+++ b/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
@@ -0,0 +1,20 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\profile_install_requirements\Install;
+
+use Drupal\Core\Extension\InstallRequirementsInterface;
+
+class Requirements implements InstallRequirementsInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRequirements(): array {
+    $GLOBALS['profile_install_requirements'] = 'profile_install_requirements';
+
+    return [];
+  }
+
+}
diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
new file mode 100644
index 000000000000..1a5182113bd6
--- /dev/null
+++ b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
@@ -0,0 +1,33 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\FunctionalTests\Installer;
+
+use Drupal\Tests\BrowserTestBase;
+
+/**
+ * Tests installing the Testing profile with update notifications on.
+ *
+ * @group Installer
+ */
+class TestingProfileRequirements extends BrowserTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $profile = 'profile_install_requirements';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * Test hooks are picked up.
+   */
+  public function testHookPickup(): void {
+    $this->assertTrue(isset($GLOBALS['profile_install_requirements']));
+  }
+
+}
diff --git a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
index 2ecefde59196..1b6723b71746 100644
--- a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
@@ -19,10 +19,10 @@ class InstallRequirementsTest extends KernelTestBase {
   public function testRequirements(): void {
     require_once 'core/includes/install.inc';
 
-    $this->assertFalse(isset($GLOBALS['install_requirements']));
+    $this->assertFalse(isset($GLOBALS['module_install_requirements']));
     \Drupal::service('module_installer')->install(['module_install_requirements']);
     drupal_check_module('module_install_requirements');
-    $this->assertTrue(isset($GLOBALS['install_requirements']));
+    $this->assertTrue(isset($GLOBALS['module_install_requirements']));
   }
 
 }
-- 
GitLab


From 74af6161475d4bc2208f167369129a0e58ebacc7 Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Sat, 7 Dec 2024 04:50:22 +0000
Subject: [PATCH 03/34] Update profile_install_requirements.info.yml

---
 .../profile_install_requirements.info.yml                     | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
index 4312afbb3bc8..662ed2045155 100644
--- a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
+++ b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
@@ -1,6 +1,6 @@
 
-name: 'Test Hook Install Requirements'
+name: 'Test Install Requirements'
 type: profile
+hidden: tru
 description: 'Support profile for testing install requirements.'
-package: Testing
 version: VERSION
-- 
GitLab


From 4fdec2b8cd09fb4f5da389440844834650bef995 Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Sat, 7 Dec 2024 04:52:41 +0000
Subject: [PATCH 04/34] Update profile_install_requirements.info.yml

---
 .../profile_install_requirements.info.yml                       | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
index 662ed2045155..d75ac0f58cae 100644
--- a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
+++ b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
@@ -1,6 +1,6 @@
 
 name: 'Test Install Requirements'
 type: profile
-hidden: tru
+hidden: true
 description: 'Support profile for testing install requirements.'
 version: VERSION
-- 
GitLab


From 9118b38bd2ef9cb45f78c70e5dcb3a090c0bb015 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 13:37:15 -0500
Subject: [PATCH 05/34] Address comments

---
 core/includes/install.inc                                  | 6 +++---
 .../Drupal/Core/Extension/InstallRequirementsInterface.php | 7 ++++---
 .../module_install_requirements.info.yml                   | 2 +-
 .../Installer/TestingProfileRequirements.php               | 2 +-
 4 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 0c5aaf82565a..8a4e513f2baf 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -800,12 +800,12 @@ function install_profile_info($profile, $langcode = 'en') {
 }
 
 /**
- * Checks a module's requirements in RequirementsInterface.
+ * Checks a module or profile requirements in RequirementsInterface.
  *
  * @param string $module
- *   Machine name of module to check.
+ *   Machine name of module or profile to check.
  * @param string $module_path
- *   The path to the module.
+ *   The path to the module or profile.
  *
  * @return array
  *   The requirements.
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index fc4fa967a096..83ed8fdd9747 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -7,9 +7,10 @@ interface InstallRequirementsInterface {
   /**
    * Check installation requirements.
    *
-   * @todo Do we need this to be in a specific location.
-   *
-   * @todo Is this restricted to one.
+   * Classes implementing this must be in the Install namespace.
+   * For example src/Install/Requirements.php.
+   * Classes implementing this must be called Requirements.
+   * There must be only one class implementing this per project.
    *
    * During the 'install' phase, modules can for example assert that
    * library or server versions are available or sufficient.
diff --git a/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
index d8b1e9555567..f5bebaf779d0 100644
--- a/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
+++ b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
@@ -1,5 +1,5 @@
 
-name: 'Test Hook Install Requirements'
+name: 'Test Install Requirements Class'
 type: module
 description: 'Support module for testing install requirements.'
 package: Testing
diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
index 1a5182113bd6..ca3985c941a4 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
@@ -7,7 +7,7 @@
 use Drupal\Tests\BrowserTestBase;
 
 /**
- * Tests installing the Testing profile with update notifications on.
+ * Tests installing a profile that implements InstallRequirementsInterface.
  *
  * @group Installer
  */
-- 
GitLab


From 68b5fd0fc069b69ecd97126b4cd6863f5ca73284 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 13:44:39 -0500
Subject: [PATCH 06/34] Update profile test to check req failure

---
 .../src/Install/Requirements.php              |  8 +++--
 .../Installer/TestingProfileRequirements.php  | 34 +++++++++++++++----
 2 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php b/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
index e168dbb2c2f5..838da3ed2de0 100644
--- a/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
+++ b/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
@@ -12,9 +12,13 @@ class Requirements implements InstallRequirementsInterface {
    * {@inheritdoc}
    */
   public function getRequirements(): array {
-    $GLOBALS['profile_install_requirements'] = 'profile_install_requirements';
+    $requirements['testing_requirements'] = [
+      'title' => t('Testing requirements'),
+      'severity' => REQUIREMENT_ERROR,
+      'description' => t('Testing requirements failed requirements.'),
+    ];
 
-    return [];
+    return $requirements;
   }
 
 }
diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
index ca3985c941a4..27a93fdf85f8 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
@@ -4,14 +4,12 @@
 
 namespace Drupal\FunctionalTests\Installer;
 
-use Drupal\Tests\BrowserTestBase;
-
 /**
  * Tests installing a profile that implements InstallRequirementsInterface.
  *
  * @group Installer
  */
-class TestingProfileRequirements extends BrowserTestBase {
+class TestingProfileRequirements extends InstallerTestBase {
 
   /**
    * {@inheritdoc}
@@ -23,11 +21,35 @@ class TestingProfileRequirements extends BrowserTestBase {
    */
   protected $defaultTheme = 'stark';
 
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpSettings(): void {
+    // This form will never be reached.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpRequirementsProblem(): void {
+    // The parent method asserts that there are no requirements errors, but
+    // this test expects a requirements error in the test method below.
+    // Therefore, we override this method to suppress the parent's assertions.
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpSite(): void {
+    // This form will never be reached.
+  }
+
   /**
-   * Test hooks are picked up.
+   * Test Requirements are picked up.
    */
-  public function testHookPickup(): void {
-    $this->assertTrue(isset($GLOBALS['profile_install_requirements']));
+  public function testRequirementsFailure(): void {
+    $this->assertSession()->pageTextContains('Testing requirements failed requirements.');
   }
 
 }
-- 
GitLab


From 385e345b724337cb680366a9bac02010b55a064c Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 13:52:05 -0500
Subject: [PATCH 07/34] Add unmet dependencies test

---
 core/includes/install.inc                     |  2 --
 ...module_install_unmet_requirements.info.yml |  6 +++++
 .../src/Install/Requirements.php              | 24 +++++++++++++++++++
 .../Installer/TestingProfileRequirements.php  |  1 -
 .../Installer/InstallRequirementsTest.php     |  8 +++++++
 5 files changed, 38 insertions(+), 3 deletions(-)
 create mode 100644 core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
 create mode 100644 core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 8a4e513f2baf..995fa1990692 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -812,8 +812,6 @@ function install_profile_info($profile, $langcode = 'en') {
  */
 function check_class_requirements(string $module, string $module_path): array {
   $requirements = [];
-  // @todo Do we need this.
-  \Drupal::service('class_loader')->addPsr4('Drupal\\' . $module . '\\', DRUPAL_ROOT . "/$module_path/src");
   $class = "Drupal\\{$module}\\Install\\Requirements";
   if (class_exists($class)) {
     $requirementsGet = new $class();
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml b/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
new file mode 100644
index 000000000000..7eb0c0cb7baf
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
@@ -0,0 +1,6 @@
+
+name: 'Test Install Requirements Class'
+type: module
+description: 'Support module for testing install unmet requirements.'
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php
new file mode 100644
index 000000000000..832cd3ee3150
--- /dev/null
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\module_install_unmet_requirements\Install;
+
+use Drupal\Core\Extension\InstallRequirementsInterface;
+
+class Requirements implements InstallRequirementsInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getRequirements(): array {
+    $requirements['testing_requirements'] = [
+      'title' => t('Testing requirements'),
+      'severity' => REQUIREMENT_ERROR,
+      'description' => t('Testing requirements failed requirements.'),
+    ];
+
+    return $requirements;
+  }
+
+}
diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
index 27a93fdf85f8..236979b5cd33 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
@@ -21,7 +21,6 @@ class TestingProfileRequirements extends InstallerTestBase {
    */
   protected $defaultTheme = 'stark';
 
-
   /**
    * {@inheritdoc}
    */
diff --git a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
index 1b6723b71746..a25ab080bbdd 100644
--- a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
@@ -25,4 +25,12 @@ public function testRequirements(): void {
     $this->assertTrue(isset($GLOBALS['module_install_requirements']));
   }
 
+  /**
+   * Tests that the installer returns false if module requirements are not met.
+   */
+  public function testRequirementsFailure(): void {
+    require_once 'core/includes/install.inc';
+    $this->assertFalse(drupal_check_module('module_install_unmet_requirements'));
+  }
+
 }
-- 
GitLab


From 4a7ed4a9981d7216d93331f124d2c651491ad560 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 14:22:54 -0500
Subject: [PATCH 08/34] Use camel case

---
 core/includes/install.inc                                   | 6 +++++-
 .../Drupal/Core/Extension/InstallRequirementsInterface.php  | 5 +++--
 ...ements.php => ModuleInstallRequirementsRequirements.php} | 2 +-
 .../src/Install/Requirements.php                            | 2 +-
 ...ments.php => ProfileInstallRequirementsRequirements.php} | 2 +-
 .../Installer/TestingProfileRequirements.php                | 2 ++
 6 files changed, 13 insertions(+), 6 deletions(-)
 rename core/modules/system/tests/modules/module_install_requirements/src/Install/{Requirements.php => ModuleInstallRequirementsRequirements.php} (78%)
 rename core/profiles/tests/profile_install_requirements/src/Install/{Requirements.php => ProfileInstallRequirementsRequirements.php} (84%)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 995fa1990692..ebeb180b8c21 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -8,6 +8,7 @@
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Database\Database;
+use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\Dependency;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Installer\InstallerKernel;
@@ -812,7 +813,10 @@ function install_profile_info($profile, $langcode = 'en') {
  */
 function check_class_requirements(string $module, string $module_path): array {
   $requirements = [];
-  $class = "Drupal\\{$module}\\Install\\Requirements";
+  $camelized = ContainerBuilder::camelize($module);
+  $name = "{$camelized}Requirements";
+
+  $class = "Drupal\\{$module}\\Install\\$name";
   if (class_exists($class)) {
     $requirementsGet = new $class();
     $requirements = $requirementsGet->getRequirements();
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index 83ed8fdd9747..652320164e3e 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -8,8 +8,9 @@ interface InstallRequirementsInterface {
    * Check installation requirements.
    *
    * Classes implementing this must be in the Install namespace.
-   * For example src/Install/Requirements.php.
-   * Classes implementing this must be called Requirements.
+   * For example src/Install/ModuleNameRequirements.php.
+   * Classes implementing this must be a camel case version of the project
+   * name and end in Requirements.
    * There must be only one class implementing this per project.
    *
    * During the 'install' phase, modules can for example assert that
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
similarity index 78%
rename from core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
rename to core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
index 86702eaabddd..962f36d09e7d 100644
--- a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements.php
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
-class Requirements implements InstallRequirementsInterface {
+class ModuleInstallRequirementsRequirements implements InstallRequirementsInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php
index 832cd3ee3150..1b2a00bf61d5 100644
--- a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
-class Requirements implements InstallRequirementsInterface {
+class ModuleInstallUnmetRequirementsRequirements implements InstallRequirementsInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php b/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
similarity index 84%
rename from core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
rename to core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
index 838da3ed2de0..adaa4c1737b8 100644
--- a/core/profiles/tests/profile_install_requirements/src/Install/Requirements.php
+++ b/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
-class Requirements implements InstallRequirementsInterface {
+class ProfileInstallRequirementsRequirements implements InstallRequirementsInterface {
 
   /**
    * {@inheritdoc}
diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
index 236979b5cd33..4c4b40918d17 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
@@ -4,6 +4,8 @@
 
 namespace Drupal\FunctionalTests\Installer;
 
+use Drupal\FunctionalTests\Installer\InstallerTestBase;
+
 /**
  * Tests installing a profile that implements InstallRequirementsInterface.
  *
-- 
GitLab


From 2ad440635c086199e63b3dac6b3bdd001ad43c0f Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 14:43:02 -0500
Subject: [PATCH 09/34] fix module test

---
 ...rements.php => ModuleInstallUnmetRequirementsRequirements.php} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/{Requirements.php => ModuleInstallUnmetRequirementsRequirements.php} (100%)

diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
similarity index 100%
rename from core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements.php
rename to core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
-- 
GitLab


From 818c2b365b7162196e7ccd3f14f07630253bb4d9 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 14:47:44 -0500
Subject: [PATCH 10/34] Add class loader for profiles and modules when needed

---
 core/includes/install.inc | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index ebeb180b8c21..94a0acd5501f 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -618,7 +618,7 @@ function drupal_check_profile($profile) {
         $requirements = array_merge($requirements, $function('install'));
       }
 
-      $requirements = array_merge($requirements, check_class_requirements($module, $module_path));
+      $requirements = array_merge($requirements, check_class_requirements($module));
     }
   }
 
@@ -811,10 +811,13 @@ function install_profile_info($profile, $langcode = 'en') {
  * @return array
  *   The requirements.
  */
-function check_class_requirements(string $module, string $module_path): array {
+function check_class_requirements(string $module, string $module_path = ''): array {
   $requirements = [];
   $camelized = ContainerBuilder::camelize($module);
   $name = "{$camelized}Requirements";
+  if ($module_path) {
+    \Drupal::service('class_loader')->addPsr4('Drupal\\' . $module . '\\', \Drupal::root() . "/$module_path/src");
+  }
 
   $class = "Drupal\\{$module}\\Install\\$name";
   if (class_exists($class)) {
-- 
GitLab


From fe0ac40649c2195e503c69c5a19f28545f2cb89c Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 7 Dec 2024 14:50:58 -0500
Subject: [PATCH 11/34] unused

---
 .../FunctionalTests/Installer/TestingProfileRequirements.php    | 2 --
 1 file changed, 2 deletions(-)

diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
index 4c4b40918d17..236979b5cd33 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
@@ -4,8 +4,6 @@
 
 namespace Drupal\FunctionalTests\Installer;
 
-use Drupal\FunctionalTests\Installer\InstallerTestBase;
-
 /**
  * Tests installing a profile that implements InstallRequirementsInterface.
  *
-- 
GitLab


From a78aa62b5acca02c6573b2830fc5f510b85d1d8a Mon Sep 17 00:00:00 2001
From: Stephen Mustgrave <38930-smustgrave@users.noreply.drupalcode.org>
Date: Wed, 8 Jan 2025 19:22:13 +0000
Subject: [PATCH 12/34] Nit: remove space

---
 .../module_install_requirements.info.yml                         | 1 -
 1 file changed, 1 deletion(-)

diff --git a/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
index f5bebaf779d0..dbbeb86129af 100644
--- a/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
+++ b/core/modules/system/tests/modules/module_install_requirements/module_install_requirements.info.yml
@@ -1,4 +1,3 @@
-
 name: 'Test Install Requirements Class'
 type: module
 description: 'Support module for testing install requirements.'
-- 
GitLab


From 0b45077c9a43441bed80eb9e74acccdc8e88ad6d Mon Sep 17 00:00:00 2001
From: Stephen Mustgrave <38930-smustgrave@users.noreply.drupalcode.org>
Date: Wed, 8 Jan 2025 19:22:58 +0000
Subject: [PATCH 13/34] Nit: empty space

---
 .../module_install_unmet_requirements.info.yml                   | 1 -
 1 file changed, 1 deletion(-)

diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml b/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
index 7eb0c0cb7baf..dec6ba7e9e85 100644
--- a/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/module_install_unmet_requirements.info.yml
@@ -1,4 +1,3 @@
-
 name: 'Test Install Requirements Class'
 type: module
 description: 'Support module for testing install unmet requirements.'
-- 
GitLab


From 48127919877889875df99bcbc6e174276794c84f Mon Sep 17 00:00:00 2001
From: Stephen Mustgrave <38930-smustgrave@users.noreply.drupalcode.org>
Date: Wed, 8 Jan 2025 19:23:38 +0000
Subject: [PATCH 14/34] Nit: empty space

---
 .../profile_install_requirements.info.yml                        | 1 -
 1 file changed, 1 deletion(-)

diff --git a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
index d75ac0f58cae..f6e04e5021c7 100644
--- a/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
+++ b/core/profiles/tests/profile_install_requirements/profile_install_requirements.info.yml
@@ -1,4 +1,3 @@
-
 name: 'Test Install Requirements'
 type: profile
 hidden: true
-- 
GitLab


From 91e403b779cdd6eab1a985c3f25ddee47efa7897 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 10 Jan 2025 20:57:04 -0500
Subject: [PATCH 15/34] Do not auto load

---
 core/includes/install.inc                          | 14 +++++++-------
 .../Extension/InstallRequirementsInterface.php     |  2 +-
 .../ModuleInstallRequirementsRequirements.php      |  2 +-
 .../ModuleInstallUnmetRequirementsRequirements.php |  2 +-
 .../Core/Installer/InstallRequirementsTest.php     |  1 -
 5 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 94a0acd5501f..5c7eb2db7509 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -810,19 +810,19 @@ function install_profile_info($profile, $langcode = 'en') {
  *
  * @return array
  *   The requirements.
+ *
+ * @internal
  */
 function check_class_requirements(string $module, string $module_path = ''): array {
   $requirements = [];
   $camelized = ContainerBuilder::camelize($module);
   $name = "{$camelized}Requirements";
-  if ($module_path) {
-    \Drupal::service('class_loader')->addPsr4('Drupal\\' . $module . '\\', \Drupal::root() . "/$module_path/src");
-  }
+  $requirements_path = \Drupal::root() . "/$module_path/src/Install/$name.php";
+  if (is_file($requirements_path)) {
+    require_once $requirements_path;
 
-  $class = "Drupal\\{$module}\\Install\\$name";
-  if (class_exists($class)) {
-    $requirementsGet = new $class();
-    $requirements = $requirementsGet->getRequirements();
+    $class_name = "Drupal\\$module\\Install\\$name";
+    $requirements = $class_name::getRequirements();
   }
 
   return $requirements;
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index 652320164e3e..be7b34651640 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -43,6 +43,6 @@ interface InstallRequirementsInterface {
    *     - REQUIREMENT_ERROR: The requirement failed with an error.
    *     Defaults to REQUIREMENT_OK when installing.
    */
-  public function getRequirements(): array;
+  public static function getRequirements(): array;
 
 }
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
index 962f36d09e7d..994b086832f9 100644
--- a/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
@@ -11,7 +11,7 @@ class ModuleInstallRequirementsRequirements implements InstallRequirementsInterf
   /**
    * {@inheritdoc}
    */
-  public function getRequirements(): array {
+  public static function getRequirements(): array {
     $GLOBALS['module_install_requirements'] = 'module_install_requirements';
 
     return [];
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
index 1b2a00bf61d5..38604d070abd 100644
--- a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
@@ -11,7 +11,7 @@ class ModuleInstallUnmetRequirementsRequirements implements InstallRequirementsI
   /**
    * {@inheritdoc}
    */
-  public function getRequirements(): array {
+  public static function getRequirements(): array {
     $requirements['testing_requirements'] = [
       'title' => t('Testing requirements'),
       'severity' => REQUIREMENT_ERROR,
diff --git a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
index a25ab080bbdd..fac9503cf9f5 100644
--- a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
@@ -20,7 +20,6 @@ public function testRequirements(): void {
     require_once 'core/includes/install.inc';
 
     $this->assertFalse(isset($GLOBALS['module_install_requirements']));
-    \Drupal::service('module_installer')->install(['module_install_requirements']);
     drupal_check_module('module_install_requirements');
     $this->assertTrue(isset($GLOBALS['module_install_requirements']));
   }
-- 
GitLab


From a02a2d3a27ea2f336a9361f8555fc811d8a07e00 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 10 Jan 2025 21:02:15 -0500
Subject: [PATCH 16/34] Stan

---
 .../src/Install/ProfileInstallRequirementsRequirements.php      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php b/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
index adaa4c1737b8..0c2eba72bf3e 100644
--- a/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
+++ b/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
@@ -11,7 +11,7 @@ class ProfileInstallRequirementsRequirements implements InstallRequirementsInter
   /**
    * {@inheritdoc}
    */
-  public function getRequirements(): array {
+  public static function getRequirements(): array {
     $requirements['testing_requirements'] = [
       'title' => t('Testing requirements'),
       'severity' => REQUIREMENT_ERROR,
-- 
GitLab


From 14be47b81e0518a4e7a0c3f2294abeb956f1258b Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 11 Jan 2025 19:29:45 -0500
Subject: [PATCH 17/34] Rename and remove unecessary check

---
 core/includes/install.inc | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 5c7eb2db7509..4c473eabcc35 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -618,7 +618,7 @@ function drupal_check_profile($profile) {
         $requirements = array_merge($requirements, $function('install'));
       }
 
-      $requirements = array_merge($requirements, check_class_requirements($module));
+      $requirements = array_merge($requirements, install_check_class_requirements($module));
     }
   }
 
@@ -629,7 +629,7 @@ function drupal_check_profile($profile) {
   }
 
   $profile_path = \Drupal::service('extension.list.profile')->getPath($profile);
-  $requirements = array_merge($requirements, check_class_requirements($profile, $profile_path));
+  $requirements = array_merge($requirements, install_check_class_requirements($profile, $profile_path));
 
   return $requirements;
 }
@@ -673,9 +673,9 @@ function drupal_check_module($module) {
   }
   // Check requirements
   $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? [];
-  $requirements = array_merge($requirements, check_class_requirements($module, $module_path));
+  $requirements = array_merge($requirements, install_check_class_requirements($module, $module_path));
 
-  if (is_array($requirements) && !empty($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
+  if (!empty($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
     // Print any error messages
     foreach ($requirements as $requirement) {
       if (isset($requirement['severity']) && $requirement['severity'] == REQUIREMENT_ERROR) {
@@ -813,7 +813,7 @@ function install_profile_info($profile, $langcode = 'en') {
  *
  * @internal
  */
-function check_class_requirements(string $module, string $module_path = ''): array {
+function install_check_class_requirements(string $module, string $module_path = ''): array {
   $requirements = [];
   $camelized = ContainerBuilder::camelize($module);
   $name = "{$camelized}Requirements";
-- 
GitLab


From 5a794a8b1a8e43c79c416e34b62bef880303ec7b Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 11 Jan 2025 22:02:30 -0500
Subject: [PATCH 18/34] Module path

---
 core/includes/install.inc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 4c473eabcc35..433dea412707 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -618,7 +618,7 @@ function drupal_check_profile($profile) {
         $requirements = array_merge($requirements, $function('install'));
       }
 
-      $requirements = array_merge($requirements, install_check_class_requirements($module));
+      $requirements = array_merge($requirements, install_check_class_requirements($module, $module_path));
     }
   }
 
@@ -813,7 +813,7 @@ function install_profile_info($profile, $langcode = 'en') {
  *
  * @internal
  */
-function install_check_class_requirements(string $module, string $module_path = ''): array {
+function install_check_class_requirements(string $module, string $module_path): array {
   $requirements = [];
   $camelized = ContainerBuilder::camelize($module);
   $name = "{$camelized}Requirements";
-- 
GitLab


From 5fd12f257a553115975f4e5167a81ba7a288a5c7 Mon Sep 17 00:00:00 2001
From: nlighteneddesign <nic@nlighteneddevelopment.com>
Date: Mon, 27 Jan 2025 14:03:50 -0500
Subject: [PATCH 19/34] Rename test to match expectations

---
 ...stingProfileRequirements.php => ProfileRequirementsTest.php} | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
 rename core/tests/Drupal/FunctionalTests/Installer/{TestingProfileRequirements.php => ProfileRequirementsTest.php} (94%)

diff --git a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php b/core/tests/Drupal/FunctionalTests/Installer/ProfileRequirementsTest.php
similarity index 94%
rename from core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
rename to core/tests/Drupal/FunctionalTests/Installer/ProfileRequirementsTest.php
index 236979b5cd33..6a6e556944b7 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/TestingProfileRequirements.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/ProfileRequirementsTest.php
@@ -9,7 +9,7 @@
  *
  * @group Installer
  */
-class TestingProfileRequirements extends InstallerTestBase {
+class ProfileRequirementsTest extends InstallerTestBase {
 
   /**
    * {@inheritdoc}
-- 
GitLab


From c510c057ff829796134132118db67d6b46dfb524 Mon Sep 17 00:00:00 2001
From: andrew farquharson <2562-andrewfarq@users.noreply.drupalcode.org>
Date: Mon, 27 Jan 2025 19:15:52 +0000
Subject: [PATCH 20/34] Edit InstallRequirementsInterface.php

---
 core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index be7b34651640..2c5ff0de1516 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -10,7 +10,7 @@ interface InstallRequirementsInterface {
    * Classes implementing this must be in the Install namespace.
    * For example src/Install/ModuleNameRequirements.php.
    * Classes implementing this must be a camel case version of the project
-   * name and end in Requirements.
+   * name and such class names must end with 'Requirements'.
    * There must be only one class implementing this per project.
    *
    * During the 'install' phase, modules can for example assert that
-- 
GitLab


From 702e1227db61ac1ea6f1858e3947491cda9ba187 Mon Sep 17 00:00:00 2001
From: andrew farquharson <2562-andrewfarq@users.noreply.drupalcode.org>
Date: Mon, 27 Jan 2025 19:19:19 +0000
Subject: [PATCH 21/34] Edit InstallRequirementsInterface.php

---
 .../Drupal/Core/Extension/InstallRequirementsInterface.php    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index 2c5ff0de1516..1c7d7e3f5c36 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -9,8 +9,8 @@ interface InstallRequirementsInterface {
    *
    * Classes implementing this must be in the Install namespace.
    * For example src/Install/ModuleNameRequirements.php.
-   * Classes implementing this must be a camel case version of the project
-   * name and such class names must end with 'Requirements'.
+   * Classes implementing this must be named using a camel case version
+   * of the project name and also end with 'Requirements'.
    * There must be only one class implementing this per project.
    *
    * During the 'install' phase, modules can for example assert that
-- 
GitLab


From 9b2e0c429a657d64a8102314b0f58623846d075f Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Fri, 7 Feb 2025 02:53:06 +0000
Subject: [PATCH 22/34] Rename to extension

---
 core/includes/install.inc                        | 16 ++++++++--------
 .../Extension/InstallRequirementsInterface.php   |  4 ++--
 .../Core/Installer/InstallRequirementsTest.php   |  2 +-
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 433dea412707..418429684f91 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -801,11 +801,11 @@ function install_profile_info($profile, $langcode = 'en') {
 }
 
 /**
- * Checks a module or profile requirements in RequirementsInterface.
+ * Checks a module or profile requirements via a class that implements RequirementsInterface.
  *
- * @param string $module
- *   Machine name of module or profile to check.
- * @param string $module_path
+ * @param string $extension
+ *   Machine name of the module or profile to check.
+ * @param string $path
  *   The path to the module or profile.
  *
  * @return array
@@ -813,15 +813,15 @@ function install_profile_info($profile, $langcode = 'en') {
  *
  * @internal
  */
-function install_check_class_requirements(string $module, string $module_path): array {
+function install_check_class_requirements(string $extension, string $path): array {
   $requirements = [];
-  $camelized = ContainerBuilder::camelize($module);
+  $camelized = ContainerBuilder::camelize($extension);
   $name = "{$camelized}Requirements";
-  $requirements_path = \Drupal::root() . "/$module_path/src/Install/$name.php";
+  $requirements_path = \Drupal::root() . "/$path/src/Install/$name.php";
   if (is_file($requirements_path)) {
     require_once $requirements_path;
 
-    $class_name = "Drupal\\$module\\Install\\$name";
+    $class_name = "Drupal\\$extension\\Install\\$name";
     $requirements = $class_name::getRequirements();
   }
 
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index 1c7d7e3f5c36..ac6274d5bb4a 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -10,8 +10,8 @@ interface InstallRequirementsInterface {
    * Classes implementing this must be in the Install namespace.
    * For example src/Install/ModuleNameRequirements.php.
    * Classes implementing this must be named using a camel case version
-   * of the project name and also end with 'Requirements'.
-   * There must be only one class implementing this per project.
+   * of the extension name and also end with 'Requirements'.
+   * There must be only one class implementing this per extension.
    *
    * During the 'install' phase, modules can for example assert that
    * library or server versions are available or sufficient.
diff --git a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
index fac9503cf9f5..8c05cfd7dc66 100644
--- a/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Installer/InstallRequirementsTest.php
@@ -14,7 +14,7 @@
 class InstallRequirementsTest extends KernelTestBase {
 
   /**
-   * Tests that the installer checks merges requirements.
+   * Confirm installer checks requirements in designated classes.
    */
   public function testRequirements(): void {
     require_once 'core/includes/install.inc';
-- 
GitLab


From ccec0a8535cf6db36c60b942e98ba8fb96900769 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 14 Feb 2025 23:43:36 -0500
Subject: [PATCH 23/34] Iterate for install requirements

---
 core/includes/install.inc                     | 25 ++++++++++++-------
 .../InstallRequirementsInterface.php          |  3 ---
 ...ents.php => ModuleInstallRequirements.php} |  2 +-
 3 files changed, 17 insertions(+), 13 deletions(-)
 rename core/modules/system/tests/modules/module_install_requirements/src/Install/{ModuleInstallRequirementsRequirements.php => ModuleInstallRequirements.php} (79%)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 418429684f91..b1662d766fad 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -8,7 +8,6 @@
 use Drupal\Component\Utility\Unicode;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Database\Database;
-use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\Extension\Dependency;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Installer\InstallerKernel;
@@ -814,16 +813,24 @@ function install_profile_info($profile, $langcode = 'en') {
  * @internal
  */
 function install_check_class_requirements(string $extension, string $path): array {
+  $dir = \Drupal::root() . "/$path/src/Install";
   $requirements = [];
-  $camelized = ContainerBuilder::camelize($extension);
-  $name = "{$camelized}Requirements";
-  $requirements_path = \Drupal::root() . "/$path/src/Install/$name.php";
-  if (is_file($requirements_path)) {
-    require_once $requirements_path;
+  if (is_dir($dir)) {
+    $fileSystemIterator = new FilesystemIterator($dir);
+    foreach ($fileSystemIterator as $fileInfo) {
+      if ($fileInfo->isFile()) {
+        $filename = $fileInfo->getFilename();
+        $requirements_path = $dir . '/' . $filename;
+        require_once $requirements_path;
+
+        $name = pathinfo($filename, PATHINFO_FILENAME);
+        $class_name = "Drupal\\$extension\\Install\\$name";
+        if (class_exists($class_name) && is_subclass_of($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
+          $requirements = $class_name::getRequirements();
+        }
+      }
+    }
 
-    $class_name = "Drupal\\$extension\\Install\\$name";
-    $requirements = $class_name::getRequirements();
   }
-
   return $requirements;
 }
diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index ac6274d5bb4a..1011090ca865 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -9,9 +9,6 @@ interface InstallRequirementsInterface {
    *
    * Classes implementing this must be in the Install namespace.
    * For example src/Install/ModuleNameRequirements.php.
-   * Classes implementing this must be named using a camel case version
-   * of the extension name and also end with 'Requirements'.
-   * There must be only one class implementing this per extension.
    *
    * During the 'install' phase, modules can for example assert that
    * library or server versions are available or sufficient.
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirements.php
similarity index 79%
rename from core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
rename to core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirements.php
index 994b086832f9..b7e57c3fddef 100644
--- a/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirementsRequirements.php
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirements.php
@@ -6,7 +6,7 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
-class ModuleInstallRequirementsRequirements implements InstallRequirementsInterface {
+class ModuleInstallRequirements implements InstallRequirementsInterface {
 
   /**
    * {@inheritdoc}
-- 
GitLab


From 67cb8fb33463b294c1bbc4ee735cc73fbc6c887e Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 14 Feb 2025 23:55:26 -0500
Subject: [PATCH 24/34] Instanceof

---
 core/includes/install.inc | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index b1662d766fad..82cdbc271071 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -10,6 +10,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Extension\Dependency;
 use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Extension\InstallRequirementsInterface;
 use Drupal\Core\Installer\InstallerKernel;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -825,7 +826,7 @@ function install_check_class_requirements(string $extension, string $path): arra
 
         $name = pathinfo($filename, PATHINFO_FILENAME);
         $class_name = "Drupal\\$extension\\Install\\$name";
-        if (class_exists($class_name) && is_subclass_of($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
+        if (class_exists($class_name) && ($class_name instanceOf InstallRequirementsInterface)) {
           $requirements = $class_name::getRequirements();
         }
       }
-- 
GitLab


From fec3599e8d861171b90a2ddee01ca7c7e3e9fbe0 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Fri, 14 Feb 2025 23:57:13 -0500
Subject: [PATCH 25/34] class_implements

---
 core/includes/install.inc | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 82cdbc271071..64278a6f436a 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -10,7 +10,6 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Extension\Dependency;
 use Drupal\Core\Extension\ExtensionDiscovery;
-use Drupal\Core\Extension\InstallRequirementsInterface;
 use Drupal\Core\Installer\InstallerKernel;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -826,7 +825,7 @@ function install_check_class_requirements(string $extension, string $path): arra
 
         $name = pathinfo($filename, PATHINFO_FILENAME);
         $class_name = "Drupal\\$extension\\Install\\$name";
-        if (class_exists($class_name) && ($class_name instanceOf InstallRequirementsInterface)) {
+        if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
           $requirements = $class_name::getRequirements();
         }
       }
-- 
GitLab


From 5129427c5956d74e252d99c4647bc22fb97b3d8c Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Sat, 15 Feb 2025 13:52:26 +0000
Subject: [PATCH 26/34] Better variable names

---
 core/includes/install.inc | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 64278a6f436a..4f553d28b2fa 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -823,8 +823,8 @@ function install_check_class_requirements(string $extension, string $path): arra
         $requirements_path = $dir . '/' . $filename;
         require_once $requirements_path;
 
-        $name = pathinfo($filename, PATHINFO_FILENAME);
-        $class_name = "Drupal\\$extension\\Install\\$name";
+        $namespace = "Drupal\\$extension\\Install";
+        $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
         if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
           $requirements = $class_name::getRequirements();
         }
-- 
GitLab


From 5b363a3e8abca8ae27cbd649c6af0450f3d0eac6 Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Sat, 15 Feb 2025 16:34:09 +0000
Subject: [PATCH 27/34] Check for php

---
 core/includes/install.inc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 4f553d28b2fa..ce19f636a52e 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -818,7 +818,7 @@ function install_check_class_requirements(string $extension, string $path): arra
   if (is_dir($dir)) {
     $fileSystemIterator = new FilesystemIterator($dir);
     foreach ($fileSystemIterator as $fileInfo) {
-      if ($fileInfo->isFile()) {
+      if ($fileInfo->isFile() && $fileInfo->getExtension() === 'php') {
         $filename = $fileInfo->getFilename();
         $requirements_path = $dir . '/' . $filename;
         require_once $requirements_path;
-- 
GitLab


From f281ee739e9a45f1954c99f49d6a41eee7da2860 Mon Sep 17 00:00:00 2001
From: nicxvan <nic@nlightened.net>
Date: Sat, 15 Feb 2025 22:51:39 -0500
Subject: [PATCH 28/34] Add check for install requirements and move to
 Install/Requirements

---
 core/includes/install.inc                          | 14 ++++++++------
 .../ModuleInstallRequirements.php                  |  2 +-
 .../ModuleInstallUnmetRequirementsRequirements.php |  2 +-
 .../ProfileInstallRequirementsRequirements.php     |  2 +-
 4 files changed, 11 insertions(+), 9 deletions(-)
 rename core/modules/system/tests/modules/module_install_requirements/src/Install/{ => Requirements}/ModuleInstallRequirements.php (83%)
 rename core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/{ => Requirements}/ModuleInstallUnmetRequirementsRequirements.php (87%)
 rename core/profiles/tests/profile_install_requirements/src/Install/{ => Requirements}/ProfileInstallRequirementsRequirements.php (88%)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index ce19f636a52e..f9e54ffd941b 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -813,7 +813,7 @@ function install_profile_info($profile, $langcode = 'en') {
  * @internal
  */
 function install_check_class_requirements(string $extension, string $path): array {
-  $dir = \Drupal::root() . "/$path/src/Install";
+  $dir = \Drupal::root() . "/$path/src/Install/Requirements";
   $requirements = [];
   if (is_dir($dir)) {
     $fileSystemIterator = new FilesystemIterator($dir);
@@ -821,12 +821,14 @@ function install_check_class_requirements(string $extension, string $path): arra
       if ($fileInfo->isFile() && $fileInfo->getExtension() === 'php') {
         $filename = $fileInfo->getFilename();
         $requirements_path = $dir . '/' . $filename;
-        require_once $requirements_path;
+        if (str_contains(file_get_contents($requirements_path), 'Drupal\Core\Extension\InstallRequirementsInterface')) {
+          require_once $requirements_path;
 
-        $namespace = "Drupal\\$extension\\Install";
-        $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
-        if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
-          $requirements = $class_name::getRequirements();
+          $namespace = "Drupal\\$extension\\Install\\Requirements";
+          $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
+          if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
+            $requirements = $class_name::getRequirements();
+          }
         }
       }
     }
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
similarity index 83%
rename from core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirements.php
rename to core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
index b7e57c3fddef..8ec213c19982 100644
--- a/core/modules/system/tests/modules/module_install_requirements/src/Install/ModuleInstallRequirements.php
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace Drupal\module_install_requirements\Install;
+namespace Drupal\module_install_requirements\Install\Requirements;
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
similarity index 87%
rename from core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
rename to core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
index 38604d070abd..3d51e1fefac5 100644
--- a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/ModuleInstallUnmetRequirementsRequirements.php
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace Drupal\module_install_unmet_requirements\Install;
+namespace Drupal\module_install_unmet_requirements\Install\Requirements;
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
diff --git a/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php b/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
similarity index 88%
rename from core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
rename to core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
index 0c2eba72bf3e..7d108181c328 100644
--- a/core/profiles/tests/profile_install_requirements/src/Install/ProfileInstallRequirementsRequirements.php
+++ b/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
@@ -2,7 +2,7 @@
 
 declare(strict_types=1);
 
-namespace Drupal\profile_install_requirements\Install;
+namespace Drupal\profile_install_requirements\Install\Requirements;
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
-- 
GitLab


From d353dfc187b31705bbf23f5052b344f3f2867af1 Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Sun, 16 Feb 2025 21:48:41 +0000
Subject: [PATCH 29/34] Update comments

---
 .../Drupal/Core/Extension/InstallRequirementsInterface.php    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index 1011090ca865..c8e3d23fafa8 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -7,8 +7,8 @@ interface InstallRequirementsInterface {
   /**
    * Check installation requirements.
    *
-   * Classes implementing this must be in the Install namespace.
-   * For example src/Install/ModuleNameRequirements.php.
+   * Classes implementing this must be in the Install/Requirements namespace.
+   * For example src/Install/Requirements/ModuleNameRequirements.php.
    *
    * During the 'install' phase, modules can for example assert that
    * library or server versions are available or sufficient.
-- 
GitLab


From 77791b5ffd5e7835a9ddd995e4fdbec98da19fc4 Mon Sep 17 00:00:00 2001
From: nicxvan <29861-nicxvan@users.noreply.drupalcode.org>
Date: Mon, 17 Feb 2025 18:10:25 +0000
Subject: [PATCH 30/34] Make this more extensible

---
 core/includes/install.inc | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index f9e54ffd941b..1a3213df5710 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -821,14 +821,12 @@ function install_check_class_requirements(string $extension, string $path): arra
       if ($fileInfo->isFile() && $fileInfo->getExtension() === 'php') {
         $filename = $fileInfo->getFilename();
         $requirements_path = $dir . '/' . $filename;
-        if (str_contains(file_get_contents($requirements_path), 'Drupal\Core\Extension\InstallRequirementsInterface')) {
-          require_once $requirements_path;
+        require_once $requirements_path;
 
-          $namespace = "Drupal\\$extension\\Install\\Requirements";
-          $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
-          if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
-            $requirements = $class_name::getRequirements();
-          }
+        $namespace = "Drupal\\$extension\\Install\\Requirements";
+        $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
+        if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
+          $requirements = $class_name::getRequirements();
         }
       }
     }
-- 
GitLab


From 7f5c3b50369231bc2e7fb67841f1b1c50b0d101e Mon Sep 17 00:00:00 2001
From: nlighteneddesign <nic@nlighteneddevelopment.com>
Date: Fri, 21 Feb 2025 16:49:50 -0500
Subject: [PATCH 31/34] Address feedback

---
 core/includes/install.inc | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 1a3213df5710..5eae97789969 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -10,6 +10,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Extension\Dependency;
 use Drupal\Core\Extension\ExtensionDiscovery;
+use Drupal\Core\Extension\InstallRequirementsInterface;
 use Drupal\Core\Installer\InstallerKernel;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 
@@ -802,9 +803,9 @@ function install_profile_info($profile, $langcode = 'en') {
 /**
  * Checks a module or profile requirements via a class that implements RequirementsInterface.
  *
- * @param string $extension
+ * @param string $extension_name
  *   Machine name of the module or profile to check.
- * @param string $path
+ * @param string $extension_path
  *   The path to the module or profile.
  *
  * @return array
@@ -812,8 +813,8 @@ function install_profile_info($profile, $langcode = 'en') {
  *
  * @internal
  */
-function install_check_class_requirements(string $extension, string $path): array {
-  $dir = \Drupal::root() . "/$path/src/Install/Requirements";
+function install_check_class_requirements(string $extension_name, string $extension_path): array {
+  $dir = \Drupal::root() . "/$extension_path/src/Install/Requirements";
   $requirements = [];
   if (is_dir($dir)) {
     $fileSystemIterator = new FilesystemIterator($dir);
@@ -823,9 +824,9 @@ function install_check_class_requirements(string $extension, string $path): arra
         $requirements_path = $dir . '/' . $filename;
         require_once $requirements_path;
 
-        $namespace = "Drupal\\$extension\\Install\\Requirements";
+        $namespace = "Drupal\\$extension_name\\Install\\Requirements";
         $class_name = $namespace . '\\' . $fileInfo->getBasename('.php');
-        if (class_exists($class_name) && class_implements($class_name, 'Drupal\Core\Extension\InstallRequirementsInterface')) {
+        if (class_exists($class_name) && class_implements($class_name, InstallRequirementsInterface::class)) {
           $requirements = $class_name::getRequirements();
         }
       }
-- 
GitLab


From 4eec6ce327f677400047d0432a28aad7c286a26b Mon Sep 17 00:00:00 2001
From: nlighteneddesign <nic@nlighteneddevelopment.com>
Date: Thu, 27 Feb 2025 09:01:10 -0500
Subject: [PATCH 32/34] Satisfy NR Bot

---
 .../lib/Drupal/Core/Extension/InstallRequirementsInterface.php | 3 +++
 .../src/Install/Requirements/ModuleInstallRequirements.php     | 3 +++
 .../ModuleInstallUnmetRequirementsRequirements.php             | 3 +++
 .../Requirements/ProfileInstallRequirementsRequirements.php    | 3 +++
 4 files changed, 12 insertions(+)

diff --git a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
index c8e3d23fafa8..ca1ad6afd673 100644
--- a/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
+++ b/core/lib/Drupal/Core/Extension/InstallRequirementsInterface.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\Core\Extension;
 
+/**
+ * Provides method for checking requirements during install time.
+ */
 interface InstallRequirementsInterface {
 
   /**
diff --git a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
index 8ec213c19982..32bc2fef1e02 100644
--- a/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
+++ b/core/modules/system/tests/modules/module_install_requirements/src/Install/Requirements/ModuleInstallRequirements.php
@@ -6,6 +6,9 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
+/**
+ * Provides method for checking requirements during install time.
+ */
 class ModuleInstallRequirements implements InstallRequirementsInterface {
 
   /**
diff --git a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
index 3d51e1fefac5..4d7367ff4141 100644
--- a/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
+++ b/core/modules/system/tests/modules/module_install_unmet_requirements/src/Install/Requirements/ModuleInstallUnmetRequirementsRequirements.php
@@ -6,6 +6,9 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
+/**
+ * Provides method for checking requirements during install time.
+ */
 class ModuleInstallUnmetRequirementsRequirements implements InstallRequirementsInterface {
 
   /**
diff --git a/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php b/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
index 7d108181c328..9a010b930f7c 100644
--- a/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
+++ b/core/profiles/tests/profile_install_requirements/src/Install/Requirements/ProfileInstallRequirementsRequirements.php
@@ -6,6 +6,9 @@
 
 use Drupal\Core\Extension\InstallRequirementsInterface;
 
+/**
+ * Provides method for checking requirements during install time.
+ */
 class ProfileInstallRequirementsRequirements implements InstallRequirementsInterface {
 
   /**
-- 
GitLab


From 6eb549c48bcced09fa1434092ff42be97b46e218 Mon Sep 17 00:00:00 2001
From: nlighteneddesign <nic@nlighteneddevelopment.com>
Date: Thu, 27 Feb 2025 11:45:49 -0500
Subject: [PATCH 33/34] Use Extension

---
 core/includes/install.inc | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 5eae97789969..40280a457ca4 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -9,6 +9,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Database\Database;
 use Drupal\Core\Extension\Dependency;
+use Drupal\Core\Extension\Extension;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Extension\InstallRequirementsInterface;
 use Drupal\Core\Installer\InstallerKernel;
@@ -618,7 +619,7 @@ function drupal_check_profile($profile) {
         $requirements = array_merge($requirements, $function('install'));
       }
 
-      $requirements = array_merge($requirements, install_check_class_requirements($module, $module_path));
+      $requirements = array_merge($requirements, install_check_class_requirements($module_list[$module]));
     }
   }
 
@@ -628,8 +629,8 @@ function drupal_check_profile($profile) {
     $requirements = array_merge($requirements, $function('install'));
   }
 
-  $profile_path = \Drupal::service('extension.list.profile')->getPath($profile);
-  $requirements = array_merge($requirements, install_check_class_requirements($profile, $profile_path));
+  $extension = \Drupal::service('extension.list.profile')->get($profile);
+  $requirements = array_merge($requirements, install_check_class_requirements($extension));
 
   return $requirements;
 }
@@ -666,6 +667,7 @@ function drupal_requirements_severity(&$requirements) {
 function drupal_check_module($module) {
   /** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
   $module_list = \Drupal::service('extension.list.module');
+  $extension = $module_list->get($module);
   $module_path = $module_list->getPath($module);
   $file = DRUPAL_ROOT . '/' . $module_path . "/$module.install";
   if (is_file($file)) {
@@ -673,7 +675,7 @@ function drupal_check_module($module) {
   }
   // Check requirements
   $requirements = \Drupal::moduleHandler()->invoke($module, 'requirements', ['install']) ?? [];
-  $requirements = array_merge($requirements, install_check_class_requirements($module, $module_path));
+  $requirements = array_merge($requirements, install_check_class_requirements($extension));
 
   if (!empty($requirements) && drupal_requirements_severity($requirements) == REQUIREMENT_ERROR) {
     // Print any error messages
@@ -803,17 +805,17 @@ function install_profile_info($profile, $langcode = 'en') {
 /**
  * Checks a module or profile requirements via a class that implements RequirementsInterface.
  *
- * @param string $extension_name
- *   Machine name of the module or profile to check.
- * @param string $extension_path
- *   The path to the module or profile.
+ * @param \Drupal\Core\Extension $extension
+ *   The extension to check install requirements for.
  *
  * @return array
  *   The requirements.
  *
  * @internal
  */
-function install_check_class_requirements(string $extension_name, string $extension_path): array {
+function install_check_class_requirements(Extension $extension): array {
+  $extension_path = $extension->getPath();
+  $extension_name = $extension->getName();
   $dir = \Drupal::root() . "/$extension_path/src/Install/Requirements";
   $requirements = [];
   if (is_dir($dir)) {
-- 
GitLab


From 70a14037c7b57b4eb32aa45faf68c0230b2998dd Mon Sep 17 00:00:00 2001
From: nlighteneddesign <nic@nlighteneddevelopment.com>
Date: Thu, 27 Feb 2025 15:56:13 -0500
Subject: [PATCH 34/34] Comment

---
 core/includes/install.inc | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/core/includes/install.inc b/core/includes/install.inc
index 40280a457ca4..2d1eb859af20 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -668,8 +668,7 @@ function drupal_check_module($module) {
   /** @var \Drupal\Core\Extension\ModuleExtensionList $module_list */
   $module_list = \Drupal::service('extension.list.module');
   $extension = $module_list->get($module);
-  $module_path = $module_list->getPath($module);
-  $file = DRUPAL_ROOT . '/' . $module_path . "/$module.install";
+  $file = \Drupal::root() . '/' . $extension->getPath() . "/$module.install";
   if (is_file($file)) {
     require_once $file;
   }
@@ -803,7 +802,9 @@ function install_profile_info($profile, $langcode = 'en') {
 }
 
 /**
- * Checks a module or profile requirements via a class that implements RequirementsInterface.
+ * Checks a module or profile requirements.
+ *
+ * See \Drupal\Core\Extension\InstallRequirementsInterface for more information.
  *
  * @param \Drupal\Core\Extension $extension
  *   The extension to check install requirements for.
-- 
GitLab