From 862b581d3ad1bf9e21520800fc24c04b91eb4ffd Mon Sep 17 00:00:00 2001
From: solideogloria <39064-solideogloria@users.noreply.drupalcode.org>
Date: Fri, 8 Mar 2024 09:11:09 -0600
Subject: [PATCH] Add changes from patch 27.

---
 .../Drupal/Core/Extension/ModuleHandler.php   | 17 +++++++++++++
 .../Core/Extension/ModuleHandlerTest.php      | 24 ++++++++++++++++++-
 2 files changed, 40 insertions(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index 7b72f3260497..88b62147cdac 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -636,6 +636,12 @@ protected function getImplementationInfo($hook) {
   protected function buildImplementationInfo($hook) {
     $implementations = [];
     $hook_info = $this->getHookInfo();
+
+    // In case it's an early stage and the hook info was loaded from cache, the
+    // module files are not yet loaded at this point and discovery below
+    // produces an empty list.
+    $this->loadAll();
+
     foreach ($this->moduleList as $module => $extension) {
       $include_file = isset($hook_info[$hook]['group']) && $this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']);
       // Since $this->implementsHook() may needlessly try to load the include
@@ -685,6 +691,17 @@ protected function buildImplementationInfo($hook) {
    *     from the cache.
    */
   protected function verifyImplementations(&$implementations, $hook) {
+    // Under certain circumstances the module files are not yet loaded. This
+    // happens for example when invoking a hook inside the constructor of a
+    // http_middleware service; these services are constructed very early as
+    // a dependency of http_kernel service. A more concrete example is a
+    // middleware service using the entity_type.manager. Most of the times
+    // the entity type information is retrieved from cache (stored in the
+    // discovery cache bin). When this cache however is missing, hooks
+    // like hook_entity_type_build() and hook_entity_type_alter() need to be
+    // invoked at this early stage.
+    $this->loadAll();
+
     $all_valid = TRUE;
     foreach ($implementations as $module => $group) {
       // If this hook implementation is stored in a lazy-loaded file, include
diff --git a/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php b/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php
index 6485ecb1f97b..a13296c5320c 100644
--- a/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php
+++ b/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php
@@ -394,6 +394,7 @@ function (callable $hook, string $module) use (&$implementors) {
    * Tests getImplementations.
    *
    * @covers ::invokeAllWith
+   * @covers ::verifyImplementations
    */
   public function testCachedGetImplementationsMissingMethod(): void {
     $this->cacheBackend->expects($this->exactly(1))
@@ -420,7 +421,6 @@ public function testCachedGetImplementationsMissingMethod(): void {
       ])
       ->onlyMethods(['buildImplementationInfo'])
       ->getMock();
-    $module_handler->load('module_handler_test');
 
     $module_handler->expects($this->never())->method('buildImplementationInfo');
     $implementors = [];
@@ -536,4 +536,26 @@ public function testGetModuleDirectories(): void {
     $this->assertEquals(['node' => $this->root . '/core/modules/node'], $module_handler->getModuleDirectories());
   }
 
+  /**
+   * Tests that modules are included in case of a partial cache miss.
+   *
+   * @covers ::hasImplementations
+   * @covers ::getImplementationInfo
+   * @covers ::buildImplementationInfo
+   */
+  public function testMissingHookImplementationCache() {
+    // Simulate missing cache entry for hook implementations, but existing one
+    // for hook info.
+    $this->cacheBackend
+      ->expects($this->exactly(2))
+      ->method('get')
+      ->willReturnMap([
+        ['hook_info', FALSE, (object) ['data' => []]],
+        ['module_implements', FALSE, FALSE],
+      ]);
+
+    $module_handler = $this->getModuleHandler();
+    $this->assertTrue($module_handler->hasImplementations('hook', 'module_handler_test'));
+  }
+
 }
-- 
GitLab