(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)
commitc24dd7db7e1e91120fd7daeb7e151f856d6b78c3
tree1a604cb31a8b82c43c42d2c6650a3c1a53faf6f7
parent89bb1a201ae034d82f1bb0950ee38ccdc099f22f
(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