(dev/core#3660) Ensure that rebuildMenuAndCaches has current mixins+classloaders
authorTim Otten <totten@civicrm.org>
Fri, 17 Jun 2022 00:00:48 +0000 (17:00 -0700)
committerTim Otten <totten@civicrm.org>
Fri, 17 Jun 2022 00:00:48 +0000 (17:00 -0700)
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

index 1255fd328595e7cd0b54d2f4f8ef30942212c8d5..c2d8d5ac716224e5a6178751307922f9fdef9301 100644 (file)
@@ -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'));