From c24dd7db7e1e91120fd7daeb7e151f856d6b78c3 Mon Sep 17 00:00:00 2001
From: Tim Otten <totten@civicrm.org>
Date: Thu, 16 Jun 2022 17:00:48 -0700
Subject: [PATCH] (dev/core#3660) Ensure that rebuildMenuAndCaches has current
 mixins+classloaders

Overview
--------

This fixes an issue in transitioning from `hook_managed` to `mixin/mgd-php@1`, wherein
managed-entities are briefly deleted (but later recreated).

Steps to Reproduce
------------------

1. (Web) Install an extension with a revision that uses `hook_managed`
2. (CLI) Switch the extension to a revision that uses `mixin/mgd-php@1`
3. (CLI) View contents of `civicrm_managed`
4. (Web) Run `civicrm/menu/rebuild`
5. (CLI) View contents of `civicrm_managed`
6. (Web) Run `civicrm/menu/rebuild`
7. (CLI) View contents of `civicrm_managed`

Before
------

While processing step 4 (`civicrm/menu/rebuild`), it fails to run the hooks for `mgd-php`.

Consequently, the list of managed-entities is lost and will disappear at step 5.

After
-----

While processing step 4 (`civicrm/menu/rebuild`), it activates the hooks for `mgd-php`.

Technical Details
------------------

When processing `civicrm/menu/rebuild`, there are a couple big substeps:

* `Civi\Core\Container::boot()` - During this process, it loads extensions. As usual,
  this reads cached metadata, sets up classloaders, sets up mixins/hooks, etc.
* `CRM_Core_Invoke::rebuildMenuAndCaches()` - During this process, it clears
  out caches and rebuilds several things (menus, managed-entities, etc).

The problem is this:

* The cache used during `boot()` has stale metadata (specifically,
  `civicrm_cache` has old values of `mixinScan` and `mixinBoot`).
  So it doesn't setup any new mixins/hooks.
* Then `rebuildMenuAndCaches()` depends on the mixins/hooks that are already setup.
  While the function does clear persistent caches, it assumes that the
  PHP runtime environment is up-to-spec. But it's not -- becuase our hooks
  were based on the caches.

The patch uses the same `refresh()` mechanism as the extension-administration subsystem (which
has to reset the classloaders+mixins after enabling or disabling an extension).
---
 CRM/Core/Invoke.php | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/CRM/Core/Invoke.php b/CRM/Core/Invoke.php
index 1255fd32859..c2d8d5ac716 100644
--- a/CRM/Core/Invoke.php
+++ b/CRM/Core/Invoke.php
@@ -379,6 +379,10 @@ class CRM_Core_Invoke {
     $config = CRM_Core_Config::singleton();
     $config->clearModuleList();
 
+    // dev/core#3660 - Activate any new classloaders/mixins/etc before re-hydrating any data-structures.
+    CRM_Extension_System::singleton()->getClassLoader()->refresh();
+    CRM_Extension_System::singleton()->getMixinLoader()->run(TRUE);
+
     // also cleanup all caches
     $config->cleanupCaches($sessionReset || CRM_Utils_Request::retrieve('sessionReset', 'Boolean', CRM_Core_DAO::$_nullObject, FALSE, 0, 'GET'));
 
-- 
GitLab